UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

185 lines (182 loc) 7.21 kB
import { SHADERLANGUAGE_WGSL, SHADERLANGUAGE_GLSL, SEMANTIC_BLENDWEIGHT, SEMANTIC_BLENDINDICES, SEMANTIC_COLOR, SEMANTIC_TEXCOORD7, SEMANTIC_TEXCOORD6, SEMANTIC_TEXCOORD5, SEMANTIC_TEXCOORD4, SEMANTIC_TEXCOORD3, SEMANTIC_TEXCOORD2, SEMANTIC_TEXCOORD1, SEMANTIC_TEXCOORD0, SEMANTIC_TANGENT, SEMANTIC_NORMAL, SEMANTIC_POSITION, primitiveGlslToWgslTypeMap } from './constants.js'; import gles3PS from './shader-chunks/frag/gles3.js'; import gles3VS from './shader-chunks/vert/gles3.js'; import webgpuPS$1 from './shader-chunks/frag/webgpu.js'; import webgpuVS$1 from './shader-chunks/vert/webgpu.js'; import webgpuPS from './shader-chunks/frag/webgpu-wgsl.js'; import webgpuVS from './shader-chunks/vert/webgpu-wgsl.js'; import sharedGLSL from './shader-chunks/frag/shared.js'; import sharedWGSL from './shader-chunks/frag/shared-wgsl.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 ShaderDefinitionUtils { static createDefinition(device, options) { const normalizedOutputTypes = (options)=>{ let fragmentOutputTypes = options.fragmentOutputTypes ?? 'vec4'; if (!Array.isArray(fragmentOutputTypes)) { fragmentOutputTypes = [ fragmentOutputTypes ]; } return fragmentOutputTypes; }; const getDefines = (gpu, gl2, isVertex, options)=>{ const deviceIntro = device.isWebGPU ? gpu : gl2; let attachmentsDefine = ''; if (!isVertex) { const fragmentOutputTypes = normalizedOutputTypes(options); for(let i = 0; i < device.maxColorAttachments; i++){ attachmentsDefine += `#define COLOR_ATTACHMENT_${i}\n`; const outType = fragmentOutputTypes[i] ?? 'vec4'; attachmentsDefine += `#define outType_${i} ${outType}\n`; } } return attachmentsDefine + deviceIntro; }; const getDefinesWgsl = (isVertex, options)=>{ let attachmentsDefine = ''; if (!isVertex) { const fragmentOutputTypes = normalizedOutputTypes(options); for(let i = 0; i < device.maxColorAttachments; i++){ const glslOutType = fragmentOutputTypes[i] ?? 'vec4'; const wgslOutType = primitiveGlslToWgslTypeMap.get(glslOutType); attachmentsDefine += `alias pcOutType${i} = ${wgslOutType};\n`; } } return attachmentsDefine; }; const name = options.name ?? 'Untitled'; let vertCode; let fragCode; const vertexDefinesCode = ShaderDefinitionUtils.getDefinesCode(device, options.vertexDefines); const fragmentDefinesCode = ShaderDefinitionUtils.getDefinesCode(device, options.fragmentDefines); const wgsl = options.shaderLanguage === SHADERLANGUAGE_WGSL; if (wgsl) { vertCode = ` ${getDefinesWgsl(true, options)} ${webgpuVS} ${sharedWGSL} ${vertexDefinesCode} ${options.vertexCode} `; fragCode = ` ${getDefinesWgsl(false, options)} ${webgpuPS} ${sharedWGSL} ${fragmentDefinesCode} ${options.fragmentCode} `; } else { vertCode = `${ShaderDefinitionUtils.versionCode(device) + getDefines(webgpuVS$1, gles3VS, true, options) + vertexDefinesCode + ShaderDefinitionUtils.precisionCode(device)} ${sharedGLSL} ${ShaderDefinitionUtils.getShaderNameCode(name)} ${options.vertexCode}`; fragCode = `${(options.fragmentPreamble || '') + ShaderDefinitionUtils.versionCode(device) + getDefines(webgpuPS$1, gles3PS, false, options) + fragmentDefinesCode + ShaderDefinitionUtils.precisionCode(device)} ${sharedGLSL} ${ShaderDefinitionUtils.getShaderNameCode(name)} ${options.fragmentCode}`; } return { name: name, shaderLanguage: options.shaderLanguage ?? SHADERLANGUAGE_GLSL, attributes: options.attributes, vshader: vertCode, vincludes: options.vertexIncludes, fincludes: options.fragmentIncludes, fshader: fragCode, useTransformFeedback: options.useTransformFeedback, meshUniformBufferFormat: options.meshUniformBufferFormat, meshBindGroupFormat: options.meshBindGroupFormat }; } static getDefinesCode(device, defines) { let code = ''; device.capsDefines.forEach((value, key)=>{ code += `#define ${key} ${value}\n`; }); code += '\n'; defines?.forEach((value, key)=>{ code += `#define ${key} ${value}\n`; }); code += '\n'; return code; } static getShaderNameCode(name) { return `#define SHADER_NAME ${name}\n`; } static versionCode(device) { return device.isWebGPU ? '#version 450\n' : '#version 300 es\n'; } static precisionCode(device, forcePrecision) { 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; const code = ` precision ${precision} float; precision ${precision} int; precision ${precision} usampler2D; precision ${precision} isampler2D; precision ${precision} sampler2DShadow; precision ${precision} samplerCubeShadow; precision ${precision} sampler2DArray; `; 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; let ignore = false; if (found > 0) { let startOfLine = vsCode.lastIndexOf('\n', found); startOfLine = startOfLine !== -1 ? startOfLine + 1 : 0; const lineStartString = vsCode.substring(startOfLine, found); if (lineStartString.includes('#')) { ignore = true; } } if (!ignore) { 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 { ShaderDefinitionUtils };