playcanvas
Version:
PlayCanvas WebGL game engine
185 lines (182 loc) • 7.21 kB
JavaScript
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 };