@gnsx/three 0.186.3 → 0.186.5

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.
Files changed (34) hide show
  1. package/build/three.webgpu.js +1326 -18
  2. package/build/three.webgpu.nodes.js +1326 -18
  3. package/examples/jsm/inspector/tabs/Settings.js +97 -0
  4. package/package.json +1 -1
  5. package/src/materials/nodes/MeshBasicNodeMaterial.js +13 -0
  6. package/src/materials/nodes/MeshLambertNodeMaterial.js +13 -0
  7. package/src/materials/nodes/MeshMatcapNodeMaterial.js +13 -0
  8. package/src/materials/nodes/MeshPhongNodeMaterial.js +13 -0
  9. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +25 -0
  10. package/src/materials/nodes/MeshSSSNodeMaterial.js +15 -0
  11. package/src/materials/nodes/MeshStandardNodeMaterial.js +13 -0
  12. package/src/materials/nodes/MeshToonNodeMaterial.js +13 -0
  13. package/src/materials/nodes/NodeMaterial.js +106 -1
  14. package/src/materials/nodes/ShadowNodeMaterial.js +13 -0
  15. package/src/materials/nodes/VolumeNodeMaterial.js +13 -0
  16. package/src/nodes/core/NodeBuilder.js +74 -0
  17. package/src/nodes/display/BufferDebug.js +143 -0
  18. package/src/nodes/display/ComplexityDebug.js +400 -0
  19. package/src/nodes/display/DrawCallDebug.js +118 -0
  20. package/src/nodes/display/LightingDebug.js +108 -0
  21. package/src/nodes/lighting/LightsNode.js +71 -2
  22. package/src/nodes/lighting/PointLightNode.js +4 -1
  23. package/src/nodes/lighting/RectAreaLightNode.js +14 -0
  24. package/src/nodes/lighting/SpotLightNode.js +10 -2
  25. package/src/renderers/common/Background.js +20 -1
  26. package/src/renderers/common/RenderObject.js +5 -0
  27. package/src/renderers/common/Renderer.js +27 -1
  28. package/src/renderers/common/nodes/NodeManager.js +32 -7
  29. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +8 -0
  30. package/src/renderers/webgl-fallback/utils/WebGLState.js +22 -3
  31. package/src/renderers/webgpu/WebGPUBackend.js +14 -2
  32. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +16 -0
  33. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +23 -0
  34. package/build/three.cjs +0 -17
@@ -0,0 +1,108 @@
1
+ // WITH_GENESYS
2
+ // Lighting only and detail lighting. Both replace the shaded albedo with a flat gray.
3
+ // !WITH_GENESYS
4
+
5
+ import { diffuseColor, diffuseContribution, metalness, roughness, specularColor, specularColorBlended, specularF90, clearcoat, sheen, iridescence, anisotropy, transmission, retroreflectivity } from '../core/PropertyNode.js';
6
+ import { normalViewGeometry } from '../accessors/Normal.js';
7
+ import { negateOnBackSide } from './FrontFacingNode.js';
8
+ import { float, vec3, Fn } from '../tsl/TSLCore.js';
9
+
10
+ /**
11
+ * Lighting only. Flat gray, no specular, geometry normals. Material detail is dropped.
12
+ *
13
+ * @type {string}
14
+ */
15
+ export const DEBUG_VIEW_LIGHTING_ONLY = 'lightingOnly';
16
+
17
+ /**
18
+ * Detail lighting. Flat gray and a constant specular, with normal maps and roughness kept.
19
+ *
20
+ * @type {string}
21
+ */
22
+ export const DEBUG_VIEW_DETAIL_LIGHTING = 'detailLighting';
23
+
24
+ /**
25
+ * Neutral albedo shared by both views. Matches Unreal's `LightingOnlyBrightness`.
26
+ *
27
+ * @type {number}
28
+ */
29
+ const LIGHTING_ONLY_BRIGHTNESS = 0.3;
30
+
31
+ /**
32
+ * Specular color used by detail lighting. Unreal writes `0.1` into the specular override.
33
+ *
34
+ * @type {number}
35
+ */
36
+ const DETAIL_LIGHTING_SPECULAR = 0.1;
37
+
38
+ /**
39
+ * Geometry normal for lighting only, so normal maps and `normalNode` do not shade the surface.
40
+ *
41
+ * @type {Node<vec3>}
42
+ */
43
+ export const lightingOnlyNormal = /*@__PURE__*/ Fn( ( builder ) => {
44
+
45
+ let node = normalViewGeometry;
46
+
47
+ if ( builder.isFlatShading() !== true ) {
48
+
49
+ node = negateOnBackSide( node );
50
+
51
+ }
52
+
53
+ return node;
54
+
55
+ }, 'vec3' );
56
+
57
+ /**
58
+ * Replaces albedo and specular after the material has written its channels.
59
+ * Lit materials become a dielectric gray. Unlit materials become flat gray.
60
+ *
61
+ * @param {NodeBuilder} builder - The current node builder.
62
+ * @param {string} view - `renderer.debug.view`.
63
+ */
64
+ export function applyLightingDebug( builder, view ) {
65
+
66
+ const material = builder.material;
67
+ const gray = vec3( LIGHTING_ONLY_BRIGHTNESS );
68
+
69
+ diffuseColor.rgb.assign( gray );
70
+
71
+ if ( material.lights !== true ) return;
72
+
73
+ metalness.assign( float( 0 ) );
74
+ diffuseContribution.assign( gray );
75
+
76
+ if ( view === DEBUG_VIEW_LIGHTING_ONLY ) {
77
+
78
+ roughness.assign( float( 1 ) );
79
+ specularColor.assign( vec3( 0 ) );
80
+ specularColorBlended.assign( vec3( 0 ) );
81
+ specularF90.assign( float( 0 ) );
82
+
83
+ // Ambient occlusion was stored for the lighting model. Lighting only has no material.
84
+ builder.context.ambientOcclusion = null;
85
+
86
+ if ( material.useClearcoat === true ) clearcoat.assign( float( 0 ) );
87
+
88
+ if ( material.useSheen === true ) sheen.assign( vec3( 0 ) );
89
+
90
+ if ( material.useIridescence === true ) iridescence.assign( float( 0 ) );
91
+
92
+ if ( material.useAnisotropy === true ) anisotropy.assign( float( 0 ) );
93
+
94
+ if ( material.useTransmission === true ) transmission.assign( float( 0 ) );
95
+
96
+ if ( material.useRetroreflection === true ) retroreflectivity.assign( float( 0 ) );
97
+
98
+ } else {
99
+
100
+ const specular = vec3( DETAIL_LIGHTING_SPECULAR );
101
+
102
+ specularColor.assign( specular );
103
+ specularColorBlended.assign( specular );
104
+ specularF90.assign( float( 1 ) );
105
+
106
+ }
107
+
108
+ }
@@ -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
- outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) );
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
- return { lightDirection, lightColor };
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
- let lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
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
- return { lightColor, lightDirection };
167
+ // WITH_GENESYS
168
+ return { lightColor, lightDirection, attenuation };
169
+ // !WITH_GENESYS
170
+ // return { lightColor, lightDirection };
163
171
 
164
172
  }
165
173
 
@@ -7,6 +7,9 @@ import { Mesh } from '../../objects/Mesh.js';
7
7
  import { SphereGeometry } from '../../geometries/SphereGeometry.js';
8
8
  import { BackSide } from '../../constants.js';
9
9
  import { error } from '../../utils.js';
10
+ // WITH_GENESYS
11
+ import { debugViewAccumulates } from '../../nodes/display/ComplexityDebug.js';
12
+ // !WITH_GENESYS
10
13
 
11
14
  const _clearColor = /*@__PURE__*/ new Color4();
12
15
 
@@ -191,7 +194,15 @@ class Background extends DataMap {
191
194
 
192
195
  }
193
196
 
194
- renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
197
+ // WITH_GENESYS
198
+ // The background is depth-tested off, so additive shader complexity would add it to every pixel.
199
+ if ( debugViewAccumulates( renderer.debug.view ) !== true ) {
200
+
201
+ renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
202
+
203
+ }
204
+ // !WITH_GENESYS
205
+ // renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
195
206
 
196
207
  } else {
197
208
 
@@ -215,6 +226,14 @@ class Background extends DataMap {
215
226
 
216
227
  //
217
228
 
229
+ // WITH_GENESYS
230
+ if ( debugViewAccumulates( renderer.debug.view ) ) {
231
+
232
+ _clearColor.set( 0, 0, 0, 1 );
233
+
234
+ }
235
+ // !WITH_GENESYS
236
+
218
237
  if ( renderer.autoClear === true || forceClear === true ) {
219
238
 
220
239
  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 ), hashString( this.renderer.debug.buffer ), this.renderer.debug.shaderComplexityBudget, this.renderer.debug.quadOverdrawBudget );
956
+ // !WITH_GENESYS
957
+
953
958
  return cacheKey;
954
959
 
955
960
  }
@@ -37,6 +37,8 @@ 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_QUAD_OVERDRAW, DEBUG_VIEW_SHADER_COMPLEXITY, DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS, DEFAULT_QUAD_OVERDRAW_BUDGET, DEFAULT_SHADER_COMPLEXITY_BUDGET, debugViewAccumulates } from '../../nodes/display/ComplexityDebug.js';
41
+ import { DEBUG_VIEW_BUFFER, DEFAULT_BUFFER } from '../../nodes/display/BufferDebug.js';
40
42
  // !WITH_GENESYS
41
43
  import { reference } from '../../nodes/accessors/ReferenceNode.js';
42
44
  import { highpModelNormalViewMatrix, highpModelViewMatrix } from '../../nodes/accessors/ModelNode.js';
@@ -743,6 +745,10 @@ class Renderer {
743
745
  * @property {?Function} onNodeBuilderCreated - A callback function that is executed after a node builder has been created and before it is built.
744
746
  * @property {?Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now.
745
747
  * @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object.
748
+ * @property {string} view - Debug view. `shaderComplexity`, `lightingComplexity`, `quadOverdraw`, and `shaderComplexityAndQuads` replace the shaded color with a heatmap. `shaderComplexityAndQuads` multiplies the shader cost by the overdraw count. `bufferVisualization` shows one material channel. `lightingOnly` and `detailLighting` light a flat gray surface. `drawCall` lights each submitted draw with its own diffuse color.
749
+ * @property {string} buffer - Channel drawn by `bufferVisualization`: `baseColor`, `worldNormal`, `roughness`, `metallic`, `ambientOcclusion`, or `emissive`.
750
+ * @property {number} shaderComplexityBudget - Proxy budget that fills the shader-complexity ramp.
751
+ * @property {number} quadOverdrawBudget - Overlapping fragments that fill the quad-overdraw ramp.
746
752
  */
747
753
 
748
754
  /**
@@ -757,6 +763,12 @@ class Renderer {
757
763
  },
758
764
  onNodeBuilderCreated: null,
759
765
  onShaderError: null,
766
+ // WITH_GENESYS
767
+ view: DEBUG_VIEW_NONE,
768
+ buffer: DEFAULT_BUFFER,
769
+ shaderComplexityBudget: DEFAULT_SHADER_COMPLEXITY_BUDGET,
770
+ quadOverdrawBudget: DEFAULT_QUAD_OVERDRAW_BUDGET,
771
+ // !WITH_GENESYS
760
772
  getShaderAsync: async ( scene, camera, object ) => {
761
773
 
762
774
  await this.compileAsync( object, camera, scene );
@@ -2691,7 +2703,11 @@ class Renderer {
2691
2703
  const useToneMapping = this.currentToneMapping !== NoToneMapping;
2692
2704
  const useColorSpace = this.currentColorSpace !== ColorManagement.workingColorSpace;
2693
2705
 
2694
- return useToneMapping || useColorSpace;
2706
+ // WITH_GENESYS
2707
+ // Accumulating views write a scalar into an intermediate target, then the output pass colorizes it.
2708
+ return useToneMapping || useColorSpace || debugViewAccumulates( this.debug.view );
2709
+ // !WITH_GENESYS
2710
+ // return useToneMapping || useColorSpace;
2695
2711
 
2696
2712
  }
2697
2713
 
@@ -2742,6 +2758,16 @@ class Renderer {
2742
2758
  */
2743
2759
  get currentToneMapping() {
2744
2760
 
2761
+ // WITH_GENESYS
2762
+ const view = this.debug.view;
2763
+
2764
+ if ( view === DEBUG_VIEW_SHADER_COMPLEXITY || view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS || view === DEBUG_VIEW_LIGHTING_COMPLEXITY || view === DEBUG_VIEW_QUAD_OVERDRAW || view === DEBUG_VIEW_BUFFER ) {
2765
+
2766
+ return NoToneMapping;
2767
+
2768
+ }
2769
+ // !WITH_GENESYS
2770
+
2745
2771
  return this.isOutputTarget ? this.toneMapping : NoToneMapping;
2746
2772
 
2747
2773
  }
@@ -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 { colorizeQuadOverdraw, colorizeShaderComplexity, DEBUG_VIEW_QUAD_OVERDRAW, DEBUG_VIEW_SHADER_COMPLEXITY, DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS, SHADER_COMPLEXITY_QUAD_COUNT_SCALE } 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
- return renderer.toneMapping + ',' + renderer.currentColorSpace + ',' + renderer.xr.isPresenting;
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,45 @@ class NodeManager extends DataMap {
1007
1014
 
1008
1015
  const renderer = this.renderer;
1009
1016
 
1010
- let output;
1017
+ let sampled;
1011
1018
 
1012
1019
  if ( outputTarget.isArrayTexture ) {
1013
1020
 
1014
1021
  if ( this.backend.isWebGLBackend ) {
1015
1022
 
1016
- output = texture( outputTarget, screenUV ).depth( builtin( 'gl_ViewID_OVR' ) ).renderOutput( renderer.toneMapping, renderer.currentColorSpace );
1023
+ sampled = texture( outputTarget, screenUV ).depth( builtin( 'gl_ViewID_OVR' ) );
1017
1024
 
1018
1025
  } else {
1019
1026
 
1020
- output = texture( outputTarget, screenUV ).depth( _outputLayerIndex ).renderOutput( renderer.toneMapping, renderer.currentColorSpace );
1027
+ sampled = texture( outputTarget, screenUV ).depth( _outputLayerIndex );
1021
1028
 
1022
1029
  }
1023
1030
 
1024
1031
  } else {
1025
1032
 
1026
- output = texture( outputTarget, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace );
1033
+ sampled = texture( outputTarget, screenUV );
1027
1034
 
1028
1035
  }
1029
1036
 
1030
- return output;
1037
+ // WITH_GENESYS
1038
+ if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY || renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS ) {
1039
+
1040
+ const complexity = renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS
1041
+ ? sampled.r.mul( sampled.g ).mul( SHADER_COMPLEXITY_QUAD_COUNT_SCALE )
1042
+ : sampled.r;
1043
+
1044
+ return vec4( colorizeShaderComplexity( complexity ), 1 ).renderOutput( NoToneMapping, renderer.currentColorSpace );
1045
+
1046
+ }
1047
+
1048
+ if ( renderer.debug.view === DEBUG_VIEW_QUAD_OVERDRAW ) {
1049
+
1050
+ return vec4( colorizeQuadOverdraw( sampled.r ), 1 ).renderOutput( NoToneMapping, renderer.currentColorSpace );
1051
+
1052
+ }
1053
+ // !WITH_GENESYS
1054
+
1055
+ return sampled.renderOutput( renderer.toneMapping, renderer.currentColorSpace );
1031
1056
 
1032
1057
  }
1033
1058
 
@@ -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 ) {
@@ -11,6 +11,9 @@ import {
11
11
  import { Color } from '../../../math/Color.js';
12
12
  import { Vector4 } from '../../../math/Vector4.js';
13
13
  import { error, ReversedDepthFuncs, warnOnce } from '../../../utils.js';
14
+ // WITH_GENESYS
15
+ import { debugViewAccumulates } from '../../../nodes/display/ComplexityDebug.js';
16
+ // !WITH_GENESYS
14
17
 
15
18
  let equationToGL, factorToGL;
16
19
 
@@ -934,9 +937,25 @@ class WebGLState {
934
937
 
935
938
  this.setFlipSided( flipSided );
936
939
 
937
- ( material.blending === NormalBlending && material.transparent === false )
938
- ? this.setBlending( NoBlending )
939
- : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
940
+ // WITH_GENESYS
941
+ // WebGL has no cached render pipeline. One+One is applied on each draw instead.
942
+ if ( debugViewAccumulates( this.backend.renderer.debug.view ) && material.isShadowPassMaterial !== true && this.backend.renderer.isOutputTarget !== true ) {
943
+
944
+ this.setBlending( AdditiveBlending, AddEquation, OneFactor, OneFactor, AddEquation, OneFactor, OneFactor, material.blendColor, material.blendAlpha, true );
945
+
946
+ } else if ( material.blending === NormalBlending && material.transparent === false ) {
947
+
948
+ this.setBlending( NoBlending );
949
+
950
+ } else {
951
+
952
+ this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
953
+
954
+ }
955
+ // !WITH_GENESYS
956
+ // ( material.blending === NormalBlending && material.transparent === false )
957
+ // ? this.setBlending( NoBlending )
958
+ // : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
940
959
 
941
960
  this.setDepthFunc( material.depthFunc );
942
961
  this.setDepthTest( material.depthTest );
@@ -2389,6 +2389,9 @@ class WebGPUBackend extends Backend {
2389
2389
  const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context );
2390
2390
  const primitiveTopology = utils.getPrimitiveTopology( object, material );
2391
2391
  const frontFaceCW = ( object.isMesh && object.matrixWorld.determinantAffine() < 0 );
2392
+ // WITH_GENESYS
2393
+ const debugView = renderObject.renderer.debug.view;
2394
+ // !WITH_GENESYS
2392
2395
 
2393
2396
  let needsUpdate = false;
2394
2397
 
@@ -2406,7 +2409,10 @@ class WebGPUBackend extends Backend {
2406
2409
  data.colorFormat !== colorFormat || data.depthStencilFormat !== depthStencilFormat ||
2407
2410
  data.primitiveTopology !== primitiveTopology ||
2408
2411
  data.frontFaceCW !== frontFaceCW ||
2409
- data.clippingContextCacheKey !== renderObject.clippingContextCacheKey
2412
+ data.clippingContextCacheKey !== renderObject.clippingContextCacheKey ||
2413
+ // WITH_GENESYS
2414
+ data.debugView !== debugView
2415
+ // !WITH_GENESYS
2410
2416
  ) {
2411
2417
 
2412
2418
  data.material = material; data.materialVersion = material.version;
@@ -2427,6 +2433,9 @@ class WebGPUBackend extends Backend {
2427
2433
  data.primitiveTopology = primitiveTopology;
2428
2434
  data.frontFaceCW = frontFaceCW;
2429
2435
  data.clippingContextCacheKey = renderObject.clippingContextCacheKey;
2436
+ // WITH_GENESYS
2437
+ data.debugView = debugView;
2438
+ // !WITH_GENESYS
2430
2439
 
2431
2440
  needsUpdate = true;
2432
2441
 
@@ -2470,7 +2479,10 @@ class WebGPUBackend extends Backend {
2470
2479
  utils.getCurrentColorSpace( renderContext ), utils.getCurrentColorFormat( renderContext ), utils.getCurrentDepthStencilFormat( renderContext ),
2471
2480
  utils.getPrimitiveTopology( object, material ),
2472
2481
  renderObject.getGeometryCacheKey(),
2473
- renderObject.clippingContextCacheKey
2482
+ renderObject.clippingContextCacheKey,
2483
+ // WITH_GENESYS
2484
+ renderObject.renderer.debug.view
2485
+ // !WITH_GENESYS
2474
2486
  ].join();
2475
2487
 
2476
2488
  }
@@ -376,6 +376,10 @@ class WGSLNodeBuilder extends NodeBuilder {
376
376
  */
377
377
  _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) {
378
378
 
379
+ // WITH_GENESYS
380
+ if ( shaderStage === 'fragment' ) this.recordFragmentTextureSample( texture, shaderStage, textureProperty + '|' + uvSnippet );
381
+ // !WITH_GENESYS
382
+
379
383
  if ( shaderStage === 'fragment' ) {
380
384
 
381
385
  if ( depthSnippet ) {
@@ -656,6 +660,10 @@ class WGSLNodeBuilder extends NodeBuilder {
656
660
  */
657
661
  generateFilteredTexture( texture, textureProperty, uvSnippet, offsetSnippet, levelSnippet = '0u', depthSnippet ) {
658
662
 
663
+ // WITH_GENESYS
664
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
665
+ // !WITH_GENESYS
666
+
659
667
  const wrapFunction = this.generateWrapFunction( texture );
660
668
  const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet );
661
669
 
@@ -693,6 +701,10 @@ class WGSLNodeBuilder extends NodeBuilder {
693
701
  */
694
702
  generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet = '0u' ) {
695
703
 
704
+ // WITH_GENESYS
705
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
706
+ // !WITH_GENESYS
707
+
696
708
  // Cube textures cannot use textureLoad in WGSL, must use textureSampleLevel
697
709
  if ( texture.isCubeTexture === true ) {
698
710
 
@@ -1071,6 +1083,10 @@ class WGSLNodeBuilder extends NodeBuilder {
1071
1083
 
1072
1084
  if ( this.isUnfilterable( texture ) === false ) {
1073
1085
 
1086
+ // WITH_GENESYS
1087
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
1088
+ // !WITH_GENESYS
1089
+
1074
1090
  if ( depthSnippet ) {
1075
1091
 
1076
1092
  if ( offsetSnippet ) {
@@ -15,6 +15,9 @@ import {
15
15
  } from '../../../constants.js';
16
16
 
17
17
  import { error, ReversedDepthFuncs, warn, warnOnce } from '../../../utils.js';
18
+ // WITH_GENESYS
19
+ import { debugViewAccumulates } from '../../../nodes/display/ComplexityDebug.js';
20
+ // !WITH_GENESYS
18
21
 
19
22
  import GPUComputePipelineDescriptor from '../descriptors/GPUComputePipelineDescriptor.js';
20
23
  import GPUPipelineLayoutDescriptor from '../descriptors/GPUPipelineLayoutDescriptor.js';
@@ -106,6 +109,26 @@ class WebGPUPipelineUtils {
106
109
 
107
110
  }
108
111
 
112
+ // WITH_GENESYS
113
+ // Accumulate shader cost with One+One. Opaque materials normally disable blending.
114
+ if ( debugViewAccumulates( backend.renderer.debug.view ) && material.isShadowPassMaterial !== true && backend.renderer.isOutputTarget !== true ) {
115
+
116
+ materialBlending = {
117
+ color: {
118
+ srcFactor: GPUBlendFactor.One,
119
+ dstFactor: GPUBlendFactor.One,
120
+ operation: GPUBlendOperation.Add
121
+ },
122
+ alpha: {
123
+ srcFactor: GPUBlendFactor.One,
124
+ dstFactor: GPUBlendFactor.One,
125
+ operation: GPUBlendOperation.Add
126
+ }
127
+ };
128
+
129
+ }
130
+ // !WITH_GENESYS
131
+
109
132
  // stencil
110
133
 
111
134
  let stencilFront = {};