UNPKG

@animech-public/playcanvas

Version:
149 lines (146 loc) 5.95 kB
import { SEMANTIC_POSITION, SEMANTIC_NORMAL, SEMANTIC_TANGENT, SEMANTIC_TEXCOORD0, SEMANTIC_TEXCOORD1, SEMANTIC_TEXCOORD2, SEMANTIC_TEXCOORD3, SEMANTIC_TEXCOORD4, SEMANTIC_TEXCOORD5, SEMANTIC_TEXCOORD6, SEMANTIC_TEXCOORD7, SEMANTIC_COLOR, SEMANTIC_BLENDINDICES, SEMANTIC_BLENDWEIGHT } from './constants.js'; import gles2PS from './shader-chunks/frag/gles2.js'; import gles2VS from './shader-chunks/vert/gles2.js'; import gles3PS from './shader-chunks/frag/gles3.js'; import gles3VS from './shader-chunks/vert/gles3.js'; import webgpuPS from './shader-chunks/frag/webgpu.js'; import webgpuVS from './shader-chunks/vert/webgpu.js'; import sharedFS from './shader-chunks/frag/shared.js'; const _attrib2Semantic = { vertex_position: SEMANTIC_POSITION, vertex_normal: SEMANTIC_NORMAL, vertex_tangent: SEMANTIC_TANGENT, vertex_texCoord0: SEMANTIC_TEXCOORD0, vertex_texCoord1: SEMANTIC_TEXCOORD1, vertex_texCoord2: SEMANTIC_TEXCOORD2, vertex_texCoord3: SEMANTIC_TEXCOORD3, vertex_texCoord4: SEMANTIC_TEXCOORD4, vertex_texCoord5: SEMANTIC_TEXCOORD5, vertex_texCoord6: SEMANTIC_TEXCOORD6, vertex_texCoord7: SEMANTIC_TEXCOORD7, vertex_color: SEMANTIC_COLOR, vertex_boneIndices: SEMANTIC_BLENDINDICES, vertex_boneWeights: SEMANTIC_BLENDWEIGHT }; class ShaderUtils { static createDefinition(device, options) { var _options$name, _options$attributes; const getDefines = (gpu, gl2, gl1, isVertex, options) => { const deviceIntro = device.isWebGPU ? gpu : device.isWebGL2 ? gl2 : ShaderUtils.gl1Extensions(device, options) + gl1; let attachmentsDefine = ''; if (!isVertex) { var _options$fragmentOutp; let fragmentOutputTypes = (_options$fragmentOutp = options.fragmentOutputTypes) != null ? _options$fragmentOutp : 'vec4'; if (!Array.isArray(fragmentOutputTypes)) { fragmentOutputTypes = [fragmentOutputTypes]; } for (let i = 0; i < device.maxColorAttachments; i++) { var _fragmentOutputTypes$; attachmentsDefine += `#define COLOR_ATTACHMENT_${i}\n`; const outType = (_fragmentOutputTypes$ = fragmentOutputTypes[i]) != null ? _fragmentOutputTypes$ : 'vec4'; attachmentsDefine += `#define outType_${i} ${outType}\n`; } } return attachmentsDefine + deviceIntro; }; const name = (_options$name = options.name) != null ? _options$name : 'Untitled'; const vertCode = ShaderUtils.versionCode(device) + getDefines(webgpuVS, gles3VS, gles2VS, true, options) + ShaderUtils.getDefinesCode(options.vertexDefines) + sharedFS + ShaderUtils.getShaderNameCode(name) + options.vertexCode; const fragCode = `${(options.fragmentPreamble || '') + ShaderUtils.versionCode(device) + getDefines(webgpuPS, gles3PS, gles2PS, false, options) + ShaderUtils.getDefinesCode(options.fragmentDefines) + ShaderUtils.precisionCode(device)}\n${sharedFS}${ShaderUtils.getShaderNameCode(name)}${options.fragmentCode || ShaderUtils.dummyFragmentCode()}`; const attribs = (_options$attributes = options.attributes) != null ? _options$attributes : ShaderUtils.collectAttributes(options.vertexCode); return { name: name, attributes: attribs, vshader: vertCode, vincludes: options.vertexIncludes, fincludes: options.fragmentIncludes, fshader: fragCode, useTransformFeedback: options.useTransformFeedback }; } static getDefinesCode(defines) { let code = ''; defines == null || defines.forEach((value, key) => { code += `#define ${key} ${value}\n`; }); return code; } static getShaderNameCode(name) { return `#define SHADER_NAME ${name}\n`; } static gl1Extensions(device, options, isVertex) { let code; if (isVertex) { code = options.vertexExtensions ? `${options.vertexExtensions}\n` : ''; } else { code = options.fragmentExtensions ? `${options.fragmentExtensions}\n` : ''; if (device.extStandardDerivatives) { code += '#extension GL_OES_standard_derivatives : enable\n'; } if (device.extTextureLod) { code += '#extension GL_EXT_shader_texture_lod : enable\n'; code += '#define SUPPORTS_TEXLOD\n'; } if (device.extDrawBuffers) { code += '#extension GL_EXT_draw_buffers : require\n'; code += '#define SUPPORTS_MRT\n'; } } return code; } static dummyFragmentCode() { return 'void main(void) {gl_FragColor = vec4(0.0);}'; } static versionCode(device) { if (device.isWebGPU) { return '#version 450\n'; } return device.isWebGL2 ? '#version 300 es\n' : ''; } static precisionCode(device, forcePrecision) { let code = ''; if (forcePrecision && forcePrecision !== 'highp' && forcePrecision !== 'mediump' && forcePrecision !== 'lowp') { forcePrecision = null; } if (forcePrecision) { if (forcePrecision === 'highp' && device.maxPrecision !== 'highp') { forcePrecision = 'mediump'; } if (forcePrecision === 'mediump' && device.maxPrecision === 'lowp') { forcePrecision = 'lowp'; } } const precision = forcePrecision ? forcePrecision : device.precision; if (!device.isWebGPU) { code = `precision ${precision} float;\nprecision ${precision} int;`; if (device.isWebGL2) { code += `precision ${precision} sampler2DShadow;\n`; } } else { code = `precision ${precision} float;\nprecision ${precision} int;\n`; } return code; } static collectAttributes(vsCode) { const attribs = {}; let attrs = 0; let found = vsCode.indexOf('attribute'); while (found >= 0) { if (found > 0 && vsCode[found - 1] === '/') break; const endOfLine = vsCode.indexOf(';', found); const startOfAttribName = vsCode.lastIndexOf(' ', endOfLine); const attribName = vsCode.substring(startOfAttribName + 1, endOfLine); if (attribs[attribName]) ; else { const semantic = _attrib2Semantic[attribName]; if (semantic !== undefined) { attribs[attribName] = semantic; } else { attribs[attribName] = `ATTR${attrs}`; attrs++; } } found = vsCode.indexOf('attribute', found + 1); } return attribs; } } export { ShaderUtils };