@gnsx/three 0.186.1 → 0.186.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/three.webgpu.js +610 -17
- package/build/three.webgpu.nodes.js +610 -17
- package/examples/jsm/inspector/Inspector.js +60 -1
- package/examples/jsm/inspector/tabs/Memory.js +60 -1
- package/examples/jsm/inspector/tabs/Settings.js +36 -0
- package/examples/jsm/inspector/ui/Profiler.js +6 -0
- package/examples/jsm/inspector/ui/Style.js +53 -1
- package/examples/jsm/inspector/ui/utils.js +121 -0
- package/package.json +1 -1
- package/src/materials/nodes/NodeMaterial.js +30 -0
- package/src/nodes/core/NodeBuilder.js +74 -0
- package/src/nodes/display/ComplexityDebug.js +278 -0
- package/src/nodes/lighting/LightsNode.js +71 -2
- package/src/nodes/lighting/PointLightNode.js +4 -1
- package/src/nodes/lighting/RectAreaLightNode.js +14 -0
- package/src/nodes/lighting/SpotLightNode.js +10 -2
- package/src/renderers/common/Background.js +17 -1
- package/src/renderers/common/RenderObject.js +5 -0
- package/src/renderers/common/Renderer.js +24 -1
- package/src/renderers/common/nodes/NodeManager.js +22 -7
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +8 -0
- package/src/renderers/webgl-fallback/utils/WebGLState.js +19 -3
- package/src/renderers/webgpu/WebGPUBackend.js +14 -2
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +16 -0
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +20 -0
- package/build/three.cjs +0 -17
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// WITH_GENESYS
|
|
2
|
+
// Shader and lighting complexity debug views. Costs are a material proxy, not ISA instruction counts.
|
|
3
|
+
// !WITH_GENESYS
|
|
4
|
+
|
|
5
|
+
import Node from '../core/Node.js';
|
|
6
|
+
import { float, vec3, vec4, If, Fn } from '../tsl/TSLCore.js';
|
|
7
|
+
import { fract, min, mix } from '../math/MathNode.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shaded output. No complexity debug view.
|
|
11
|
+
*
|
|
12
|
+
* @type {string}
|
|
13
|
+
*/
|
|
14
|
+
export const DEBUG_VIEW_NONE = 'none';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Material-cost heatmap. Overlapping draws accumulate, then a fullscreen pass applies the ramp.
|
|
18
|
+
*
|
|
19
|
+
* @type {string}
|
|
20
|
+
*/
|
|
21
|
+
export const DEBUG_VIEW_SHADER_COMPLEXITY = 'shaderComplexity';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Direct-light count heatmap. The visible surface wins.
|
|
25
|
+
*
|
|
26
|
+
* @type {string}
|
|
27
|
+
*/
|
|
28
|
+
export const DEBUG_VIEW_LIGHTING_COMPLEXITY = 'lightingComplexity';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Proxy budget that fills the shader-complexity ramp.
|
|
32
|
+
* A plain lit material stays in the green stops. Transmission plus several
|
|
33
|
+
* texture samples climbs toward red.
|
|
34
|
+
*
|
|
35
|
+
* @type {number}
|
|
36
|
+
*/
|
|
37
|
+
export const DEFAULT_SHADER_COMPLEXITY_BUDGET = 800;
|
|
38
|
+
|
|
39
|
+
/** @type {number} */
|
|
40
|
+
export const SHADER_COMPLEXITY_BASE_UNLIT = 20;
|
|
41
|
+
|
|
42
|
+
/** @type {number} */
|
|
43
|
+
export const SHADER_COMPLEXITY_BASE_LIT = 40;
|
|
44
|
+
|
|
45
|
+
/** @type {number} */
|
|
46
|
+
export const SHADER_COMPLEXITY_TEXTURE_COST = 16;
|
|
47
|
+
|
|
48
|
+
/** @type {number} */
|
|
49
|
+
export const SHADER_COMPLEXITY_FEATURE_COST = 30;
|
|
50
|
+
|
|
51
|
+
/** @type {number} */
|
|
52
|
+
export const SHADER_COMPLEXITY_TRANSMISSION_COST = 60;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Attenuation above this counts as a light that shades the pixel.
|
|
56
|
+
*
|
|
57
|
+
* @type {number}
|
|
58
|
+
*/
|
|
59
|
+
export const LIGHTING_COMPLEXITY_EPSILON = 0.001;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Added on top of 1 when a received light casts a shadow.
|
|
63
|
+
* Applied even where the shadow map is black.
|
|
64
|
+
*
|
|
65
|
+
* @type {number}
|
|
66
|
+
*/
|
|
67
|
+
export const LIGHTING_COMPLEXITY_SHADOW_WEIGHT = 0.5;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Unreal `ShaderComplexityColors` from `BaseEngine.ini`.
|
|
71
|
+
*
|
|
72
|
+
* @type {Array<Array<number>>}
|
|
73
|
+
*/
|
|
74
|
+
const SHADER_COMPLEXITY_COLORS = [
|
|
75
|
+
[ 0.0, 1.0, 0.127 ],
|
|
76
|
+
[ 0.0, 1.0, 0.0 ],
|
|
77
|
+
[ 0.046, 0.52, 0.0 ],
|
|
78
|
+
[ 0.215, 0.215, 0.0 ],
|
|
79
|
+
[ 0.52, 0.046, 0.0 ],
|
|
80
|
+
[ 0.7, 0.0, 0.0 ],
|
|
81
|
+
[ 1.0, 0.0, 0.0 ],
|
|
82
|
+
[ 1.0, 0.0, 0.5 ],
|
|
83
|
+
[ 1.0, 0.9, 0.9 ]
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Unreal `LightComplexityColors` from `BaseEngine.ini`.
|
|
88
|
+
*
|
|
89
|
+
* @type {Array<Array<number>>}
|
|
90
|
+
*/
|
|
91
|
+
const LIGHT_COMPLEXITY_COLORS = [
|
|
92
|
+
[ 0.0, 0.0, 0.0 ],
|
|
93
|
+
[ 0.0, 0.0, 0.4 ],
|
|
94
|
+
[ 0.0, 0.3, 1.0 ],
|
|
95
|
+
[ 0.0, 0.7, 0.4 ],
|
|
96
|
+
[ 0.0, 1.0, 0.0 ],
|
|
97
|
+
[ 0.8, 0.8, 0.0 ],
|
|
98
|
+
[ 1.0, 0.3, 0.0 ],
|
|
99
|
+
[ 0.7, 0.0, 0.0 ],
|
|
100
|
+
[ 0.5, 0.0, 0.5 ],
|
|
101
|
+
[ 0.7, 0.3, 0.7 ],
|
|
102
|
+
[ 1.0, 0.9, 0.9 ]
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
const rgb = ( colors, index ) => vec3( colors[ index ][ 0 ], colors[ index ][ 1 ], colors[ index ][ 2 ] );
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Linear sample of a fixed RGB ramp. `cost` is in steps, and one step is one light.
|
|
109
|
+
*
|
|
110
|
+
* @param {Node<float>} cost - Complexity in ramp steps.
|
|
111
|
+
* @param {Array<Array<number>>} colors - Ramp stops.
|
|
112
|
+
* @return {Node<vec3>} The ramp color.
|
|
113
|
+
*/
|
|
114
|
+
const colorizeLinear = ( cost, colors ) => {
|
|
115
|
+
|
|
116
|
+
const steps = colors.length - 1;
|
|
117
|
+
const expanded = cost.div( steps ).clamp( 0, 0.999 ).mul( steps );
|
|
118
|
+
const index = expanded.floor();
|
|
119
|
+
const frac = fract( expanded );
|
|
120
|
+
|
|
121
|
+
let color = rgb( colors, 0 );
|
|
122
|
+
|
|
123
|
+
for ( let i = 0; i < steps; i ++ ) {
|
|
124
|
+
|
|
125
|
+
const sample = mix( rgb( colors, i ), rgb( colors, i + 1 ), frac );
|
|
126
|
+
|
|
127
|
+
color = index.greaterThanEqual( float( i ) ).and( index.lessThan( float( i + 1 ) ) ).select( sample, color );
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return color;
|
|
132
|
+
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Maps a direct-light cost through Unreal's light-complexity ramp.
|
|
137
|
+
* Ten lights saturate at white.
|
|
138
|
+
*
|
|
139
|
+
* @param {Node<float>} cost - Accumulated light weight.
|
|
140
|
+
* @return {Node<vec3>} The ramp color.
|
|
141
|
+
*/
|
|
142
|
+
export const colorizeLightComplexity = ( cost ) => colorizeLinear( cost, LIGHT_COMPLEXITY_COLORS );
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Unreal's nonlinear shader-complexity ramp (`ColorizeComplexity`).
|
|
146
|
+
* The first third of the normalized cost spreads across the first seven stops.
|
|
147
|
+
*
|
|
148
|
+
* @param {Node<float>} complexity - Accumulated cost divided by the budget.
|
|
149
|
+
* @return {Node<vec3>} The ramp color.
|
|
150
|
+
*/
|
|
151
|
+
export const colorizeShaderComplexity = /*@__PURE__*/ Fn( ( [ complexity ] ) => {
|
|
152
|
+
|
|
153
|
+
const c = complexity.clamp( 0, 0.999 );
|
|
154
|
+
const expanded = min( float( SHADER_COMPLEXITY_COLORS.length - 2 ), c.mul( 18 ) );
|
|
155
|
+
const color = vec3( 0 ).toVar();
|
|
156
|
+
const frac = fract( expanded );
|
|
157
|
+
|
|
158
|
+
If( expanded.lessThan( 1 ), () => {
|
|
159
|
+
|
|
160
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 0 ), rgb( SHADER_COMPLEXITY_COLORS, 1 ), frac ) );
|
|
161
|
+
|
|
162
|
+
} ).ElseIf( expanded.lessThan( 2 ), () => {
|
|
163
|
+
|
|
164
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 1 ), rgb( SHADER_COMPLEXITY_COLORS, 2 ), frac ) );
|
|
165
|
+
|
|
166
|
+
} ).ElseIf( expanded.lessThan( 3 ), () => {
|
|
167
|
+
|
|
168
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 2 ), rgb( SHADER_COMPLEXITY_COLORS, 3 ), frac ) );
|
|
169
|
+
|
|
170
|
+
} ).ElseIf( expanded.lessThan( 4 ), () => {
|
|
171
|
+
|
|
172
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 3 ), rgb( SHADER_COMPLEXITY_COLORS, 4 ), frac ) );
|
|
173
|
+
|
|
174
|
+
} ).ElseIf( expanded.lessThan( 5 ), () => {
|
|
175
|
+
|
|
176
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 4 ), rgb( SHADER_COMPLEXITY_COLORS, 5 ), frac ) );
|
|
177
|
+
|
|
178
|
+
} ).ElseIf( expanded.lessThan( 6 ), () => {
|
|
179
|
+
|
|
180
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 5 ), rgb( SHADER_COMPLEXITY_COLORS, 6 ), frac ) );
|
|
181
|
+
|
|
182
|
+
} ).Else( () => {
|
|
183
|
+
|
|
184
|
+
// Nine stops, so the upper range uses the `count > 8` scale of 3.
|
|
185
|
+
const upper = c.sub( 0.33333333 ).mul( 3.0 );
|
|
186
|
+
const upperFrac = fract( upper );
|
|
187
|
+
|
|
188
|
+
If( upper.lessThanEqual( 1 ), () => {
|
|
189
|
+
|
|
190
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 6 ), rgb( SHADER_COMPLEXITY_COLORS, 7 ), upperFrac ) );
|
|
191
|
+
|
|
192
|
+
} ).Else( () => {
|
|
193
|
+
|
|
194
|
+
color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 7 ), rgb( SHADER_COMPLEXITY_COLORS, 8 ), upperFrac ) );
|
|
195
|
+
|
|
196
|
+
} );
|
|
197
|
+
|
|
198
|
+
} );
|
|
199
|
+
|
|
200
|
+
return color;
|
|
201
|
+
|
|
202
|
+
} );
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Reads the builder's shader-complexity proxy at code-generation time,
|
|
206
|
+
* after the real material graph has been generated and texture samples counted.
|
|
207
|
+
*
|
|
208
|
+
* @augments Node
|
|
209
|
+
*/
|
|
210
|
+
class ShaderComplexityRatioNode extends Node {
|
|
211
|
+
|
|
212
|
+
static get type() {
|
|
213
|
+
|
|
214
|
+
return 'ShaderComplexityRatioNode';
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
constructor() {
|
|
219
|
+
|
|
220
|
+
super( 'float' );
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
generate( builder ) {
|
|
225
|
+
|
|
226
|
+
const budget = builder.renderer.debug.shaderComplexityBudget;
|
|
227
|
+
const safeBudget = ( typeof budget === 'number' && budget > 0 ) ? budget : 1;
|
|
228
|
+
const ratio = builder.getShaderComplexityCost() / safeBudget;
|
|
229
|
+
|
|
230
|
+
return ratio.toFixed( 6 );
|
|
231
|
+
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Static fragment proxy for a material. Texture samples are counted later, during generation.
|
|
238
|
+
*
|
|
239
|
+
* @param {NodeMaterial} material - The material being built.
|
|
240
|
+
* @return {number} The base cost, excluding texture samples.
|
|
241
|
+
*/
|
|
242
|
+
export function getShaderComplexityBase( material ) {
|
|
243
|
+
|
|
244
|
+
let cost = material.lights === true ? SHADER_COMPLEXITY_BASE_LIT : SHADER_COMPLEXITY_BASE_UNLIT;
|
|
245
|
+
|
|
246
|
+
if ( material.useClearcoat === true ) cost += SHADER_COMPLEXITY_FEATURE_COST;
|
|
247
|
+
|
|
248
|
+
if ( material.useSheen === true ) cost += SHADER_COMPLEXITY_FEATURE_COST;
|
|
249
|
+
|
|
250
|
+
if ( material.useIridescence === true ) cost += SHADER_COMPLEXITY_FEATURE_COST;
|
|
251
|
+
|
|
252
|
+
if ( material.useAnisotropy === true ) cost += SHADER_COMPLEXITY_FEATURE_COST;
|
|
253
|
+
|
|
254
|
+
if ( material.useTransmission === true ) cost += SHADER_COMPLEXITY_TRANSMISSION_COST;
|
|
255
|
+
|
|
256
|
+
return cost;
|
|
257
|
+
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Replaces the shaded color with `vec4(cost / budget, 0, 0, 1)`.
|
|
262
|
+
* The real graph is still generated so texture samples are counted first.
|
|
263
|
+
*
|
|
264
|
+
* @param {Node} resultNode - The material's shaded output.
|
|
265
|
+
* @return {Node<vec4>} The complexity ratio in the red channel.
|
|
266
|
+
*/
|
|
267
|
+
export function shaderComplexityOutput( resultNode ) {
|
|
268
|
+
|
|
269
|
+
// Generate the shaded graph first so texture samples are counted, then
|
|
270
|
+
// replace the color. A bypass of a value node emits a bare expression
|
|
271
|
+
// statement, which WGSL rejects.
|
|
272
|
+
const shaded = vec4( resultNode ).toVar();
|
|
273
|
+
|
|
274
|
+
const ratio = new ShaderComplexityRatioNode();
|
|
275
|
+
|
|
276
|
+
return vec4( ratio, 0, 0, 1 ).add( shaded.mul( 0 ) );
|
|
277
|
+
|
|
278
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import Node from '../core/Node.js';
|
|
2
|
-
import { property, vec3 } from '../tsl/TSLBase.js';
|
|
2
|
+
import { float, property, vec3 } from '../tsl/TSLBase.js';
|
|
3
3
|
import { hashArray } from '../core/NodeUtils.js';
|
|
4
4
|
import { warn } from '../../utils.js';
|
|
5
5
|
// WITH_GENESYS
|
|
6
|
+
import { colorizeLightComplexity, DEBUG_VIEW_LIGHTING_COMPLEXITY, LIGHTING_COMPLEXITY_EPSILON, LIGHTING_COMPLEXITY_SHADOW_WEIGHT } from '../display/ComplexityDebug.js';
|
|
7
|
+
// !WITH_GENESYS
|
|
8
|
+
// WITH_GENESYS
|
|
6
9
|
import LightProbeGridNode from './LightProbeGridNode.js';
|
|
7
10
|
// !WITH_GENESYS
|
|
8
11
|
|
|
@@ -27,6 +30,10 @@ const totalSpecular = property( 'vec3', 'totalSpecular' );
|
|
|
27
30
|
*/
|
|
28
31
|
const outgoingLight = property( 'vec3', 'outgoingLight' );
|
|
29
32
|
|
|
33
|
+
// WITH_GENESYS
|
|
34
|
+
const lightingComplexity = property( 'float', 'lightingComplexity' );
|
|
35
|
+
// !WITH_GENESYS
|
|
36
|
+
|
|
30
37
|
/**
|
|
31
38
|
* Sorts an array of lights in ascending order by their IDs.
|
|
32
39
|
*
|
|
@@ -380,6 +387,10 @@ class LightsNode extends Node {
|
|
|
380
387
|
reflectedLight
|
|
381
388
|
}, builder );
|
|
382
389
|
|
|
390
|
+
// WITH_GENESYS
|
|
391
|
+
this._addLightingComplexity( builder, lightNode, lightData );
|
|
392
|
+
// !WITH_GENESYS
|
|
393
|
+
|
|
383
394
|
}
|
|
384
395
|
|
|
385
396
|
/**
|
|
@@ -399,7 +410,39 @@ class LightsNode extends Node {
|
|
|
399
410
|
reflectedLight
|
|
400
411
|
}, builder );
|
|
401
412
|
|
|
413
|
+
// WITH_GENESYS
|
|
414
|
+
this._addLightingComplexity( builder, lightNode, lightData );
|
|
415
|
+
// !WITH_GENESYS
|
|
416
|
+
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// WITH_GENESYS
|
|
420
|
+
/**
|
|
421
|
+
* Adds this direct light's weight to the lighting-complexity accumulator.
|
|
422
|
+
* Point, spot, and rect-area lights count only where attenuation is in range.
|
|
423
|
+
* Directional lights have no falloff, so they always count. Shadow-casting
|
|
424
|
+
* lights add extra weight even where the shadow map is black.
|
|
425
|
+
*
|
|
426
|
+
* @private
|
|
427
|
+
* @param {NodeBuilder} builder - The current node builder.
|
|
428
|
+
* @param {LightingNode} lightNode - The light node being shaded.
|
|
429
|
+
* @param {Object} lightData - Direct light terms, including an optional attenuation node.
|
|
430
|
+
*/
|
|
431
|
+
_addLightingComplexity( builder, lightNode, lightData ) {
|
|
432
|
+
|
|
433
|
+
if ( builder.renderer.debug.view !== DEBUG_VIEW_LIGHTING_COMPLEXITY ) return;
|
|
434
|
+
|
|
435
|
+
if ( builder.material && builder.material.isShadowPassMaterial === true ) return;
|
|
436
|
+
|
|
437
|
+
const attenuation = lightData.attenuation !== undefined ? lightData.attenuation : float( 1 );
|
|
438
|
+
const light = lightNode.light;
|
|
439
|
+
const castsShadow = light !== undefined && light !== null && light.castShadow === true && builder.object.receiveShadow === true;
|
|
440
|
+
const weight = castsShadow ? float( 1 + LIGHTING_COMPLEXITY_SHADOW_WEIGHT ) : float( 1 );
|
|
441
|
+
|
|
442
|
+
lightingComplexity.addAssign( attenuation.greaterThan( LIGHTING_COMPLEXITY_EPSILON ).select( weight, float( 0 ) ) );
|
|
443
|
+
|
|
402
444
|
}
|
|
445
|
+
// !WITH_GENESYS
|
|
403
446
|
|
|
404
447
|
/**
|
|
405
448
|
* Setups the internal lights by building all respective
|
|
@@ -463,6 +506,14 @@ class LightsNode extends Node {
|
|
|
463
506
|
|
|
464
507
|
properties.nodes = stack.nodes;
|
|
465
508
|
|
|
509
|
+
// WITH_GENESYS
|
|
510
|
+
if ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_COMPLEXITY && ( builder.material === null || builder.material.isShadowPassMaterial !== true ) ) {
|
|
511
|
+
|
|
512
|
+
lightingComplexity.assign( 0 );
|
|
513
|
+
|
|
514
|
+
}
|
|
515
|
+
// !WITH_GENESYS
|
|
516
|
+
|
|
466
517
|
lightingModel.start( builder );
|
|
467
518
|
|
|
468
519
|
const { backdrop, backdropAlpha } = context;
|
|
@@ -487,10 +538,28 @@ class LightsNode extends Node {
|
|
|
487
538
|
totalDiffuseNode.assign( totalDiffuse );
|
|
488
539
|
totalSpecularNode.assign( directSpecular.add( indirectSpecular ) );
|
|
489
540
|
|
|
490
|
-
|
|
541
|
+
// WITH_GENESYS
|
|
542
|
+
const lightingComplexityView = builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_COMPLEXITY && ( builder.material === null || builder.material.isShadowPassMaterial !== true );
|
|
543
|
+
|
|
544
|
+
if ( lightingComplexityView !== true ) {
|
|
545
|
+
|
|
546
|
+
outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) );
|
|
547
|
+
|
|
548
|
+
}
|
|
549
|
+
// !WITH_GENESYS
|
|
550
|
+
// outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) );
|
|
491
551
|
|
|
492
552
|
lightingModel.finish( builder );
|
|
493
553
|
|
|
554
|
+
// WITH_GENESYS
|
|
555
|
+
// After finish(), so clearcoat and sheen cannot draw over the heatmap.
|
|
556
|
+
if ( lightingComplexityView === true ) {
|
|
557
|
+
|
|
558
|
+
outgoingLightNode.assign( colorizeLightComplexity( lightingComplexity ) );
|
|
559
|
+
|
|
560
|
+
}
|
|
561
|
+
// !WITH_GENESYS
|
|
562
|
+
|
|
494
563
|
outgoingLightNode = outgoingLightNode.bypass( builder.removeStack() );
|
|
495
564
|
|
|
496
565
|
} else {
|
|
@@ -17,7 +17,10 @@ export const directPointLight = ( { color, lightVector, cutoffDistance, decayExp
|
|
|
17
17
|
|
|
18
18
|
const lightColor = color.mul( attenuation );
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// WITH_GENESYS
|
|
21
|
+
return { lightDirection, lightColor, attenuation };
|
|
22
|
+
// !WITH_GENESYS
|
|
23
|
+
// return { lightDirection, lightColor };
|
|
21
24
|
|
|
22
25
|
};
|
|
23
26
|
|
|
@@ -88,6 +88,20 @@ class RectAreaLightNode extends AnalyticLightNode {
|
|
|
88
88
|
|
|
89
89
|
setupDirectRectArea( builder ) {
|
|
90
90
|
|
|
91
|
+
// WITH_GENESYS
|
|
92
|
+
// LTC lookups are part of the light loop, not the material's shader cost.
|
|
93
|
+
if ( _ltcLib !== null ) {
|
|
94
|
+
|
|
95
|
+
_ltcLib.LTC_FLOAT_1.isRectAreaLTC = true;
|
|
96
|
+
_ltcLib.LTC_FLOAT_2.isRectAreaLTC = true;
|
|
97
|
+
|
|
98
|
+
if ( _ltcLib.LTC_HALF_1 ) _ltcLib.LTC_HALF_1.isRectAreaLTC = true;
|
|
99
|
+
|
|
100
|
+
if ( _ltcLib.LTC_HALF_2 ) _ltcLib.LTC_HALF_2.isRectAreaLTC = true;
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
// !WITH_GENESYS
|
|
104
|
+
|
|
91
105
|
let ltc_1, ltc_2;
|
|
92
106
|
|
|
93
107
|
if ( builder.isAvailable( 'float32Filterable' ) ) {
|
|
@@ -135,7 +135,12 @@ class SpotLightNode extends AnalyticLightNode {
|
|
|
135
135
|
decayExponent: decayExponentNode
|
|
136
136
|
} );
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
// WITH_GENESYS
|
|
139
|
+
const attenuation = spotAttenuation.mul( lightAttenuation );
|
|
140
|
+
|
|
141
|
+
let lightColor = colorNode.mul( attenuation );
|
|
142
|
+
// !WITH_GENESYS
|
|
143
|
+
// let lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
|
|
139
144
|
|
|
140
145
|
let projected, lightCoord;
|
|
141
146
|
|
|
@@ -159,7 +164,10 @@ class SpotLightNode extends AnalyticLightNode {
|
|
|
159
164
|
|
|
160
165
|
}
|
|
161
166
|
|
|
162
|
-
|
|
167
|
+
// WITH_GENESYS
|
|
168
|
+
return { lightColor, lightDirection, attenuation };
|
|
169
|
+
// !WITH_GENESYS
|
|
170
|
+
// return { lightColor, lightDirection };
|
|
163
171
|
|
|
164
172
|
}
|
|
165
173
|
|
|
@@ -191,7 +191,15 @@ class Background extends DataMap {
|
|
|
191
191
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
|
|
194
|
+
// WITH_GENESYS
|
|
195
|
+
// The background is depth-tested off, so additive shader complexity would add it to every pixel.
|
|
196
|
+
if ( renderer.debug.view !== 'shaderComplexity' ) {
|
|
197
|
+
|
|
198
|
+
renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
|
|
199
|
+
|
|
200
|
+
}
|
|
201
|
+
// !WITH_GENESYS
|
|
202
|
+
// renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
|
|
195
203
|
|
|
196
204
|
} else {
|
|
197
205
|
|
|
@@ -215,6 +223,14 @@ class Background extends DataMap {
|
|
|
215
223
|
|
|
216
224
|
//
|
|
217
225
|
|
|
226
|
+
// WITH_GENESYS
|
|
227
|
+
if ( renderer.debug.view === 'shaderComplexity' ) {
|
|
228
|
+
|
|
229
|
+
_clearColor.set( 0, 0, 0, 1 );
|
|
230
|
+
|
|
231
|
+
}
|
|
232
|
+
// !WITH_GENESYS
|
|
233
|
+
|
|
218
234
|
if ( renderer.autoClear === true || forceClear === true ) {
|
|
219
235
|
|
|
220
236
|
const clearColorValue = renderContext.clearColorValue;
|
|
@@ -950,6 +950,11 @@ class RenderObject {
|
|
|
950
950
|
|
|
951
951
|
cacheKey = hash( cacheKey, this.renderer.contextNode.id, this.renderer.contextNode.version );
|
|
952
952
|
|
|
953
|
+
// WITH_GENESYS
|
|
954
|
+
// hash() xors each argument as a number, so a view name has to be hashed first.
|
|
955
|
+
cacheKey = hash( cacheKey, hashString( this.renderer.debug.view ), this.renderer.debug.shaderComplexityBudget );
|
|
956
|
+
// !WITH_GENESYS
|
|
957
|
+
|
|
953
958
|
return cacheKey;
|
|
954
959
|
|
|
955
960
|
}
|
|
@@ -37,6 +37,7 @@ import { float, vec3, vec4, Fn } from '../../nodes/tsl/TSLCore.js';
|
|
|
37
37
|
import { detachRendererReference } from '../../nodes/accessors/RendererReferenceNode.js';
|
|
38
38
|
import { toneMappingExposure } from '../../nodes/display/ToneMappingNode.js';
|
|
39
39
|
import { ProfilerService } from '../../profiler/ProfilerService.js';
|
|
40
|
+
import { DEBUG_VIEW_LIGHTING_COMPLEXITY, DEBUG_VIEW_NONE, DEBUG_VIEW_SHADER_COMPLEXITY, DEFAULT_SHADER_COMPLEXITY_BUDGET } from '../../nodes/display/ComplexityDebug.js';
|
|
40
41
|
// !WITH_GENESYS
|
|
41
42
|
import { reference } from '../../nodes/accessors/ReferenceNode.js';
|
|
42
43
|
import { highpModelNormalViewMatrix, highpModelViewMatrix } from '../../nodes/accessors/ModelNode.js';
|
|
@@ -743,6 +744,8 @@ class Renderer {
|
|
|
743
744
|
* @property {?Function} onNodeBuilderCreated - A callback function that is executed after a node builder has been created and before it is built.
|
|
744
745
|
* @property {?Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now.
|
|
745
746
|
* @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object.
|
|
747
|
+
* @property {string} view - Debug view. `shaderComplexity` and `lightingComplexity` replace the shaded color with a heatmap.
|
|
748
|
+
* @property {number} shaderComplexityBudget - Proxy budget that fills the shader-complexity ramp.
|
|
746
749
|
*/
|
|
747
750
|
|
|
748
751
|
/**
|
|
@@ -757,6 +760,10 @@ class Renderer {
|
|
|
757
760
|
},
|
|
758
761
|
onNodeBuilderCreated: null,
|
|
759
762
|
onShaderError: null,
|
|
763
|
+
// WITH_GENESYS
|
|
764
|
+
view: DEBUG_VIEW_NONE,
|
|
765
|
+
shaderComplexityBudget: DEFAULT_SHADER_COMPLEXITY_BUDGET,
|
|
766
|
+
// !WITH_GENESYS
|
|
760
767
|
getShaderAsync: async ( scene, camera, object ) => {
|
|
761
768
|
|
|
762
769
|
await this.compileAsync( object, camera, scene );
|
|
@@ -2691,7 +2698,13 @@ class Renderer {
|
|
|
2691
2698
|
const useToneMapping = this.currentToneMapping !== NoToneMapping;
|
|
2692
2699
|
const useColorSpace = this.currentColorSpace !== ColorManagement.workingColorSpace;
|
|
2693
2700
|
|
|
2694
|
-
|
|
2701
|
+
// WITH_GENESYS
|
|
2702
|
+
// Shader complexity writes a scalar into an intermediate target, then the output pass colorizes it.
|
|
2703
|
+
const shaderComplexity = this.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY;
|
|
2704
|
+
|
|
2705
|
+
return useToneMapping || useColorSpace || shaderComplexity;
|
|
2706
|
+
// !WITH_GENESYS
|
|
2707
|
+
// return useToneMapping || useColorSpace;
|
|
2695
2708
|
|
|
2696
2709
|
}
|
|
2697
2710
|
|
|
@@ -2742,6 +2755,16 @@ class Renderer {
|
|
|
2742
2755
|
*/
|
|
2743
2756
|
get currentToneMapping() {
|
|
2744
2757
|
|
|
2758
|
+
// WITH_GENESYS
|
|
2759
|
+
const view = this.debug.view;
|
|
2760
|
+
|
|
2761
|
+
if ( view === DEBUG_VIEW_SHADER_COMPLEXITY || view === DEBUG_VIEW_LIGHTING_COMPLEXITY ) {
|
|
2762
|
+
|
|
2763
|
+
return NoToneMapping;
|
|
2764
|
+
|
|
2765
|
+
}
|
|
2766
|
+
// !WITH_GENESYS
|
|
2767
|
+
|
|
2745
2768
|
return this.isOutputTarget ? this.toneMapping : NoToneMapping;
|
|
2746
2769
|
|
|
2747
2770
|
}
|
|
@@ -7,7 +7,11 @@ import { NodeFrame, NodeUpdateType, StackTrace } from '../../../nodes/Nodes.js';
|
|
|
7
7
|
import { renderGroup, cubeTexture, texture, fog, rangeFogFactor, densityFogFactor, reference, pmremTexture, screenUV, uniform } from '../../../nodes/TSL.js';
|
|
8
8
|
import { builtin } from '../../../nodes/accessors/BuiltinNode.js';
|
|
9
9
|
|
|
10
|
-
import { CubeUVReflectionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping } from '../../../constants.js';
|
|
10
|
+
import { CubeUVReflectionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping, NoToneMapping } from '../../../constants.js';
|
|
11
|
+
// WITH_GENESYS
|
|
12
|
+
import { vec4 } from '../../../nodes/tsl/TSLCore.js';
|
|
13
|
+
import { colorizeShaderComplexity, DEBUG_VIEW_SHADER_COMPLEXITY } from '../../../nodes/display/ComplexityDebug.js';
|
|
14
|
+
// !WITH_GENESYS
|
|
11
15
|
import { hashArray } from '../../../nodes/core/NodeUtils.js';
|
|
12
16
|
import { error } from '../../../utils.js';
|
|
13
17
|
|
|
@@ -992,7 +996,10 @@ class NodeManager extends DataMap {
|
|
|
992
996
|
|
|
993
997
|
const renderer = this.renderer;
|
|
994
998
|
|
|
995
|
-
|
|
999
|
+
// WITH_GENESYS
|
|
1000
|
+
return renderer.toneMapping + ',' + renderer.currentColorSpace + ',' + renderer.xr.isPresenting + ',' + renderer.debug.view;
|
|
1001
|
+
// !WITH_GENESYS
|
|
1002
|
+
// return renderer.toneMapping + ',' + renderer.currentColorSpace + ',' + renderer.xr.isPresenting;
|
|
996
1003
|
|
|
997
1004
|
}
|
|
998
1005
|
|
|
@@ -1007,27 +1014,35 @@ class NodeManager extends DataMap {
|
|
|
1007
1014
|
|
|
1008
1015
|
const renderer = this.renderer;
|
|
1009
1016
|
|
|
1010
|
-
let
|
|
1017
|
+
let sampled;
|
|
1011
1018
|
|
|
1012
1019
|
if ( outputTarget.isArrayTexture ) {
|
|
1013
1020
|
|
|
1014
1021
|
if ( this.backend.isWebGLBackend ) {
|
|
1015
1022
|
|
|
1016
|
-
|
|
1023
|
+
sampled = texture( outputTarget, screenUV ).depth( builtin( 'gl_ViewID_OVR' ) );
|
|
1017
1024
|
|
|
1018
1025
|
} else {
|
|
1019
1026
|
|
|
1020
|
-
|
|
1027
|
+
sampled = texture( outputTarget, screenUV ).depth( _outputLayerIndex );
|
|
1021
1028
|
|
|
1022
1029
|
}
|
|
1023
1030
|
|
|
1024
1031
|
} else {
|
|
1025
1032
|
|
|
1026
|
-
|
|
1033
|
+
sampled = texture( outputTarget, screenUV );
|
|
1027
1034
|
|
|
1028
1035
|
}
|
|
1029
1036
|
|
|
1030
|
-
|
|
1037
|
+
// WITH_GENESYS
|
|
1038
|
+
if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY ) {
|
|
1039
|
+
|
|
1040
|
+
return vec4( colorizeShaderComplexity( sampled.r ), 1 ).renderOutput( NoToneMapping, renderer.currentColorSpace );
|
|
1041
|
+
|
|
1042
|
+
}
|
|
1043
|
+
// !WITH_GENESYS
|
|
1044
|
+
|
|
1045
|
+
return sampled.renderOutput( renderer.toneMapping, renderer.currentColorSpace );
|
|
1031
1046
|
|
|
1032
1047
|
}
|
|
1033
1048
|
|
|
@@ -635,6 +635,10 @@ ${ flowData.code }
|
|
|
635
635
|
*/
|
|
636
636
|
generateTexture( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet ) {
|
|
637
637
|
|
|
638
|
+
// WITH_GENESYS
|
|
639
|
+
this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet );
|
|
640
|
+
// !WITH_GENESYS
|
|
641
|
+
|
|
638
642
|
if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`;
|
|
639
643
|
|
|
640
644
|
if ( texture.isDepthTexture ) {
|
|
@@ -678,6 +682,10 @@ ${ flowData.code }
|
|
|
678
682
|
*/
|
|
679
683
|
generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ) {
|
|
680
684
|
|
|
685
|
+
// WITH_GENESYS
|
|
686
|
+
this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
|
|
687
|
+
// !WITH_GENESYS
|
|
688
|
+
|
|
681
689
|
if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`;
|
|
682
690
|
|
|
683
691
|
if ( offsetSnippet ) {
|
|
@@ -934,9 +934,25 @@ class WebGLState {
|
|
|
934
934
|
|
|
935
935
|
this.setFlipSided( flipSided );
|
|
936
936
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
937
|
+
// WITH_GENESYS
|
|
938
|
+
// WebGL has no cached render pipeline. One+One is applied on each draw instead.
|
|
939
|
+
if ( this.backend.renderer.debug.view === 'shaderComplexity' && material.isShadowPassMaterial !== true && this.backend.renderer.isOutputTarget !== true ) {
|
|
940
|
+
|
|
941
|
+
this.setBlending( AdditiveBlending, AddEquation, OneFactor, OneFactor, AddEquation, OneFactor, OneFactor, material.blendColor, material.blendAlpha, true );
|
|
942
|
+
|
|
943
|
+
} else if ( material.blending === NormalBlending && material.transparent === false ) {
|
|
944
|
+
|
|
945
|
+
this.setBlending( NoBlending );
|
|
946
|
+
|
|
947
|
+
} else {
|
|
948
|
+
|
|
949
|
+
this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
|
|
950
|
+
|
|
951
|
+
}
|
|
952
|
+
// !WITH_GENESYS
|
|
953
|
+
// ( material.blending === NormalBlending && material.transparent === false )
|
|
954
|
+
// ? this.setBlending( NoBlending )
|
|
955
|
+
// : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
|
|
940
956
|
|
|
941
957
|
this.setDepthFunc( material.depthFunc );
|
|
942
958
|
this.setDepthTest( material.depthTest );
|