Skip to content

Commit

Permalink
Refactor of private ShaderPass class to be dynamic instead of hardcod…
Browse files Browse the repository at this point in the history
…ed (#5256)

* Refactor of private ShaderPass class to be dynamic instead of hardcoded

* removed reduntant ignores

---------

Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
  • Loading branch information
mvaligursky and Martin Valigursky authored Apr 20, 2023
1 parent 12d6b79 commit 664d24a
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 125 deletions.
2 changes: 1 addition & 1 deletion src/deprecated/deprecated.js
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ _defineAlias('sheenGloss', 'sheenGlossiess');
_defineAlias('clearCoatGloss', 'clearCostGlossiness');

function _defineOption(name, newName) {
if (name !== 'chunks' && name !== '_pass') {
if (name !== 'chunks' && name !== '_pass' && name !== '_isForwardPass') {
Object.defineProperty(StandardMaterialOptions.prototype, name, {
get: function () {
Debug.deprecated(`Getting pc.Options#${name} has been deprecated as the property has been moved to pc.Options.LitOptions#${newName || name}.`);
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export { MorphTarget } from './scene/morph-target.js';
export { ParticleEmitter } from './scene/particle-system/particle-emitter.js';
export { QuadRender } from './scene/graphics/quad-render.js';
export { Scene } from './scene/scene.js';
export { ShaderPass } from './scene/shader-pass.js';
export { Skin } from './scene/skin.js';
export { SkinInstance } from './scene/skin-instance.js';
export { Sprite } from './scene/sprite.js';
Expand Down
26 changes: 2 additions & 24 deletions src/scene/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -650,30 +650,8 @@ export const SHADER_DEPTH = 2;
// shader pass used by the Picker class to render mesh ID
export const SHADER_PICK = 3;

// next shader pass constants are undocumented - see ShaderPass class
export const SHADER_SHADOW = 4; // start of shadow related pass constants
// 4 = PCF3 DIR
// 5 = VSM8 DIR
// 6 = VSM16 DIR
// 7 = VSM32 DIR
// 8 = PCF5 DIR
// 9 = PCF1 DIR

// 10 = PCF3 OMNI
// 11 = VSM8 OMNI
// 12 = VSM16 OMNI
// 13 = VSM32 OMNI
// 14 = PCF5 OMNI
// 15 = PCF1 OMNI

// 16 = PCF3 SPOT
// 17 = VSM8 SPOT
// 18 = VSM16 SPOT
// 19 = VSM32 SPOT
// 20 = PCF5 SPOT
// 21 = PCF1 SPOT

// Note: the Editor is using constant 24 for its internal purpose
// shadow pass used by the shadow rendering code
export const SHADER_SHADOW = 4;

/**
* Shader that performs forward rendering.
Expand Down
10 changes: 10 additions & 0 deletions src/scene/materials/lit-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class LitOptions {

_pass = 0;

_isForwardPass = false;

/**
* Enable alpha testing. See {@link Material#alphaTest}.
*
Expand Down Expand Up @@ -328,6 +330,14 @@ class LitOptions {
get pass() {
return this._pass;
}

set isForwardPass(p) {
Debug.warn(`pc.LitOptions#isForwardPass should be set by its parent pc.StandardMaterialOptions, setting it directly has no effect.`);
}

get isForwardPass() {
return this._isForwardPass;
}
}

export { LitOptions };
12 changes: 12 additions & 0 deletions src/scene/materials/standard-material-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class StandardMaterialOptions {
/** @private */
_pass = 0;

/** @private */
_isForwardPass = false;

chunks = [];

/**
Expand Down Expand Up @@ -115,6 +118,15 @@ class StandardMaterialOptions {
get pass() {
return this._pass;
}

set isForwardPass(value) {
this._isForwardPass = value;
this.litOptions._isForwardPass = value;
}

get isForwardPass() {
return this._isForwardPass;
}
}

export { StandardMaterialOptions };
3 changes: 2 additions & 1 deletion src/scene/materials/standard-material.js
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,8 @@ class StandardMaterial extends Material {
this.updateEnvUniforms(device, scene);

// Minimal options for Depth and Shadow passes
const minimalOptions = pass === SHADER_DEPTH || pass === SHADER_PICK || ShaderPass.isShadow(pass);
const shaderPassInfo = ShaderPass.get(device).getByIndex(pass);
const minimalOptions = pass === SHADER_DEPTH || pass === SHADER_PICK || shaderPassInfo.isShadowPass;
let options = minimalOptions ? standard.optionsContextMin : standard.optionsContext;

if (minimalOptions)
Expand Down
4 changes: 3 additions & 1 deletion src/scene/particle-system/particle-emitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import {
EMITTERSHAPE_BOX,
PARTICLEMODE_GPU,
PARTICLEORIENTATION_SCREEN, PARTICLEORIENTATION_WORLD,
PARTICLESORT_NONE
PARTICLESORT_NONE,
SHADER_FORWARD
} from '../constants.js';
import { Mesh } from '../mesh.js';
import { MeshInstance } from '../mesh-instance.js';
Expand Down Expand Up @@ -857,6 +858,7 @@ class ParticleEmitter {
const processingOptions = new ShaderProcessorOptions(viewUniformFormat, viewBindGroupFormat);

const shader = programLib.getProgram('particle', {
pass: SHADER_FORWARD,
useCpu: this.emitter.useCpu,
normal: this.emitter.normalOption,
halflambert: this.emitter.halfLambert,
Expand Down
37 changes: 34 additions & 3 deletions src/scene/renderer/shadow-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ function getDepthKey(meshInstance) {
* @ignore
*/
class ShadowRenderer {
/**
* A cache of shadow passes. First index is looked up by light type, second by shadow type.
*
* @type {import('../shader-pass.js').ShaderPassInfo[][]}
* @private
*/
shadowPassCache = [];

/**
* @param {import('./renderer.js').Renderer} renderer - The renderer.
* @param {import('../lighting/light-texture-atlas.js').LightTextureAtlas} lightTextureAtlas - The
Expand Down Expand Up @@ -243,6 +251,31 @@ class ShadowRenderer {
}
}

getShadowPass(light) {

// get shader pass from cache for this light type and shadow type
const lightType = light._type;
const shadowType = light._shadowType;
let shadowPassInfo = this.shadowPassCache[lightType]?.[shadowType];
if (!shadowPassInfo) {

// new shader pass if not in cache
const shadowPassName = `ShadowPass_${lightType}_${shadowType}`;
shadowPassInfo = ShaderPass.get(this.device).allocate(shadowPassName, {
isShadow: true,
lightType: lightType,
shadowType: shadowType
});

// add it to the cache
if (!this.shadowPassCache[lightType])
this.shadowPassCache[lightType] = [];
this.shadowPassCache[lightType][shadowType] = shadowPassInfo;
}

return shadowPassInfo.index;
}

/**
* @param {import('../mesh-instance.js').MeshInstance[]} visibleCasters - Visible mesh
* instances.
Expand All @@ -254,9 +287,7 @@ class ShadowRenderer {
const renderer = this.renderer;
const scene = renderer.scene;
const passFlags = 1 << SHADER_SHADOW;

// Sort shadow casters
const shadowPass = ShaderPass.getShadow(light._type, light._shadowType);
const shadowPass = this.getShadowPass(light);

// TODO: Similarly to forward renderer, a shader creation part of this loop should be split into a separate loop,
// and endShaderBatch should be called at its end
Expand Down
12 changes: 10 additions & 2 deletions src/scene/shader-lib/program-library.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,16 @@ class ProgramLibrary {
const generatedShaderDef = this.generateShaderDefinition(generator, name, generationKey, options);
Debug.assert(generatedShaderDef);

// use shader pass name if known
let passName = '';
if (options.pass) {
const shaderPassInfo = ShaderPass.get(this._device).getByIndex(options.pass);
passName = `-${shaderPassInfo.name}`;
}

// create a shader definition for the shader that will include the processingOptions
const shaderDefinition = {
name: `${generatedShaderDef.name}-processed`,
name: `${generatedShaderDef.name}${passName}-proc`,
attributes: generatedShaderDef.attributes,
vshader: generatedShaderDef.vshader,
fshader: generatedShaderDef.fshader,
Expand Down Expand Up @@ -224,7 +231,8 @@ class ProgramLibrary {
}

_getDefaultStdMatOptions(pass) {
return (pass === SHADER_DEPTH || pass === SHADER_PICK || ShaderPass.isShadow(pass)) ?
const shaderPassInfo = ShaderPass.get(this._device).getByIndex(pass);
return (pass === SHADER_DEPTH || pass === SHADER_PICK || shaderPassInfo.isShadow) ?
this._defaultStdMatOptionMin : this._defaultStdMatOption;
}

Expand Down
3 changes: 2 additions & 1 deletion src/scene/shader-lib/programs/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ const basic = {
attributes.vertex_texCoord0 = SEMANTIC_TEXCOORD0;
}

const shaderPassDefine = ShaderPass.getPassShaderDefine(options.pass);
const shaderPassInfo = ShaderPass.get(device).getByIndex(options.pass);
const shaderPassDefine = shaderPassInfo.shaderDefine;

// GENERATE VERTEX SHADER
let vshader = shaderPassDefine;
Expand Down
18 changes: 10 additions & 8 deletions src/scene/shader-lib/programs/lit-shader.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
LIGHTSHAPE_PUNCTUAL, LIGHTSHAPE_RECT, LIGHTSHAPE_DISK, LIGHTSHAPE_SPHERE,
LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_OMNI, LIGHTTYPE_SPOT,
SHADER_DEPTH, SHADER_PICK,
SHADOW_PCF3, SHADOW_PCF5, SHADOW_VSM8, SHADOW_VSM16, SHADOW_VSM32,
SHADOW_PCF1, SHADOW_PCF3, SHADOW_PCF5, SHADOW_VSM8, SHADOW_VSM16, SHADOW_VSM32,
SPECOCC_AO, SPECOCC_GLOSSDEPENDENT,
SPECULAR_PHONG,
SPRITE_RENDERMODE_SLICED, SPRITE_RENDERMODE_TILED, shadowTypeToString
Expand Down Expand Up @@ -93,9 +93,11 @@ class LitShader {
this.chunks = shaderChunks;
}

this.shaderPassInfo = ShaderPass.get(this.device).getByIndex(options.pass);
this.shadowPass = this.shaderPassInfo.isShadow;

this.lighting = (options.lights.length > 0) || options.dirLightMapEnabled || options.clusteredLightingEnabled;
this.reflections = !!options.reflectionSource;
this.shadowPass = ShaderPass.isShadow(options.pass);
this.needsNormal = this.lighting || this.reflections || options.useSpecular || options.ambientSH || options.heightMapEnabled || options.enableGGXSpecular ||
(options.clusteredLightingEnabled && !this.shadowPass) || options.clearCoatNormalMapEnabled;
this.needsNormal = this.needsNormal && !this.shadowPass;
Expand Down Expand Up @@ -433,13 +435,13 @@ class LitShader {
}
});

const shaderPassDefine = ShaderPass.getPassShaderDefine(this.options.pass);
const shaderPassDefine = this.shaderPassInfo.shaderDefine;
this.vshader = shaderPassDefine + this.varyings + code;
}

_fsGetBeginCode() {

let code = ShaderPass.getPassShaderDefine(this.options.pass);
let code = this.shaderPassInfo.shaderDefine;

for (let i = 0; i < this.defines.length; i++) {
code += `#define ${this.defines[i]}\n`;
Expand Down Expand Up @@ -485,8 +487,8 @@ class LitShader {
const chunks = this.chunks;
const varyings = this.varyings;

const lightType = ShaderPass.toLightType(options.pass);
const shadowType = ShaderPass.toShadowType(options.pass);
const lightType = this.shaderPassInfo.lightType;
const shadowType = this.shaderPassInfo.shadowType;

let code = this._fsGetBeginCode();

Expand Down Expand Up @@ -544,7 +546,7 @@ class LitShader {

if (shadowType === SHADOW_PCF3 && (!device.webgl2 || (lightType === LIGHTTYPE_OMNI && !options.clusteredLightingEnabled))) {
code += " gl_FragColor = packFloat(depth);\n";
} else if (shadowType === SHADOW_PCF3 || shadowType === SHADOW_PCF5) {
} else if (shadowType === SHADOW_PCF3 || shadowType === SHADOW_PCF5 || shadowType === SHADOW_PCF1) {
code += " gl_FragColor = vec4(1.0);\n"; // just the simplest code, color is not written anyway

// clustered omni light is using shadow sampler and needs to write custom depth
Expand Down Expand Up @@ -1510,7 +1512,7 @@ class LitShader {
fragmentCode: this.fshader
});

if (ShaderPass.isForward(this.options.pass)) {
if (this.options.isForwardPass) {
definition.tag = SHADERTAG_MATERIAL;
}

Expand Down
9 changes: 7 additions & 2 deletions src/scene/shader-lib/programs/standard.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const standard = {
_getUvSourceExpression: function (transformPropName, uVPropName, options) {
const transformId = options[transformPropName];
const uvChannel = options[uVPropName];
const isMainPass = ShaderPass.isForward(options.pass);
const isMainPass = options.isForwardPass;

let expression;
if (isMainPass && options.litOptions.nineSlicedMode === SPRITE_RENDERMODE_SLICED) {
Expand Down Expand Up @@ -240,6 +240,11 @@ const standard = {
* @ignore
*/
createShaderDefinition: function (device, options) {

const shaderPassInfo = ShaderPass.get(device).getByIndex(options.pass);
const isForwardPass = shaderPassInfo.isForward;
options.isForwardPass = isForwardPass;

const litShader = new LitShader(device, options.litOptions);

// generate vertex shader
Expand Down Expand Up @@ -308,7 +313,7 @@ const standard = {
decl.append(`uniform float textureBias;`);
}

if (ShaderPass.isForward(options.pass)) {
if (isForwardPass) {
// parallax
if (options.heightMap) {
// if (!options.normalMap) {
Expand Down
Loading

0 comments on commit 664d24a

Please sign in to comment.