playcanvas
Version:
PlayCanvas WebGL game engine
85 lines (82 loc) • 3.56 kB
JavaScript
import { SEMANTIC_POSITION, SEMANTIC_TEXCOORD0, SEMANTIC_ATTR1, SEMANTIC_ATTR2, SEMANTIC_ATTR3, SEMANTIC_ATTR4, SHADERLANGUAGE_WGSL, SHADERLANGUAGE_GLSL } from '../../../platform/graphics/constants.js';
import { ShaderDefinitionUtils } from '../../../platform/graphics/shader-definition-utils.js';
import { blendNames } from '../../constants.js';
import { ShaderGenerator } from './shader-generator.js';
import { ShaderChunks } from '../shader-chunks.js';
const normalTypeNames = [
'NONE',
'VERTEX',
'MAP'
];
class ShaderGeneratorParticle extends ShaderGenerator {
generateKey(options) {
const definesHash = ShaderGenerator.definesHash(options.defines);
let key = `particle_${definesHash}_`;
for(const prop in options){
if (options.hasOwnProperty(prop)) {
key += options[prop];
}
}
return key;
}
createVertexDefines(options, attributes) {
const vDefines = new Map(options.defines);
if (options.mesh) vDefines.set('USE_MESH', '');
if (options.meshUv) vDefines.set('USE_MESH_UV', '');
if (options.localSpace) vDefines.set('LOCAL_SPACE', '');
if (options.screenSpace) vDefines.set('SCREEN_SPACE', '');
if (options.animTex) vDefines.set('ANIMTEX', '');
if (options.soft > 0) vDefines.set('SOFT', '');
if (options.stretch > 0.0) vDefines.set('STRETCH', '');
if (options.customFace) vDefines.set('CUSTOM_FACE', '');
if (options.pack8) vDefines.set('PACK8', '');
if (options.localSpace) vDefines.set('LOCAL_SPACE', '');
if (options.animTexLoop) vDefines.set('ANIMTEX_LOOP', '');
if (options.wrap) vDefines.set('WRAP', '');
if (options.alignToMotion) vDefines.set('ALIGN_TO_MOTION', '');
vDefines.set('NORMAL', normalTypeNames[options.normal]);
attributes.particle_vertexData = SEMANTIC_POSITION;
if (options.mesh && options.meshUv) {
attributes.particle_uv = SEMANTIC_TEXCOORD0;
}
if (options.useCpu) {
attributes.particle_vertexData2 = SEMANTIC_ATTR1;
attributes.particle_vertexData3 = SEMANTIC_ATTR2;
attributes.particle_vertexData4 = SEMANTIC_ATTR3;
attributes.particle_vertexData5 = SEMANTIC_ATTR4;
}
return vDefines;
}
createFragmentDefines(options) {
const fDefines = new Map(options.defines);
if (options.soft > 0) fDefines.set('SOFT', '');
if (options.halflambert) fDefines.set('HALF_LAMBERT', '');
fDefines.set('NORMAL', normalTypeNames[options.normal]);
fDefines.set('BLEND', blendNames[options.blend]);
return fDefines;
}
createShaderDefinition(device, options) {
const shaderLanguage = device.isWebGPU ? SHADERLANGUAGE_WGSL : SHADERLANGUAGE_GLSL;
const engineChunks = ShaderChunks.get(device, shaderLanguage);
const attributes = {};
const vDefines = this.createVertexDefines(options, attributes);
const fDefines = this.createFragmentDefines(options);
const executionDefine = `PARTICLE_${options.useCpu ? 'CPU' : 'GPU'}\n`;
vDefines.set(executionDefine, '');
fDefines.set(executionDefine, '');
const includes = new Map(engineChunks);
return ShaderDefinitionUtils.createDefinition(device, {
name: 'ParticleShader',
shaderLanguage: shaderLanguage,
attributes: attributes,
vertexCode: engineChunks.get('particle_shaderVS'),
fragmentCode: engineChunks.get('particle_shaderPS'),
fragmentDefines: fDefines,
fragmentIncludes: includes,
vertexIncludes: includes,
vertexDefines: vDefines
});
}
}
const particle = new ShaderGeneratorParticle();
export { particle };