Skip to content

Commit 51caad7

Browse files
mvaligurskyMartin Valigursky
and
Martin Valigursky
committed
Updates to material chunks override functionality (#7284)
* Updates to material chunks override functionality * lint * cleanup --------- Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
1 parent 57f7af5 commit 51caad7

File tree

8 files changed

+104
-76
lines changed

8 files changed

+104
-76
lines changed

src/scene/materials/lit-material.js

-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ class LitMaterial extends Material {
2424

2525
shaderChunk = 'void evaluateFrontend() {}\n';
2626

27-
chunks = null;
28-
2927
useLighting = true;
3028

3129
useFog = true;

src/scene/materials/material.js

+34
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,39 @@ class Material {
173173
*/
174174
stencilBack = null;
175175

176+
/**
177+
* @type {Object<string, string>}
178+
* @private
179+
*/
180+
_chunks = { };
181+
176182
/** @protected */
177183
constructor() {
178184
if (new.target === Material) {
179185
Debug.error('Material class cannot be instantiated, use ShaderMaterial instead');
180186
}
181187
}
182188

189+
/**
190+
* Sets the object containing custom shader chunks that will replace default ones.
191+
*
192+
* @type {Object<string, string>}
193+
*/
194+
set chunks(value) {
195+
this.clearVariants();
196+
this._chunks = value;
197+
}
198+
199+
/**
200+
* Gets the object containing custom shader chunks.
201+
*
202+
* @type {Object<string, string>}
203+
*/
204+
get chunks() {
205+
this.clearVariants();
206+
return this._chunks;
207+
}
208+
183209
/**
184210
* Sets the offset for the output depth buffer value. Useful for decals to prevent z-fighting.
185211
* Typically a small negative value (-0.1) is used to render the mesh slightly closer to the
@@ -534,6 +560,14 @@ class Material {
534560
this.defines.clear();
535561
source.defines.forEach((value, key) => this.defines.set(key, value));
536562

563+
// chunks
564+
const srcChunks = source._chunks;
565+
for (const p in srcChunks) {
566+
if (srcChunks.hasOwnProperty(p)) {
567+
this._chunks[p] = srcChunks[p];
568+
}
569+
}
570+
537571
return this;
538572
}
539573

src/scene/materials/shader-material.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ class ShaderMaterial extends Material {
110110
gamma: params.cameraShaderParams.shaderOutputGamma,
111111
toneMapping: params.cameraShaderParams.toneMapping,
112112
fog: params.cameraShaderParams.fog,
113-
shaderDesc: this.shaderDesc
113+
shaderDesc: this.shaderDesc,
114+
chunks: this.chunks ?? {} // override chunks from the material
114115
};
115116

116117
const processingOptions = new ShaderProcessorOptions(params.viewUniformFormat, params.viewBindGroupFormat, params.vertexFormat);

src/scene/materials/standard-material.js

-27
Original file line numberDiff line numberDiff line change
@@ -588,29 +588,9 @@ class StandardMaterial extends Material {
588588
this[`_${name}`] = _props[name].value();
589589
});
590590

591-
/**
592-
* @type {Object<string, string>}
593-
* @private
594-
*/
595-
this._chunks = { };
596591
this._uniformCache = { };
597592
}
598593

599-
/**
600-
* Object containing custom shader chunks that will replace default ones.
601-
*
602-
* @type {Object<string, string>}
603-
*/
604-
set chunks(value) {
605-
this._dirtyShader = true;
606-
this._chunks = value;
607-
}
608-
609-
get chunks() {
610-
this._dirtyShader = true;
611-
return this._chunks;
612-
}
613-
614594
/**
615595
* Copy a `StandardMaterial`.
616596
*
@@ -625,13 +605,6 @@ class StandardMaterial extends Material {
625605
this[k] = source[k];
626606
});
627607

628-
// clone chunks
629-
for (const p in source._chunks) {
630-
if (source._chunks.hasOwnProperty(p)) {
631-
this._chunks[p] = source._chunks[p];
632-
}
633-
}
634-
635608
// clone user attributes
636609
this.userAttributes = new Map(source.userAttributes);
637610

src/scene/shader-lib/programs/lit-shader.js

+1-30
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import {
22
SEMANTIC_ATTR8, SEMANTIC_ATTR9, SEMANTIC_ATTR12, SEMANTIC_ATTR13, SEMANTIC_ATTR14, SEMANTIC_ATTR15,
33
SEMANTIC_BLENDINDICES, SEMANTIC_BLENDWEIGHT, SEMANTIC_COLOR, SEMANTIC_NORMAL, SEMANTIC_POSITION, SEMANTIC_TANGENT,
4-
SEMANTIC_TEXCOORD0, SEMANTIC_TEXCOORD1,
5-
SHADERTAG_MATERIAL
4+
SEMANTIC_TEXCOORD0, SEMANTIC_TEXCOORD1
65
} from '../../../platform/graphics/constants.js';
76
import {
87
BLEND_ADDITIVEALPHA, BLEND_NORMAL, BLEND_PREMULTIPLIED,
@@ -21,7 +20,6 @@ import { ChunkUtils } from '../chunk-utils.js';
2120
import { LightsBuffer } from '../../lighting/lights-buffer.js';
2221
import { ShaderPass } from '../../shader-pass.js';
2322
import { validateUserChunks } from '../chunks/chunk-validation.js';
24-
import { ShaderUtils } from '../../../platform/graphics/shader-utils.js';
2523
import { ChunkBuilder } from '../chunk-builder.js';
2624
import { ShaderGenerator } from './shader-generator.js';
2725
import { Debug } from '../../../core/debug.js';
@@ -1531,33 +1529,6 @@ class LitShader {
15311529

15321530
Debug.assert(!this.fshader.includes('litShaderArgs'), 'Automatic compatibility with shaders using litShaderArgs has been removed. Please update the shader to use the new system.');
15331531
}
1534-
1535-
getDefinition(options) {
1536-
1537-
const vIncludes = new Map();
1538-
vIncludes.set('transformCoreVS', this.chunks.transformCoreVS);
1539-
vIncludes.set('transformInstancingVS', this.chunks.transformInstancingVS);
1540-
vIncludes.set('skinVS', this.chunks.skinVS);
1541-
vIncludes.set('skinBatchVS', this.chunks.skinBatchVS);
1542-
1543-
const defines = new Map(options.defines);
1544-
1545-
const definition = ShaderUtils.createDefinition(this.device, {
1546-
name: 'LitShader',
1547-
attributes: this.attributes,
1548-
vertexCode: this.vshader,
1549-
fragmentCode: this.fshader,
1550-
vertexIncludes: vIncludes,
1551-
fragmentDefines: defines,
1552-
vertexDefines: defines
1553-
});
1554-
1555-
if (this.shaderPassInfo.isForward) {
1556-
definition.tag = SHADERTAG_MATERIAL;
1557-
}
1558-
1559-
return definition;
1560-
}
15611532
}
15621533

15631534
export { LitShader };

src/scene/shader-lib/programs/lit.js

+27-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import { ChunkBuilder } from '../chunk-builder.js';
22
import { LitShader } from './lit-shader.js';
33
import { LitOptionsUtils } from './lit-options-utils.js';
44
import { ShaderGenerator } from './shader-generator.js';
5+
import { SHADERTAG_MATERIAL } from '../../../platform/graphics/constants.js';
6+
import { ShaderUtils } from '../../../platform/graphics/shader-utils.js';
57

68
/**
79
* @import { GraphicsDevice } from '../../../platform/graphics/graphics-device.js'
10+
* @import { LitMaterialOptions } from '../../materials/lit-material-options.js'
811
*/
912

1013
const dummyUvs = [0, 1, 2, 3, 4, 5, 6, 7];
@@ -24,7 +27,7 @@ class ShaderGeneratorLit extends ShaderGenerator {
2427

2528
/**
2629
* @param {GraphicsDevice} device - The graphics device.
27-
* @param {object} options - The options to be passed to the backend.
30+
* @param {LitMaterialOptions} options - The options to be passed to the backend.
2831
* @returns {object} Returns the created shader definition.
2932
*/
3033
createShaderDefinition(device, options) {
@@ -47,7 +50,29 @@ class ShaderGeneratorLit extends ShaderGenerator {
4750
litShader.generateVertexShader(usedUvSets, usedUvSets, mapTransforms);
4851
litShader.generateFragmentShader(decl.code, code.code, func.code, 'vUv0');
4952

50-
return litShader.getDefinition(options);
53+
const vIncludes = new Map(Object.entries({
54+
...Object.getPrototypeOf(litShader.chunks), // the prototype stores the default chunks
55+
...litShader.chunks, // user overrides are supplied as instance properties
56+
...options.litOptions.chunks
57+
}));
58+
59+
const defines = new Map(options.defines);
60+
61+
const definition = ShaderUtils.createDefinition(device, {
62+
name: 'LitShader',
63+
attributes: litShader.attributes,
64+
vertexCode: litShader.vshader,
65+
fragmentCode: litShader.fshader,
66+
vertexIncludes: vIncludes,
67+
fragmentDefines: defines,
68+
vertexDefines: defines
69+
});
70+
71+
if (litShader.shaderPassInfo.isForward) {
72+
definition.tag = SHADERTAG_MATERIAL;
73+
}
74+
75+
return definition;
5176
}
5277
}
5378

src/scene/shader-lib/programs/shader-generator-shader.js

+15-13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const fShader = `
2222

2323
class ShaderGeneratorShader extends ShaderGenerator {
2424
generateKey(options) {
25+
26+
// Note: options.chunks are not included in the key as currently shader variants are removed
27+
// from the material when its chunks are modified.
28+
2529
const desc = options.shaderDesc;
2630
const vsHash = desc.vertexCode ? hashCode(desc.vertexCode) : 0;
2731
const fsHash = desc.fragmentCode ? hashCode(desc.fragmentCode) : 0;
@@ -66,7 +70,7 @@ class ShaderGeneratorShader extends ShaderGenerator {
6670
defines.set('GAMMA', gammaNames[options.gamma]);
6771
}
6872

69-
createVertexDefinition(definitionOptions, options, shaderPassInfo) {
73+
createVertexDefinition(definitionOptions, options, shaderPassInfo, sharedIncludes) {
7074

7175
const desc = options.shaderDesc;
7276

@@ -77,10 +81,7 @@ class ShaderGeneratorShader extends ShaderGenerator {
7781
definitionOptions.vertexCode = desc.vertexCode;
7882

7983
} else {
80-
const includes = new Map(Object.entries({
81-
...shaderChunks,
82-
...options.chunks
83-
}));
84+
const includes = new Map(sharedIncludes);
8485
const defines = new Map(options.defines);
8586
this.addSharedDefines(defines, options);
8687

@@ -103,7 +104,7 @@ class ShaderGeneratorShader extends ShaderGenerator {
103104
}
104105
}
105106

106-
createFragmentDefinition(definitionOptions, options, shaderPassInfo) {
107+
createFragmentDefinition(definitionOptions, options, shaderPassInfo, sharedIncludes) {
107108

108109
const desc = options.shaderDesc;
109110

@@ -114,11 +115,7 @@ class ShaderGeneratorShader extends ShaderGenerator {
114115
definitionOptions.fragmentCode = desc.fragmentCode;
115116

116117
} else {
117-
const includes = new Map(Object.entries({
118-
...shaderChunks,
119-
...options.chunks
120-
}));
121-
118+
const includes = new Map(sharedIncludes);
122119
includes.set('shaderPassDefines', shaderPassInfo.shaderDefines);
123120
includes.set('gamma', ShaderGenerator.gammaCode(options.gamma));
124121
includes.set('fog', ShaderGenerator.fogCode(options.fog));
@@ -146,9 +143,14 @@ class ShaderGeneratorShader extends ShaderGenerator {
146143
meshBindGroupFormat: desc.meshBindGroupFormat
147144
};
148145

146+
const sharedIncludes = new Map(Object.entries({
147+
...shaderChunks, // default chunks
148+
...options.chunks // material override chunks
149+
}));
150+
149151
this.createAttributesDefinition(definitionOptions, options);
150-
this.createVertexDefinition(definitionOptions, options, shaderPassInfo);
151-
this.createFragmentDefinition(definitionOptions, options, shaderPassInfo);
152+
this.createVertexDefinition(definitionOptions, options, shaderPassInfo, sharedIncludes);
153+
this.createFragmentDefinition(definitionOptions, options, shaderPassInfo, sharedIncludes);
152154

153155
return ShaderUtils.createDefinition(device, definitionOptions);
154156
}

src/scene/shader-lib/programs/standard.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { ChunkUtils } from '../chunk-utils.js';
1111
import { StandardMaterialOptions } from '../../materials/standard-material-options.js';
1212
import { LitOptionsUtils } from './lit-options-utils.js';
1313
import { ShaderGenerator } from './shader-generator.js';
14+
import { ShaderUtils } from '../../../platform/graphics/shader-utils.js';
15+
import { SHADERTAG_MATERIAL } from '../../../platform/graphics/constants.js';
1416

1517
/**
1618
* @import { GraphicsDevice } from '../../../platform/graphics/graphics-device.js'
@@ -528,7 +530,29 @@ class ShaderGeneratorStandard extends ShaderGenerator {
528530

529531
litShader.generateFragmentShader(decl.code, code.code, func.code, lightingUv);
530532

531-
return litShader.getDefinition(options);
533+
const vIncludes = new Map(Object.entries({
534+
...Object.getPrototypeOf(litShader.chunks), // the prototype stores the default chunks
535+
...litShader.chunks, // user overrides are supplied as instance properties
536+
...options.litOptions.chunks
537+
}));
538+
539+
const defines = new Map(options.defines);
540+
541+
const definition = ShaderUtils.createDefinition(device, {
542+
name: 'StandardShader',
543+
attributes: litShader.attributes,
544+
vertexCode: litShader.vshader,
545+
fragmentCode: litShader.fshader,
546+
vertexIncludes: vIncludes,
547+
fragmentDefines: defines,
548+
vertexDefines: defines
549+
});
550+
551+
if (litShader.shaderPassInfo.isForward) {
552+
definition.tag = SHADERTAG_MATERIAL;
553+
}
554+
555+
return definition;
532556
}
533557
}
534558

0 commit comments

Comments
 (0)