playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
85 lines (82 loc) • 4.32 kB
JavaScript
import { hashCode } from '../../../core/hash.js';
import { MapUtils } from '../../../core/map-utils.js';
import { SEMANTIC_BLENDWEIGHT, SEMANTIC_BLENDINDICES, SEMANTIC_ATTR15, SHADERLANGUAGE_WGSL, SHADERLANGUAGE_GLSL } from '../../../platform/graphics/constants.js';
import { ShaderDefinitionUtils } from '../../../platform/graphics/shader-definition-utils.js';
import { ShaderGenerator } from './shader-generator.js';
import { ShaderChunks } from '../shader-chunks.js';
class ShaderGeneratorShader extends ShaderGenerator {
generateKey(options) {
const desc = options.shaderDesc;
const vsHashGLSL = desc.vertexGLSL ? hashCode(desc.vertexGLSL) : 0;
const fsHashGLSL = desc.fragmentGLSL ? hashCode(desc.fragmentGLSL) : 0;
const vsHashWGSL = desc.vertexWGSL ? hashCode(desc.vertexWGSL) : 0;
const fsHashWGSL = desc.fragmentWGSL ? hashCode(desc.fragmentWGSL) : 0;
const definesHash = ShaderGenerator.definesHash(options.defines);
const chunksKey = options.shaderChunks?.key ?? '';
let key = `${desc.uniqueName}_${definesHash}_${vsHashGLSL}_${fsHashGLSL}_${vsHashWGSL}_${fsHashWGSL}_${chunksKey}`;
if (options.skin) key += '_skin';
if (options.useInstancing) key += '_inst';
if (options.useMorphPosition) key += '_morphp';
if (options.useMorphNormal) key += '_morphn';
if (options.useMorphTextureBasedInt) key += '_morphi';
return key;
}
createAttributesDefinition(definitionOptions, options) {
const srcAttributes = options.shaderDesc.attributes;
const attributes = srcAttributes ? {
...srcAttributes
} : undefined;
if (options.skin) {
attributes.vertex_boneWeights = SEMANTIC_BLENDWEIGHT;
attributes.vertex_boneIndices = SEMANTIC_BLENDINDICES;
}
if (options.useMorphPosition || options.useMorphNormal) {
attributes.morph_vertex_id = SEMANTIC_ATTR15;
}
definitionOptions.attributes = attributes;
}
createVertexDefinition(definitionOptions, options, sharedIncludes, wgsl) {
const desc = options.shaderDesc;
const includes = new Map(sharedIncludes);
includes.set('transformInstancingVS', '');
const defines = new Map(options.defines);
if (options.skin) defines.set('SKIN', true);
if (options.useInstancing) defines.set('INSTANCING', true);
if (options.useMorphPosition || options.useMorphNormal) {
defines.set('MORPHING', true);
if (options.useMorphTextureBasedInt) defines.set('MORPHING_INT', true);
if (options.useMorphPosition) defines.set('MORPHING_POSITION', true);
if (options.useMorphNormal) defines.set('MORPHING_NORMAL', true);
}
definitionOptions.vertexCode = wgsl ? desc.vertexWGSL : desc.vertexGLSL;
definitionOptions.vertexIncludes = includes;
definitionOptions.vertexDefines = defines;
}
createFragmentDefinition(definitionOptions, options, sharedIncludes, wgsl) {
const desc = options.shaderDesc;
const includes = new Map(sharedIncludes);
const defines = new Map(options.defines);
definitionOptions.fragmentCode = wgsl ? desc.fragmentWGSL : desc.fragmentGLSL;
definitionOptions.fragmentIncludes = includes;
definitionOptions.fragmentDefines = defines;
}
createShaderDefinition(device, options) {
const desc = options.shaderDesc;
const wgsl = device.isWebGPU && !!desc.vertexWGSL && !!desc.fragmentWGSL && (options.shaderChunks?.useWGSL ?? true);
const definitionOptions = {
name: `ShaderMaterial-${desc.uniqueName}`,
shaderLanguage: wgsl ? SHADERLANGUAGE_WGSL : SHADERLANGUAGE_GLSL,
fragmentOutputTypes: desc.fragmentOutputTypes,
meshUniformBufferFormat: desc.meshUniformBufferFormat,
meshBindGroupFormat: desc.meshBindGroupFormat
};
const shaderLanguage = wgsl ? SHADERLANGUAGE_WGSL : SHADERLANGUAGE_GLSL;
const sharedIncludes = MapUtils.merge(ShaderChunks.get(device, shaderLanguage), options.shaderChunks[shaderLanguage]);
this.createAttributesDefinition(definitionOptions, options);
this.createVertexDefinition(definitionOptions, options, sharedIncludes, wgsl);
this.createFragmentDefinition(definitionOptions, options, sharedIncludes, wgsl);
return ShaderDefinitionUtils.createDefinition(device, definitionOptions);
}
}
const shaderGeneratorShader = new ShaderGeneratorShader();
export { shaderGeneratorShader };