Skip to content

Commit ae68126

Browse files
authored
LitOptions class to hold backend options (#4900)
* Created a LitOptions object to hold the backend options for the lit shader. Also validates that options changed directly through the onUpdateShader so users get some feedback if they set a value moved to the backend options. Changed the name of ambientTint in the backend to be more explanatory, which coincidentally helps with the validation in this PR as well. * Fix lint * Add deprecation callbacks for options. Replacing the options with a class allows for hooking up setters and getters for the parameters that have been moved to the lit options. This allows for a more generic solution for validating option properties having been moved. * Update documentation to reflect options split for onUpdateShader Add refraction as a deprecated option as that is now known as useRefraction and resides in the lit options. Rename options to Standard Material Options. * Add exception for chunks in options which will be allowed to exist in both option sets. * Moved options documentation to their respective files and provide a link to them from the standard material * Since options allocate LitOptions, we don't need to create these options when we run our update refs. * Add exception for pass and duplicate it between the lit and standard options. * Fix lint * Fix tests. * Fix unit test * Fix * Add getter and setter for pass to inform user to always set it on the StandardMaterialOptions. Also updated the documentation to use properties annotations (with types) for typescript. * Fixed pass member name * Use fog constants instead of string * Add missing full stops to some of the comments * Missing full stop * Fix bad import * Fixed docs * Fixed litoptions returning pass * Alphabetical order of LitOptions index import. * Fixed deprecation for pass now renamed to _pass * Fix types. * Add JS docs to the LitOptions and StandardMaterialOptions classes. * Fix setting deprecated options in lit options and options respectively.
1 parent ec2555f commit ae68126

9 files changed

+264
-89
lines changed

src/deprecated/deprecated.js

+24
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ import { SkinInstance } from '../scene/skin-instance.js';
7171
import { StandardMaterial } from '../scene/materials/standard-material.js';
7272
import { Batch } from '../scene/batching/batch.js';
7373
import { getDefaultMaterial } from '../scene/materials/default-material.js';
74+
import { StandardMaterialOptions } from '../scene/materials/standard-material-options.js';
75+
import { LitOptions } from '../scene/materials/lit-options.js';
7476

7577
import { Animation, Key, Node } from '../scene/animation/animation.js';
7678
import { Skeleton } from '../scene/animation/skeleton.js';
@@ -785,6 +787,28 @@ _defineAlias('glossVertexColor', 'glossMapVertexColor');
785787
_defineAlias('opacityVertexColor', 'opacityMapVertexColor');
786788
_defineAlias('lightVertexColor', 'lightMapVertexColor');
787789

790+
function _defineOption(name, newName) {
791+
if (name !== 'chunks' && name !== '_pass') {
792+
Object.defineProperty(StandardMaterialOptions.prototype, name, {
793+
get: function () {
794+
Debug.deprecated(`Getting pc.Options#${name} has been deprecated as the property has been moved to pc.Options.LitOptions#${newName || name}.`);
795+
return this.litOptions[newName || name];
796+
},
797+
set: function (value) {
798+
Debug.deprecated(`Setting pc.Options#${name} has been deprecated as the property has been moved to pc.Options.LitOptions#${newName || name}.`);
799+
this.litOptions[newName || name] = value;
800+
}
801+
});
802+
}
803+
}
804+
_defineOption('refraction', 'useRefraction');
805+
806+
const tempOptions = new LitOptions();
807+
const litOptionProperties = Object.getOwnPropertyNames(tempOptions);
808+
for (const litOption in litOptionProperties) {
809+
_defineOption(litOptionProperties[litOption]);
810+
}
811+
788812
// ANIMATION
789813

790814
export const anim = {

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export { Layer } from './scene/layer.js';
115115
export { LayerComposition } from './scene/composition/layer-composition.js';
116116
export { Light } from './scene/light.js';
117117
export { LightingParams } from './scene/lighting/lighting-params.js';
118+
export { LitOptions } from './scene/materials/lit-options.js';
118119
export { Material } from './scene/materials/material.js';
119120
export { Mesh } from './scene/mesh.js';
120121
export { MeshInstance, Command } from './scene/mesh-instance.js';
@@ -128,6 +129,7 @@ export { Skin } from './scene/skin.js';
128129
export { SkinInstance } from './scene/skin-instance.js';
129130
export { Sprite } from './scene/sprite.js';
130131
export { StandardMaterial } from './scene/materials/standard-material.js';
132+
export { StandardMaterialOptions } from './scene/materials/standard-material-options.js';
131133
export { StencilParameters } from './scene/stencil-parameters.js';
132134
export { TextureAtlas } from './scene/texture-atlas.js';
133135

src/scene/materials/lit-options.js

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { Debug } from '../../core/debug.js';
2+
import {
3+
BLEND_NONE, FOG_NONE, GAMMA_NONE
4+
} from '../constants.js';
5+
6+
/**
7+
* The lit options determines how the lit-shader gets generated. It specifies a set of
8+
* parameters which triggers different fragment and vertex shader generation in the backend.
9+
*
10+
* @property {object} chunks Object containing custom shader chunks that will replace default ones.
11+
* @property {string} customFragmentShader Replaced the whole fragment shader with this string.
12+
* @property {number} fog The type of fog being applied in the shader. See {@link Scene#fog} for the list of
13+
* possible values.
14+
* @property {number} gamma The type of gamma correction being applied in the shader. See
15+
* {@link Scene#gammaCorrection} for the list of possible values.
16+
* @property {number} toneMap The type of tone mapping being applied in the shader. See {@link Scene#toneMapping}
17+
* for the list of possible values.
18+
* @property {boolean} conserveEnergy The value of {@link StandardMaterial#conserveEnergy}.
19+
* @property {number} occludeSpecular The value of {@link StandardMaterial#occludeSpecular}.
20+
* @property {boolean} occludeDirect The value of {@link StandardMaterial#occludeDirect}.
21+
* @property {number} shadingModel The value of {@link StandardMaterial#shadingModel}.
22+
* @property {number} fresnelModel The value of {@link StandardMaterial#fresnelModel}.
23+
* @property {number} cubeMapProjection The value of {@link StandardMaterial#cubeMapProjection}.
24+
* @property {boolean} useMetalness The value of {@link StandardMaterial#useMetalness}.
25+
* @property {number} blendType The value of {@link Material#blendType}.
26+
* @property {boolean} twoSidedLighting The value of {@link Material#twoSidedLighting}.
27+
* @property {number} occludeSpecularFloat Defines if {@link StandardMaterial#occludeSpecularIntensity} constant
28+
* should affect specular occlusion.
29+
* @property {boolean} alphaTest Enable alpha testing. See {@link Material#alphaTest}.
30+
* @property {boolean} alphaToCoverage Enable alpha to coverage. See {@link Material#alphaToCoverage}.
31+
* @property {boolean} opacityFadesSpecular Enable specular fade. See {@link Material#opacityFadesSpecular}.
32+
* @property {float} ambientSH If ambient spherical harmonics are used. Ambient SH replace prefiltered cubemap
33+
* ambient on certain platform (mostly Android) for performance reasons.
34+
* @property {boolean} useSpecular If any specular or reflections are needed at all.
35+
* @property {boolean} fixSeams If cubemaps require seam fixing (see {@link Texture#options.fixCubemapSeams}).
36+
* @property {string} forceFragmentPrecision Override fragment shader numeric precision. Can be "lowp", "mediump",
37+
* "highp" or null to use default.
38+
* @property {boolean} fastTbn Use slightly cheaper normal mapping code (skip tangent space normalization). Can look
39+
* buggy sometimes.
40+
* @property {boolean} useRefraction If refraction is used.
41+
* @property {number} skyboxIntensity If reflected skybox intensity should be modulated.
42+
* @property {boolean} useCubeMapRotation If cube map rotation is enabled.
43+
* @property {boolean} useInstancing If hardware instancing compatible shader should be generated. Transform is read
44+
* from per-instance {@link VertexBuffer} instead of shader's uniforms.
45+
* @property {boolean} useMorphPosition If morphing code should be generated to morph positions.
46+
* @property {boolean} useMorphNormal If morphing code should be generated to morph normals.
47+
* @property {string} reflectionSource One of "envAtlasHQ", "envAtlas", "cubeMap", "sphereMap".
48+
* @property {boolean} ambientSource One of "ambientSH", "envAtlas", "constant".
49+
*/
50+
class LitOptions {
51+
constructor() {
52+
this.hasTangents = false;
53+
this.chunks = [];
54+
55+
this._pass = 0;
56+
this.alphaTest = false;
57+
this.forceFragmentPrecision = false;
58+
this.blendType = BLEND_NONE;
59+
this.separateAmbient = false;
60+
this.screenSpace = false;
61+
this.skin = false;
62+
this.useInstancing = false;
63+
this.useMorphPosition = false;
64+
this.useMorphNormal = false;
65+
this.useMorphTextureBased = false;
66+
67+
this.nineSlicedMode = false;
68+
69+
this.clusteredLightingEnabled = true;
70+
71+
this.clusteredLightingCookiesEnabled = false;
72+
this.clusteredLightingShadowsEnabled = false;
73+
this.clusteredLightingShadowType = 0;
74+
this.clusteredLightingAreaLightsEnabled = false;
75+
76+
this.vertexColors = false;
77+
this.lightMapEnabled = false;
78+
this.useLightMapVertexColors = false;
79+
this.dirLightMapEnabled = false;
80+
this.heightMapEnabled = false;
81+
this.normalMapEnabled = false;
82+
this.clearCoatNormalMapEnabled = false;
83+
this.aoMapEnabled = false;
84+
this.useAoVertexColors = false;
85+
this.diffuseMapEnabled = false;
86+
87+
this.useAmbientTint = false;
88+
this.customFragmentShader = null;
89+
this.pixelSnap = false;
90+
91+
this.useClearCoatNormalMap = false;
92+
this.useDiffuseMap = false;
93+
this.useAoMap = false;
94+
95+
this.detailModes = 0;
96+
this.shadingModel = 0;
97+
this.ambientSH = false;
98+
this.fastTbn = false;
99+
this.twoSidedLighting = false;
100+
this.occludeSpecular = false;
101+
this.occludeSpecularFloat = false;
102+
103+
this.useMsdf = false;
104+
this.msdfTextAttribute = 0;
105+
106+
this.alphaToCoverage = false;
107+
this.opacityFadesSpecular = false;
108+
109+
this.cubeMapProjection = false;
110+
111+
this.occludeDirect = false;
112+
this.conserveEnergy = false;
113+
this.useSpecular = false;
114+
this.useSpecularityFactor = false;
115+
this.useSpecularColor = false;
116+
this.enableGGXSpecular = false;
117+
this.fresnelModel = 0;
118+
this.useRefraction = false;
119+
this.useClearCoat = false;
120+
this.useSheen = false;
121+
this.useIridescence = false;
122+
this.useMetalness = false;
123+
this.useDynamicRefraction = false;
124+
125+
this.fog = FOG_NONE;
126+
this.gamma = GAMMA_NONE;
127+
this.toneMap = -1;
128+
this.fixSeams = false;
129+
130+
this.reflectionSource = null;
131+
this.reflectionEncoding = null;
132+
this.ambientSource = 'constant';
133+
this.ambientEncoding = null;
134+
135+
// TODO: add a test for if non skybox cubemaps have rotation (when this is supported) - for now assume no non-skybox cubemap rotation
136+
this.skyboxIntensity = 1.0;
137+
this.useCubeMapRotation = false;
138+
139+
this.lightMapWithoutAmbient = false;
140+
141+
this.lights = [];
142+
this.noShadow = false;
143+
this.lightMaskDynamic = 0x0;
144+
}
145+
146+
set pass(p) {
147+
Debug.warn(`pc.LitOptions#pass should be set by its parent pc.StandardMaterialOptions, setting it directly has no effect.`);
148+
}
149+
150+
get pass() {
151+
return this._pass;
152+
}
153+
}
154+
155+
export { LitOptions };

src/scene/materials/standard-material-options-builder.js

+7-9
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,19 @@ class StandardMaterialOptionsBuilder {
4444

4545
// Minimal options for Depth and Shadow passes
4646
updateMinRef(options, scene, stdMat, objDefs, staticLightList, pass, sortedLights) {
47-
options.litOptions = {};
4847
this._updateSharedOptions(options, scene, stdMat, objDefs, pass);
4948
this._updateMinOptions(options, stdMat);
5049
this._updateUVOptions(options, stdMat, objDefs, true);
5150
options.litOptions.chunks = options.chunks;
5251
}
5352

5453
updateRef(options, scene, stdMat, objDefs, staticLightList, pass, sortedLights) {
55-
options.litOptions = {};
5654
this._updateSharedOptions(options, scene, stdMat, objDefs, pass);
5755
this._updateEnvOptions(options, stdMat, scene);
5856
this._updateMaterialOptions(options, stdMat);
5957
if (pass === SHADER_FORWARDHDR) {
60-
if (options.gamma) options.gamma = GAMMA_SRGBHDR;
61-
options.toneMap = TONEMAP_LINEAR;
58+
if (options.litOptions.gamma) options.litOptions.gamma = GAMMA_SRGBHDR;
59+
options.litOptions.toneMap = TONEMAP_LINEAR;
6260
}
6361
options.litOptions.hasTangents = objDefs && ((objDefs & SHADERDEF_TANGENTS) !== 0);
6462
this._updateLightOptions(options, scene, stdMat, objDefs, sortedLights, staticLightList);
@@ -70,7 +68,7 @@ class StandardMaterialOptionsBuilder {
7068
options.forceUv1 = stdMat.forceUv1;
7169
options.chunks = stdMat.chunks || '';
7270

73-
options.litOptions.pass = pass;
71+
options.pass = pass;
7472
options.litOptions.alphaTest = stdMat.alphaTest > 0;
7573
options.litOptions.forceFragmentPrecision = stdMat.forceFragmentPrecision || '';
7674
options.litOptions.blendType = stdMat.blendType;
@@ -120,13 +118,13 @@ class StandardMaterialOptionsBuilder {
120118

121119
// All texture related lit options
122120
options.litOptions.lightMapEnabled = options.lightMap;
123-
options.litOptions.lightMapVertexColors = options.lightVertexColors;
121+
options.litOptions.useLightMapVertexColors = options.lightVertexColors;
124122
options.litOptions.dirLightMapEnabled = options.dirLightMap;
125123
options.litOptions.heightMapEnabled = options.heightMap;
126124
options.litOptions.normalMapEnabled = options.normalMap;
127125
options.litOptions.clearCoatNormalMapEnabled = options.clearCoatNormalMap;
128126
options.litOptions.aoMapEnabled = options.aoMap;
129-
options.litOptions.aoVertexColors = options.aoVertexColors;
127+
options.litOptions.useAoVertexColors = options.aoVertexColors;
130128
options.litOptions.diffuseMapEnabled = options.diffuseMap;
131129
}
132130

@@ -248,7 +246,7 @@ class StandardMaterialOptionsBuilder {
248246
options.sheenGlossinessTint = 1;
249247

250248
// LIT OPTIONS
251-
options.litOptions.ambientTint = options.ambientTint;
249+
options.litOptions.useAmbientTint = options.ambientTint;
252250
options.litOptions.customFragmentShader = stdMat.customFragmentShader;
253251
options.litOptions.pixelSnap = stdMat.pixelSnap;
254252

@@ -279,7 +277,7 @@ class StandardMaterialOptionsBuilder {
279277
options.litOptions.useSpecularColor = useSpecularColor;
280278
options.litOptions.enableGGXSpecular = stdMat.enableGGXSpecular;
281279
options.litOptions.fresnelModel = stdMat.fresnelModel;
282-
options.litOptions.useRefraction = (stdMat.refraction || !!stdMat.refractionMap) && (stdMat.useDynamicRefraction || !!options.reflectionSource);
280+
options.litOptions.useRefraction = (stdMat.refraction || !!stdMat.refractionMap) && (stdMat.useDynamicRefraction || !!options.litOptions.reflectionSource);
283281
options.litOptions.useClearCoat = !!stdMat.clearCoat;
284282
options.litOptions.useSheen = stdMat.useSheen;
285283
options.litOptions.useIridescence = stdMat.useIridescence && stdMat.iridescence !== 0.0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { LitOptions } from "./lit-options.js";
2+
3+
/**
4+
* The standard material options define a set of options used to control the shader frontend shader generation,
5+
* such as textures, tints and multipliers.
6+
*
7+
* @property {number} pass Value of {@link Layer#shaderPass} of the Layer being rendered. Must be set to the
8+
* same in {@link LitOptions#pass}.
9+
* @property {boolean} forceUv1 If UV1 (second set of texture coordinates) is required in the shader. Will be
10+
* declared as "vUv1" and passed to the fragment shader.
11+
* @property {boolean} ambientTint The value of {@link StandardMaterial#ambientTint}.
12+
* @property {boolean} diffuseTint Defines if {@link StandardMaterial#diffuse} constant should affect diffuse color.
13+
* @property {boolean} specularTint Defines if {@link StandardMaterial#specular} constant should affect specular
14+
* color.
15+
* @property {boolean} metalnessTint Defines if {@link StandardMaterial#metalness} constant should affect metalness
16+
* value.
17+
* @property {boolean} glossTint Defines if {@link StandardMaterial#shininess} constant should affect glossiness
18+
* value.
19+
* @property {boolean} emissiveTint Defines if {@link StandardMaterial#emissive} constant should affect emission
20+
* value.
21+
* @property {boolean} opacityTint Defines if {@link StandardMaterial#opacity} constant should affect opacity value.
22+
* @property {boolean} packedNormal If normal map contains X in RGB, Y in Alpha, and Z must be reconstructed.
23+
*/
24+
class StandardMaterialOptions {
25+
constructor() {
26+
this.chunks = [];
27+
this._pass = 0;
28+
this.forceUv1 = false;
29+
this.ambientTint = false;
30+
this.diffuseTint = false;
31+
this.specularTint = false;
32+
this.metalnessTint = false;
33+
this.glossTint = false;
34+
this.emissiveTint = false;
35+
this.opacityTint = false;
36+
this.emissiveEncoding = 'linear';
37+
this.lightMapEncoding = 'linear';
38+
this.packedNormal = false;
39+
40+
this.litOptions = new LitOptions();
41+
}
42+
43+
set pass(p) {
44+
this._pass = p;
45+
this.litOptions._pass = p;
46+
}
47+
48+
get pass() {
49+
return this._pass;
50+
}
51+
}
52+
53+
export { StandardMaterialOptions };

0 commit comments

Comments
 (0)