@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
@@ -21614,6 +21614,767 @@ class VertexColorNode extends AttributeNode {
21614
21614
  */
21615
21615
  const vertexColor = ( index = 0 ) => new VertexColorNode( index );
21616
21616
 
21617
+ // WITH_GENESYS
21618
+ // Shader and lighting complexity debug views. Costs are a material proxy, not ISA instruction counts.
21619
+ // !WITH_GENESYS
21620
+
21621
+
21622
+ /**
21623
+ * Shaded output. No complexity debug view.
21624
+ *
21625
+ * @type {string}
21626
+ */
21627
+ const DEBUG_VIEW_NONE = 'none';
21628
+
21629
+ /**
21630
+ * Material-cost heatmap. Overlapping draws accumulate, then a fullscreen pass applies the ramp.
21631
+ *
21632
+ * @type {string}
21633
+ */
21634
+ const DEBUG_VIEW_SHADER_COMPLEXITY = 'shaderComplexity';
21635
+
21636
+ /**
21637
+ * Direct-light count heatmap. The visible surface wins.
21638
+ *
21639
+ * @type {string}
21640
+ */
21641
+ const DEBUG_VIEW_LIGHTING_COMPLEXITY = 'lightingComplexity';
21642
+
21643
+ /**
21644
+ * Per-pixel overdraw heatmap. Each fragment that passes the depth test adds one.
21645
+ * This is the portable stand-in for Unreal's 2×2 quad-coverage count.
21646
+ *
21647
+ * @type {string}
21648
+ */
21649
+ const DEBUG_VIEW_QUAD_OVERDRAW = 'quadOverdraw';
21650
+
21651
+ /**
21652
+ * Shader cost multiplied by the number of fragments that shaded the pixel, then the shader-complexity ramp.
21653
+ * One opaque surface matches {@link DEBUG_VIEW_SHADER_COMPLEXITY}. Each extra overlapping fragment scales the summed cost.
21654
+ * WebGPU cannot count wasted lanes in a 2×2 quad, so the count is fragments that pass the depth test.
21655
+ *
21656
+ * @type {string}
21657
+ */
21658
+ const DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS = 'shaderComplexityAndQuads';
21659
+
21660
+ /**
21661
+ * Proxy budget that fills the shader-complexity ramp.
21662
+ * Unlit and basic stay green. Phong and standard move through yellow into red.
21663
+ * Transmission plus several texture samples climbs toward white.
21664
+ *
21665
+ * @type {number}
21666
+ */
21667
+ const DEFAULT_SHADER_COMPLEXITY_BUDGET = 800;
21668
+
21669
+ /**
21670
+ * Overlapping fragments that fill the quad-overdraw ramp.
21671
+ * Unreal's stair reaches white at ten layers (`1 / 16` stored, then scaled by 1.6).
21672
+ *
21673
+ * @type {number}
21674
+ */
21675
+ const DEFAULT_QUAD_OVERDRAW_BUDGET = 10;
21676
+
21677
+ /**
21678
+ * Storage scale for the overdraw count in {@link DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS}.
21679
+ * Each fragment adds `1 / scale`, so an 8-bit target can hold this many layers.
21680
+ * The output pass multiplies that channel back to a count. Half-float targets hold the same count exactly.
21681
+ *
21682
+ * @type {number}
21683
+ */
21684
+ const SHADER_COMPLEXITY_QUAD_COUNT_SCALE = 16;
21685
+
21686
+ /**
21687
+ * Added for each fragment texture sample. Lighting-model costs are returned
21688
+ * directly by {@link NodeMaterial#getShaderComplexity}.
21689
+ *
21690
+ * @type {number}
21691
+ */
21692
+ const SHADER_COMPLEXITY_TEXTURE_COST = 16;
21693
+
21694
+ /**
21695
+ * Attenuation above this counts as a light that shades the pixel.
21696
+ *
21697
+ * @type {number}
21698
+ */
21699
+ const LIGHTING_COMPLEXITY_EPSILON = 0.001;
21700
+
21701
+ /**
21702
+ * Added on top of 1 when a received light casts a shadow.
21703
+ * Applied even where the shadow map is black.
21704
+ *
21705
+ * @type {number}
21706
+ */
21707
+ const LIGHTING_COMPLEXITY_SHADOW_WEIGHT = 0.5;
21708
+
21709
+ /**
21710
+ * Unreal `ShaderComplexityColors` from `BaseEngine.ini`.
21711
+ *
21712
+ * @type {Array<Array<number>>}
21713
+ */
21714
+ const SHADER_COMPLEXITY_COLORS = [
21715
+ [ 0.0, 1.0, 0.127 ],
21716
+ [ 0.0, 1.0, 0.0 ],
21717
+ [ 0.046, 0.52, 0.0 ],
21718
+ [ 0.215, 0.215, 0.0 ],
21719
+ [ 0.52, 0.046, 0.0 ],
21720
+ [ 0.7, 0.0, 0.0 ],
21721
+ [ 1.0, 0.0, 0.0 ],
21722
+ [ 1.0, 0.0, 0.5 ],
21723
+ [ 1.0, 0.9, 0.9 ]
21724
+ ];
21725
+
21726
+ /**
21727
+ * Unreal `QuadComplexityColors` from `BaseEngine.ini`.
21728
+ * Sampled as a stair: one overlapping fragment is one stop.
21729
+ *
21730
+ * @type {Array<Array<number>>}
21731
+ */
21732
+ const QUAD_COMPLEXITY_COLORS = [
21733
+ [ 0.0, 0.0, 0.0 ],
21734
+ [ 0.0, 0.0, 0.4 ],
21735
+ [ 0.0, 0.3, 1.0 ],
21736
+ [ 0.0, 0.7, 0.4 ],
21737
+ [ 0.0, 1.0, 0.0 ],
21738
+ [ 0.8, 0.8, 0.0 ],
21739
+ [ 1.0, 0.3, 0.0 ],
21740
+ [ 0.7, 0.0, 0.0 ],
21741
+ [ 0.5, 0.0, 0.5 ],
21742
+ [ 0.7, 0.3, 0.7 ],
21743
+ [ 1.0, 0.9, 0.9 ]
21744
+ ];
21745
+
21746
+ /**
21747
+ * Unreal `LightComplexityColors` from `BaseEngine.ini`.
21748
+ *
21749
+ * @type {Array<Array<number>>}
21750
+ */
21751
+ const LIGHT_COMPLEXITY_COLORS = [
21752
+ [ 0.0, 0.0, 0.0 ],
21753
+ [ 0.0, 0.0, 0.4 ],
21754
+ [ 0.0, 0.3, 1.0 ],
21755
+ [ 0.0, 0.7, 0.4 ],
21756
+ [ 0.0, 1.0, 0.0 ],
21757
+ [ 0.8, 0.8, 0.0 ],
21758
+ [ 1.0, 0.3, 0.0 ],
21759
+ [ 0.7, 0.0, 0.0 ],
21760
+ [ 0.5, 0.0, 0.5 ],
21761
+ [ 0.7, 0.3, 0.7 ],
21762
+ [ 1.0, 0.9, 0.9 ]
21763
+ ];
21764
+
21765
+ const rgb = ( colors, index ) => vec3( colors[ index ][ 0 ], colors[ index ][ 1 ], colors[ index ][ 2 ] );
21766
+
21767
+ /**
21768
+ * Linear sample of a fixed RGB ramp. `cost` is in steps, and one step is one light.
21769
+ *
21770
+ * @param {Node<float>} cost - Complexity in ramp steps.
21771
+ * @param {Array<Array<number>>} colors - Ramp stops.
21772
+ * @return {Node<vec3>} The ramp color.
21773
+ */
21774
+ const colorizeLinear = ( cost, colors ) => {
21775
+
21776
+ const steps = colors.length - 1;
21777
+ const expanded = cost.div( steps ).clamp( 0, 0.999 ).mul( steps );
21778
+ const index = expanded.floor();
21779
+ const frac = fract( expanded );
21780
+
21781
+ let color = rgb( colors, 0 );
21782
+
21783
+ for ( let i = 0; i < steps; i ++ ) {
21784
+
21785
+ const sample = mix( rgb( colors, i ), rgb( colors, i + 1 ), frac );
21786
+
21787
+ color = index.greaterThanEqual( float( i ) ).and( index.lessThan( float( i + 1 ) ) ).select( sample, color );
21788
+
21789
+ }
21790
+
21791
+ return color;
21792
+
21793
+ };
21794
+
21795
+ /**
21796
+ * Maps a direct-light cost through Unreal's light-complexity ramp.
21797
+ * Ten lights saturate at white.
21798
+ *
21799
+ * @param {Node<float>} cost - Accumulated light weight.
21800
+ * @return {Node<vec3>} The ramp color.
21801
+ */
21802
+ const colorizeLightComplexity = ( cost ) => colorizeLinear( cost, LIGHT_COMPLEXITY_COLORS );
21803
+
21804
+ /**
21805
+ * Unreal's stair sample for quad overdraw (`CS_STAIR`).
21806
+ * `cost` is the accumulated fragment count divided by the budget.
21807
+ *
21808
+ * @param {Node<float>} cost - Overdraw count divided by the budget.
21809
+ * @return {Node<vec3>} The ramp color.
21810
+ */
21811
+ const colorizeQuadOverdraw = ( cost ) => {
21812
+
21813
+ const steps = QUAD_COMPLEXITY_COLORS.length - 1;
21814
+ const index = round( cost.clamp( 0, 1 ).mul( steps ) );
21815
+
21816
+ let color = rgb( QUAD_COMPLEXITY_COLORS, 0 );
21817
+
21818
+ for ( let i = 0; i <= steps; i ++ ) {
21819
+
21820
+ color = index.equal( float( i ) ).select( rgb( QUAD_COMPLEXITY_COLORS, i ), color );
21821
+
21822
+ }
21823
+
21824
+ return color;
21825
+
21826
+ };
21827
+
21828
+ /**
21829
+ * Views that add a scalar per fragment, then colorize that sum in the output pass.
21830
+ *
21831
+ * @param {string} view - `renderer.debug.view`.
21832
+ * @return {boolean} `true` when the view accumulates.
21833
+ */
21834
+ function debugViewAccumulates( view ) {
21835
+
21836
+ return view === DEBUG_VIEW_SHADER_COMPLEXITY || view === DEBUG_VIEW_QUAD_OVERDRAW || view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS;
21837
+
21838
+ }
21839
+
21840
+ /**
21841
+ * Unreal's nonlinear shader-complexity ramp (`ColorizeComplexity`).
21842
+ * The first third of the normalized cost spreads across the first seven stops.
21843
+ *
21844
+ * @param {Node<float>} complexity - Accumulated cost divided by the budget.
21845
+ * @return {Node<vec3>} The ramp color.
21846
+ */
21847
+ const colorizeShaderComplexity = /*@__PURE__*/ Fn( ( [ complexity ] ) => {
21848
+
21849
+ const c = complexity.clamp( 0, 0.999 );
21850
+ const expanded = min$1( float( SHADER_COMPLEXITY_COLORS.length - 2 ), c.mul( 18 ) );
21851
+ const color = vec3( 0 ).toVar();
21852
+ const frac = fract( expanded );
21853
+
21854
+ If( expanded.lessThan( 1 ), () => {
21855
+
21856
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 0 ), rgb( SHADER_COMPLEXITY_COLORS, 1 ), frac ) );
21857
+
21858
+ } ).ElseIf( expanded.lessThan( 2 ), () => {
21859
+
21860
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 1 ), rgb( SHADER_COMPLEXITY_COLORS, 2 ), frac ) );
21861
+
21862
+ } ).ElseIf( expanded.lessThan( 3 ), () => {
21863
+
21864
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 2 ), rgb( SHADER_COMPLEXITY_COLORS, 3 ), frac ) );
21865
+
21866
+ } ).ElseIf( expanded.lessThan( 4 ), () => {
21867
+
21868
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 3 ), rgb( SHADER_COMPLEXITY_COLORS, 4 ), frac ) );
21869
+
21870
+ } ).ElseIf( expanded.lessThan( 5 ), () => {
21871
+
21872
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 4 ), rgb( SHADER_COMPLEXITY_COLORS, 5 ), frac ) );
21873
+
21874
+ } ).ElseIf( expanded.lessThan( 6 ), () => {
21875
+
21876
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 5 ), rgb( SHADER_COMPLEXITY_COLORS, 6 ), frac ) );
21877
+
21878
+ } ).Else( () => {
21879
+
21880
+ // Nine stops, so the upper range uses the `count > 8` scale of 3.
21881
+ const upper = c.sub( 0.33333333 ).mul( 3.0 );
21882
+ const upperFrac = fract( upper );
21883
+
21884
+ If( upper.lessThanEqual( 1 ), () => {
21885
+
21886
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 6 ), rgb( SHADER_COMPLEXITY_COLORS, 7 ), upperFrac ) );
21887
+
21888
+ } ).Else( () => {
21889
+
21890
+ color.assign( mix( rgb( SHADER_COMPLEXITY_COLORS, 7 ), rgb( SHADER_COMPLEXITY_COLORS, 8 ), upperFrac ) );
21891
+
21892
+ } );
21893
+
21894
+ } );
21895
+
21896
+ return color;
21897
+
21898
+ } );
21899
+
21900
+ /**
21901
+ * Reads the builder's shader-complexity proxy at code-generation time,
21902
+ * after the real material graph has been generated and texture samples counted.
21903
+ *
21904
+ * @augments Node
21905
+ */
21906
+ class ShaderComplexityRatioNode extends Node {
21907
+
21908
+ static get type() {
21909
+
21910
+ return 'ShaderComplexityRatioNode';
21911
+
21912
+ }
21913
+
21914
+ constructor() {
21915
+
21916
+ super( 'float' );
21917
+
21918
+ }
21919
+
21920
+ generate( builder ) {
21921
+
21922
+ const budget = builder.renderer.debug.shaderComplexityBudget;
21923
+ const safeBudget = ( typeof budget === 'number' && budget > 0 ) ? budget : 1;
21924
+ const ratio = builder.getShaderComplexityCost() / safeBudget;
21925
+
21926
+ return ratio.toFixed( 6 );
21927
+
21928
+ }
21929
+
21930
+ }
21931
+
21932
+ /**
21933
+ * Replaces the shaded color with `vec4(cost / budget, 0, 0, 1)`.
21934
+ * The real graph is still generated so texture samples are counted first.
21935
+ *
21936
+ * @param {Node} resultNode - The material's shaded output.
21937
+ * @return {Node<vec4>} The complexity ratio in the red channel.
21938
+ */
21939
+ function shaderComplexityOutput( resultNode ) {
21940
+
21941
+ // Generate the shaded graph first so texture samples are counted, then
21942
+ // replace the color. A bypass of a value node emits a bare expression
21943
+ // statement, which WGSL rejects.
21944
+ const shaded = vec4( resultNode ).toVar();
21945
+
21946
+ const ratio = new ShaderComplexityRatioNode();
21947
+
21948
+ return vec4( ratio, 0, 0, 1 ).add( shaded.mul( 0 ) );
21949
+
21950
+ }
21951
+
21952
+ /**
21953
+ * Same cost as {@link shaderComplexityOutput}, plus one overdraw step in green.
21954
+ * The output pass multiplies red by the accumulated green count.
21955
+ *
21956
+ * @param {Node} resultNode - The material's shaded output.
21957
+ * @return {Node<vec4>} Cost ratio in red, one scaled fragment in green.
21958
+ */
21959
+ function shaderComplexityAndQuadsOutput( resultNode ) {
21960
+
21961
+ const shaded = vec4( resultNode ).toVar();
21962
+ const ratio = new ShaderComplexityRatioNode();
21963
+ const step = float( 1 / SHADER_COMPLEXITY_QUAD_COUNT_SCALE );
21964
+
21965
+ return vec4( ratio, step, 0, 1 ).add( shaded.mul( 0 ) );
21966
+
21967
+ }
21968
+
21969
+ /**
21970
+ * Reads `1 / quadOverdrawBudget` at code-generation time.
21971
+ *
21972
+ * @augments Node
21973
+ */
21974
+ class QuadOverdrawRatioNode extends Node {
21975
+
21976
+ static get type() {
21977
+
21978
+ return 'QuadOverdrawRatioNode';
21979
+
21980
+ }
21981
+
21982
+ constructor() {
21983
+
21984
+ super( 'float' );
21985
+
21986
+ }
21987
+
21988
+ generate( builder ) {
21989
+
21990
+ const budget = builder.renderer.debug.quadOverdrawBudget;
21991
+ const safeBudget = ( typeof budget === 'number' && budget > 0 ) ? budget : 1;
21992
+
21993
+ return ( 1 / safeBudget ).toFixed( 6 );
21994
+
21995
+ }
21996
+
21997
+ }
21998
+
21999
+ /**
22000
+ * Replaces the shaded color with `vec4(1 / budget, 0, 0, 1)`.
22001
+ * The real graph is still generated so clipped fragments are not counted.
22002
+ *
22003
+ * @param {Node} resultNode - The material's shaded output.
22004
+ * @return {Node<vec4>} One overdraw step in the red channel.
22005
+ */
22006
+ function quadOverdrawOutput( resultNode ) {
22007
+
22008
+ const shaded = vec4( resultNode ).toVar();
22009
+ const ratio = new QuadOverdrawRatioNode();
22010
+
22011
+ return vec4( ratio, 0, 0, 1 ).add( shaded.mul( 0 ) );
22012
+
22013
+ }
22014
+
22015
+ // WITH_GENESYS
22016
+ // Buffer visualization. Shows one material channel in place of the shaded color.
22017
+ // !WITH_GENESYS
22018
+
22019
+
22020
+ /**
22021
+ * Buffer visualization. The visible surface wins, and one material channel replaces the shaded color.
22022
+ *
22023
+ * @type {string}
22024
+ */
22025
+ const DEBUG_VIEW_BUFFER = 'bufferVisualization';
22026
+
22027
+ /**
22028
+ * Albedo before lighting, including maps and vertex colors.
22029
+ *
22030
+ * @type {string}
22031
+ */
22032
+ const BUFFER_BASE_COLOR = 'baseColor';
22033
+
22034
+ /**
22035
+ * Shading normal in world space, packed to RGB with `n * 0.5 + 0.5`.
22036
+ *
22037
+ * @type {string}
22038
+ */
22039
+ const BUFFER_WORLD_NORMAL = 'worldNormal';
22040
+
22041
+ /**
22042
+ * Scalar roughness used by the lighting model. Black is smooth.
22043
+ *
22044
+ * @type {string}
22045
+ */
22046
+ const BUFFER_ROUGHNESS = 'roughness';
22047
+
22048
+ /**
22049
+ * Scalar metalness. White is metal. Unreal calls this buffer Metallic.
22050
+ *
22051
+ * @type {string}
22052
+ */
22053
+ const BUFFER_METALLIC = 'metallic';
22054
+
22055
+ /**
22056
+ * Material ambient occlusion. White means no occlusion map.
22057
+ *
22058
+ * @type {string}
22059
+ */
22060
+ const BUFFER_AMBIENT_OCCLUSION = 'ambientOcclusion';
22061
+
22062
+ /**
22063
+ * Emissive color before it is added to the lit result.
22064
+ *
22065
+ * @type {string}
22066
+ */
22067
+ const BUFFER_EMISSIVE = 'emissive';
22068
+
22069
+ /**
22070
+ * Channel drawn when buffer visualization is first enabled.
22071
+ *
22072
+ * @type {string}
22073
+ */
22074
+ const DEFAULT_BUFFER = BUFFER_BASE_COLOR;
22075
+
22076
+ /**
22077
+ * Writes a defined value for channels a material may never assign.
22078
+ * Standard and physical materials overwrite roughness and metalness in `setupVariants`,
22079
+ * and emissive is overwritten when the material has one.
22080
+ *
22081
+ * @param {string} buffer - `renderer.debug.buffer`.
22082
+ */
22083
+ function assignBufferDefaults( buffer ) {
22084
+
22085
+ if ( buffer === BUFFER_ROUGHNESS ) {
22086
+
22087
+ roughness.assign( float( 0 ) );
22088
+
22089
+ } else if ( buffer === BUFFER_METALLIC ) {
22090
+
22091
+ metalness.assign( float( 0 ) );
22092
+
22093
+ } else if ( buffer === BUFFER_EMISSIVE ) {
22094
+
22095
+ emissive.assign( vec3( 0 ) );
22096
+
22097
+ }
22098
+
22099
+ }
22100
+
22101
+ /**
22102
+ * The color for one buffer channel. Scalar channels are copied into RGB.
22103
+ *
22104
+ * @param {string} buffer - `renderer.debug.buffer`.
22105
+ * @return {Node<vec3>} The channel color.
22106
+ */
22107
+ function bufferVisualizationColor( buffer ) {
22108
+
22109
+ if ( buffer === BUFFER_WORLD_NORMAL ) {
22110
+
22111
+ return normalWorld.mul( 0.5 ).add( 0.5 );
22112
+
22113
+ }
22114
+
22115
+ if ( buffer === BUFFER_ROUGHNESS ) {
22116
+
22117
+ return vec3( roughness );
22118
+
22119
+ }
22120
+
22121
+ if ( buffer === BUFFER_METALLIC ) {
22122
+
22123
+ return vec3( metalness );
22124
+
22125
+ }
22126
+
22127
+ if ( buffer === BUFFER_AMBIENT_OCCLUSION ) {
22128
+
22129
+ return vec3( ambientOcclusion );
22130
+
22131
+ }
22132
+
22133
+ if ( buffer === BUFFER_EMISSIVE ) {
22134
+
22135
+ return emissive;
22136
+
22137
+ }
22138
+
22139
+ return diffuseColor.rgb;
22140
+
22141
+ }
22142
+
22143
+ /**
22144
+ * Replaces the shaded color with the selected buffer. Alpha stays the material's coverage
22145
+ * so masked and transparent surfaces keep their shape.
22146
+ *
22147
+ * @param {string} buffer - `renderer.debug.buffer`.
22148
+ * @return {Node<vec4>} The buffer color.
22149
+ */
22150
+ function bufferVisualizationOutput( buffer ) {
22151
+
22152
+ return vec4( bufferVisualizationColor( buffer ), diffuseColor.a );
22153
+
22154
+ }
22155
+
22156
+ // WITH_GENESYS
22157
+ // Lighting only and detail lighting. Both replace the shaded albedo with a flat gray.
22158
+ // !WITH_GENESYS
22159
+
22160
+
22161
+ /**
22162
+ * Lighting only. Flat gray, no specular, geometry normals. Material detail is dropped.
22163
+ *
22164
+ * @type {string}
22165
+ */
22166
+ const DEBUG_VIEW_LIGHTING_ONLY = 'lightingOnly';
22167
+
22168
+ /**
22169
+ * Detail lighting. Flat gray and a constant specular, with normal maps and roughness kept.
22170
+ *
22171
+ * @type {string}
22172
+ */
22173
+ const DEBUG_VIEW_DETAIL_LIGHTING = 'detailLighting';
22174
+
22175
+ /**
22176
+ * Neutral albedo shared by both views. Matches Unreal's `LightingOnlyBrightness`.
22177
+ *
22178
+ * @type {number}
22179
+ */
22180
+ const LIGHTING_ONLY_BRIGHTNESS = 0.3;
22181
+
22182
+ /**
22183
+ * Specular color used by detail lighting. Unreal writes `0.1` into the specular override.
22184
+ *
22185
+ * @type {number}
22186
+ */
22187
+ const DETAIL_LIGHTING_SPECULAR = 0.1;
22188
+
22189
+ /**
22190
+ * Geometry normal for lighting only, so normal maps and `normalNode` do not shade the surface.
22191
+ *
22192
+ * @type {Node<vec3>}
22193
+ */
22194
+ const lightingOnlyNormal = /*@__PURE__*/ Fn( ( builder ) => {
22195
+
22196
+ let node = normalViewGeometry;
22197
+
22198
+ if ( builder.isFlatShading() !== true ) {
22199
+
22200
+ node = negateOnBackSide( node );
22201
+
22202
+ }
22203
+
22204
+ return node;
22205
+
22206
+ }, 'vec3' );
22207
+
22208
+ /**
22209
+ * Replaces albedo and specular after the material has written its channels.
22210
+ * Lit materials become a dielectric gray. Unlit materials become flat gray.
22211
+ *
22212
+ * @param {NodeBuilder} builder - The current node builder.
22213
+ * @param {string} view - `renderer.debug.view`.
22214
+ */
22215
+ function applyLightingDebug( builder, view ) {
22216
+
22217
+ const material = builder.material;
22218
+ const gray = vec3( LIGHTING_ONLY_BRIGHTNESS );
22219
+
22220
+ diffuseColor.rgb.assign( gray );
22221
+
22222
+ if ( material.lights !== true ) return;
22223
+
22224
+ metalness.assign( float( 0 ) );
22225
+ diffuseContribution.assign( gray );
22226
+
22227
+ if ( view === DEBUG_VIEW_LIGHTING_ONLY ) {
22228
+
22229
+ roughness.assign( float( 1 ) );
22230
+ specularColor.assign( vec3( 0 ) );
22231
+ specularColorBlended.assign( vec3( 0 ) );
22232
+ specularF90.assign( float( 0 ) );
22233
+
22234
+ // Ambient occlusion was stored for the lighting model. Lighting only has no material.
22235
+ builder.context.ambientOcclusion = null;
22236
+
22237
+ if ( material.useClearcoat === true ) clearcoat.assign( float( 0 ) );
22238
+
22239
+ if ( material.useSheen === true ) sheen.assign( vec3( 0 ) );
22240
+
22241
+ if ( material.useIridescence === true ) iridescence.assign( float( 0 ) );
22242
+
22243
+ if ( material.useAnisotropy === true ) anisotropy.assign( float( 0 ) );
22244
+
22245
+ if ( material.useTransmission === true ) transmission.assign( float( 0 ) );
22246
+
22247
+ if ( material.useRetroreflection === true ) retroreflectivity.assign( float( 0 ) );
22248
+
22249
+ } else {
22250
+
22251
+ const specular = vec3( DETAIL_LIGHTING_SPECULAR );
22252
+
22253
+ specularColor.assign( specular );
22254
+ specularColorBlended.assign( specular );
22255
+ specularF90.assign( float( 1 ) );
22256
+
22257
+ }
22258
+
22259
+ }
22260
+
22261
+ // WITH_GENESYS
22262
+ // Draw call coloration. One stable diffuse color per submitted draw, then lit.
22263
+ // !WITH_GENESYS
22264
+
22265
+
22266
+ /**
22267
+ * Draw call coloration. Each submitted draw gets one diffuse color. An instanced mesh is one draw.
22268
+ * The color is lit, so lights and shadows still show. Unlit materials stay flat.
22269
+ *
22270
+ * @type {string}
22271
+ */
22272
+ const DEBUG_VIEW_DRAW_CALL = 'drawCall';
22273
+
22274
+ /**
22275
+ * Golden-ratio step. Sequential object ids land on opposite sides of the hue wheel.
22276
+ *
22277
+ * @type {number}
22278
+ */
22279
+ const DRAW_CALL_HUE_STEP = 0.618033988749895;
22280
+
22281
+ /**
22282
+ * Saturation of a draw color. High enough that neighboring hues stay apart after lighting.
22283
+ *
22284
+ * @type {number}
22285
+ */
22286
+ const DRAW_CALL_SATURATION = 0.85;
22287
+
22288
+ /**
22289
+ * Value of a draw color. Lighting and shadows darken it from here.
22290
+ *
22291
+ * @type {number}
22292
+ */
22293
+ const DRAW_CALL_VALUE = 0.92;
22294
+
22295
+ /**
22296
+ * Writes a saturated color for this draw into `color`.
22297
+ * Hue walks the wheel by the golden ratio, so consecutive objects do not share a tint.
22298
+ * Instances of one mesh share the object id, so they share the color.
22299
+ *
22300
+ * @param {Color} color - The uniform color, updated in place.
22301
+ * @param {Object3D} object - The drawn object.
22302
+ * @param {Material} material - The drawn material. A multi-material group is its own draw.
22303
+ * @return {Color} `color`.
22304
+ */
22305
+ function writeDrawCallColor( color, object, material ) {
22306
+
22307
+ const hue = ( ( object.id + material.id * 64 ) * DRAW_CALL_HUE_STEP ) % 1;
22308
+ const s = DRAW_CALL_SATURATION;
22309
+ const v = DRAW_CALL_VALUE;
22310
+ const sector = hue * 6;
22311
+ const i = Math.floor( sector );
22312
+ const f = sector - i;
22313
+ const p = v * ( 1 - s );
22314
+ const q = v * ( 1 - f * s );
22315
+ const t = v * ( 1 - ( 1 - f ) * s );
22316
+
22317
+ switch ( i % 6 ) {
22318
+
22319
+ case 0: return color.setRGB( v, t, p );
22320
+ case 1: return color.setRGB( q, v, p );
22321
+ case 2: return color.setRGB( p, v, t );
22322
+ case 3: return color.setRGB( p, q, v );
22323
+ case 4: return color.setRGB( t, p, v );
22324
+ default: return color.setRGB( v, p, q );
22325
+
22326
+ }
22327
+
22328
+ }
22329
+
22330
+ /**
22331
+ * Replaces albedo with the draw color after the material has written its channels.
22332
+ * Lit materials become a matte dielectric in that color. Unlit materials become flat.
22333
+ * The color is an object uniform, so meshes that share a material still differ.
22334
+ *
22335
+ * @param {NodeBuilder} builder - The current node builder.
22336
+ */
22337
+ function applyDrawCallDebug( builder ) {
22338
+
22339
+ const material = builder.material;
22340
+ const colorNode = uniform( new Color() ).onObjectUpdate( ( { object, material: drawnMaterial }, self ) => {
22341
+
22342
+ if ( object === null || drawnMaterial === null ) return;
22343
+
22344
+ return writeDrawCallColor( self.value, object, drawnMaterial );
22345
+
22346
+ } );
22347
+
22348
+ diffuseColor.rgb.assign( colorNode );
22349
+
22350
+ if ( material.lights !== true ) return;
22351
+
22352
+ metalness.assign( float( 0 ) );
22353
+ diffuseContribution.assign( colorNode );
22354
+ roughness.assign( float( 1 ) );
22355
+ specularColor.assign( vec3( 0 ) );
22356
+ specularColorBlended.assign( vec3( 0 ) );
22357
+ specularF90.assign( float( 0 ) );
22358
+
22359
+ // Ambient occlusion belonged to the original material.
22360
+ builder.context.ambientOcclusion = null;
22361
+
22362
+ if ( material.useClearcoat === true ) clearcoat.assign( float( 0 ) );
22363
+
22364
+ if ( material.useSheen === true ) sheen.assign( vec3( 0 ) );
22365
+
22366
+ if ( material.useIridescence === true ) iridescence.assign( float( 0 ) );
22367
+
22368
+ if ( material.useAnisotropy === true ) anisotropy.assign( float( 0 ) );
22369
+
22370
+ if ( material.useTransmission === true ) transmission.assign( float( 0 ) );
22371
+
22372
+ if ( material.useRetroreflection === true ) retroreflectivity.assign( float( 0 ) );
22373
+
22374
+ }
22375
+
22376
+ // !WITH_GENESYS
22377
+
21617
22378
  /**
21618
22379
  * Base class for all node materials.
21619
22380
  *
@@ -22112,10 +22873,33 @@ class NodeMaterial extends Material {
22112
22873
 
22113
22874
  if ( this.fragmentNode === null ) {
22114
22875
 
22876
+ // WITH_GENESYS
22877
+ // Fallback for materials that never write the channel. Lit materials overwrite these.
22878
+ if ( renderer.debug.view === DEBUG_VIEW_BUFFER && this.isShadowPassMaterial !== true ) {
22879
+
22880
+ assignBufferDefaults( renderer.debug.buffer );
22881
+
22882
+ }
22883
+ // !WITH_GENESYS
22884
+
22115
22885
  this.setupDiffuseColor( builder );
22116
22886
  this.setupAmbientOcclusion( builder );
22117
22887
  this.setupVariants( builder );
22118
22888
 
22889
+ // WITH_GENESYS
22890
+ // After the material writes its channels, so roughness and normals already exist
22891
+ // for detail lighting and can be replaced for lighting only.
22892
+ if ( ( renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || renderer.debug.view === DEBUG_VIEW_DETAIL_LIGHTING ) && this.isShadowPassMaterial !== true ) {
22893
+
22894
+ applyLightingDebug( builder, renderer.debug.view );
22895
+
22896
+ } else if ( renderer.debug.view === DEBUG_VIEW_DRAW_CALL && this.isShadowPassMaterial !== true ) {
22897
+
22898
+ applyDrawCallDebug( builder );
22899
+
22900
+ }
22901
+ // !WITH_GENESYS
22902
+
22119
22903
  const outgoingLightNode = this.setupLighting( builder );
22120
22904
 
22121
22905
  if ( clippingNode !== null ) builder.stack.addToStack( clippingNode );
@@ -22185,6 +22969,32 @@ class NodeMaterial extends Material {
22185
22969
 
22186
22970
  }
22187
22971
 
22972
+ // WITH_GENESYS
22973
+ // The screen output pass colorizes the accumulated ratio. Wrapping that pass
22974
+ // would replace the heatmap with this material's own constant cost.
22975
+ if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY && this.isShadowPassMaterial !== true && renderer.isOutputTarget !== true ) {
22976
+
22977
+ builder.shaderComplexityBase = this.getShaderComplexity();
22978
+ resultNode = shaderComplexityOutput( resultNode );
22979
+
22980
+ } else if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS && this.isShadowPassMaterial !== true && renderer.isOutputTarget !== true ) {
22981
+
22982
+ builder.shaderComplexityBase = this.getShaderComplexity();
22983
+ resultNode = shaderComplexityAndQuadsOutput( resultNode );
22984
+
22985
+ } else if ( renderer.debug.view === DEBUG_VIEW_QUAD_OVERDRAW && this.isShadowPassMaterial !== true && renderer.isOutputTarget !== true ) {
22986
+
22987
+ resultNode = quadOverdrawOutput( resultNode );
22988
+
22989
+ } else if ( renderer.debug.view === DEBUG_VIEW_BUFFER && this.isShadowPassMaterial !== true && this.fragmentNode === null ) {
22990
+
22991
+ // The fullscreen output pass sets fragmentNode. Scene materials do not, including
22992
+ // when the scene is drawn straight to the canvas.
22993
+ resultNode = bufferVisualizationOutput( renderer.debug.buffer );
22994
+
22995
+ }
22996
+ // !WITH_GENESYS
22997
+
22188
22998
  builder.stack.outputNode = resultNode;
22189
22999
 
22190
23000
  builder.addFlow( 'fragment', builder.removeStack() );
@@ -22195,6 +23005,21 @@ class NodeMaterial extends Material {
22195
23005
 
22196
23006
  }
22197
23007
 
23008
+ // WITH_GENESYS
23009
+ /**
23010
+ * Static shader-complexity proxy for this material's lighting model.
23011
+ * Fragment texture samples are counted later, while the shader is generated.
23012
+ * Derived materials override this instead of registering a type flag.
23013
+ *
23014
+ * @return {number} The base cost, excluding texture samples.
23015
+ */
23016
+ getShaderComplexity() {
23017
+
23018
+ return this.lights === true ? 40 : 20;
23019
+
23020
+ }
23021
+ // !WITH_GENESYS
23022
+
22198
23023
  /**
22199
23024
  * Setups the clipping node.
22200
23025
  *
@@ -22519,9 +23344,18 @@ class NodeMaterial extends Material {
22519
23344
  /**
22520
23345
  * Setups the normal node from the material.
22521
23346
  *
23347
+ * @param {NodeBuilder} builder - The current node builder.
22522
23348
  * @return {Node<vec3>} The normal node.
22523
23349
  */
22524
- setupNormal() {
23350
+ setupNormal( builder ) {
23351
+
23352
+ // WITH_GENESYS
23353
+ if ( ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || builder.renderer.debug.view === DEBUG_VIEW_DRAW_CALL ) && this.isShadowPassMaterial !== true && this.fragmentNode === null ) {
23354
+
23355
+ return lightingOnlyNormal();
23356
+
23357
+ }
23358
+ // !WITH_GENESYS
22525
23359
 
22526
23360
  return this.normalNode ? vec3( this.normalNode ) : materialNormal;
22527
23361
 
@@ -22698,10 +23532,36 @@ class NodeMaterial extends Material {
22698
23532
 
22699
23533
  }
22700
23534
 
23535
+ // WITH_GENESYS
23536
+ if ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_COMPLEXITY && this.isShadowPassMaterial !== true ) {
23537
+
23538
+ const hasLightLoop = lightsNode && ( materialLightings.length > 0 || lightsNode.getScope().hasLights );
23539
+
23540
+ if ( hasLightLoop !== true ) {
23541
+
23542
+ outgoingLightNode = vec3( 0 );
23543
+
23544
+ }
23545
+
23546
+ return outgoingLightNode;
23547
+
23548
+ }
23549
+ // !WITH_GENESYS
23550
+
22701
23551
  // EMISSIVE
22702
23552
 
22703
23553
  if ( ( emissiveNode && emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) {
22704
23554
 
23555
+ // WITH_GENESYS
23556
+ // Lighting only and draw call substitute a plain lit material, so emissive is dropped.
23557
+ // Detail lighting keeps it.
23558
+ if ( ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || builder.renderer.debug.view === DEBUG_VIEW_DRAW_CALL ) && this.isShadowPassMaterial !== true ) {
23559
+
23560
+ return outgoingLightNode;
23561
+
23562
+ }
23563
+ // !WITH_GENESYS
23564
+
22705
23565
  emissive.assign( vec3( emissiveNode ? emissiveNode : materialEmissive ) );
22706
23566
 
22707
23567
  outgoingLightNode = outgoingLightNode.add( emissive );
@@ -24576,6 +25436,19 @@ class MeshBasicNodeMaterial extends NodeMaterial {
24576
25436
 
24577
25437
  }
24578
25438
 
25439
+ // WITH_GENESYS
25440
+ /**
25441
+ * Shader-complexity proxy for {@link BasicLightingModel}.
25442
+ *
25443
+ * @return {number} The base cost, excluding texture samples.
25444
+ */
25445
+ getShaderComplexity() {
25446
+
25447
+ return 80;
25448
+
25449
+ }
25450
+ // !WITH_GENESYS
25451
+
24579
25452
  /**
24580
25453
  * Setups the lighting model.
24581
25454
  *
@@ -24759,6 +25632,19 @@ class MeshLambertNodeMaterial extends NodeMaterial {
24759
25632
 
24760
25633
  }
24761
25634
 
25635
+ // WITH_GENESYS
25636
+ /**
25637
+ * Shader-complexity proxy for Lambert. Specular is forced off.
25638
+ *
25639
+ * @return {number} The base cost, excluding texture samples.
25640
+ */
25641
+ getShaderComplexity() {
25642
+
25643
+ return 140;
25644
+
25645
+ }
25646
+ // !WITH_GENESYS
25647
+
24762
25648
  /**
24763
25649
  * Setups the lighting model.
24764
25650
  *
@@ -24860,6 +25746,19 @@ class MeshPhongNodeMaterial extends NodeMaterial {
24860
25746
 
24861
25747
  }
24862
25748
 
25749
+ // WITH_GENESYS
25750
+ /**
25751
+ * Shader-complexity proxy for Blinn-Phong.
25752
+ *
25753
+ * @return {number} The base cost, excluding texture samples.
25754
+ */
25755
+ getShaderComplexity() {
25756
+
25757
+ return 200;
25758
+
25759
+ }
25760
+ // !WITH_GENESYS
25761
+
24863
25762
  /**
24864
25763
  * Setups the lighting model.
24865
25764
  *
@@ -28348,6 +29247,19 @@ class MeshStandardNodeMaterial extends NodeMaterial {
28348
29247
 
28349
29248
  }
28350
29249
 
29250
+ // WITH_GENESYS
29251
+ /**
29252
+ * Shader-complexity proxy for the Cook-Torrance GGX model.
29253
+ *
29254
+ * @return {number} The base cost, excluding texture samples.
29255
+ */
29256
+ getShaderComplexity() {
29257
+
29258
+ return 240;
29259
+
29260
+ }
29261
+ // !WITH_GENESYS
29262
+
28351
29263
  /**
28352
29264
  * Setups the lighting model.
28353
29265
  *
@@ -28777,6 +29689,31 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
28777
29689
 
28778
29690
  }
28779
29691
 
29692
+ // WITH_GENESYS
29693
+ /**
29694
+ * GGX base from {@link MeshStandardNodeMaterial}, plus each enabled physical feature.
29695
+ *
29696
+ * @return {number} The base cost, excluding texture samples.
29697
+ */
29698
+ getShaderComplexity() {
29699
+
29700
+ let cost = super.getShaderComplexity();
29701
+
29702
+ if ( this.useClearcoat === true ) cost += 30;
29703
+
29704
+ if ( this.useSheen === true ) cost += 30;
29705
+
29706
+ if ( this.useIridescence === true ) cost += 30;
29707
+
29708
+ if ( this.useAnisotropy === true ) cost += 30;
29709
+
29710
+ if ( this.useTransmission === true ) cost += 60;
29711
+
29712
+ return cost;
29713
+
29714
+ }
29715
+ // !WITH_GENESYS
29716
+
28780
29717
  /**
28781
29718
  * Setups the lighting model.
28782
29719
  *
@@ -29061,6 +29998,21 @@ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial {
29061
29998
 
29062
29999
  }
29063
30000
 
30001
+ // WITH_GENESYS
30002
+ /**
30003
+ * Physical complexity, plus the subsurface term when it is evaluated.
30004
+ *
30005
+ * @return {number} The base cost, excluding texture samples.
30006
+ */
30007
+ getShaderComplexity() {
30008
+
30009
+ const cost = super.getShaderComplexity();
30010
+
30011
+ return this.useSSS === true ? cost + 40 : cost;
30012
+
30013
+ }
30014
+ // !WITH_GENESYS
30015
+
29064
30016
  /**
29065
30017
  * Setups the lighting model.
29066
30018
  *
@@ -29182,6 +30134,19 @@ class MeshToonNodeMaterial extends NodeMaterial {
29182
30134
 
29183
30135
  }
29184
30136
 
30137
+ // WITH_GENESYS
30138
+ /**
30139
+ * Shader-complexity proxy for toon banding.
30140
+ *
30141
+ * @return {number} The base cost, excluding texture samples.
30142
+ */
30143
+ getShaderComplexity() {
30144
+
30145
+ return 170;
30146
+
30147
+ }
30148
+ // !WITH_GENESYS
30149
+
29185
30150
  /**
29186
30151
  * Setups the lighting model.
29187
30152
  *
@@ -29253,6 +30218,19 @@ class MeshMatcapNodeMaterial extends NodeMaterial {
29253
30218
 
29254
30219
  }
29255
30220
 
30221
+ // WITH_GENESYS
30222
+ /**
30223
+ * Shader-complexity proxy for matcap UV shading.
30224
+ *
30225
+ * @return {number} The base cost, excluding texture samples.
30226
+ */
30227
+ getShaderComplexity() {
30228
+
30229
+ return 50;
30230
+
30231
+ }
30232
+ // !WITH_GENESYS
30233
+
29256
30234
  /**
29257
30235
  * Setups the matcap specific node variables.
29258
30236
  *
@@ -29928,6 +30906,19 @@ class ShadowNodeMaterial extends NodeMaterial {
29928
30906
 
29929
30907
  }
29930
30908
 
30909
+ // WITH_GENESYS
30910
+ /**
30911
+ * Shader-complexity proxy for the shadow mask.
30912
+ *
30913
+ * @return {number} The base cost, excluding texture samples.
30914
+ */
30915
+ getShaderComplexity() {
30916
+
30917
+ return 110;
30918
+
30919
+ }
30920
+ // !WITH_GENESYS
30921
+
29931
30922
  /**
29932
30923
  * Setups the lighting model.
29933
30924
  *
@@ -30214,6 +31205,19 @@ class VolumeNodeMaterial extends NodeMaterial {
30214
31205
 
30215
31206
  }
30216
31207
 
31208
+ // WITH_GENESYS
31209
+ /**
31210
+ * Shader-complexity proxy for volumetric ray integration.
31211
+ *
31212
+ * @return {number} The base cost, excluding texture samples.
31213
+ */
31214
+ getShaderComplexity() {
31215
+
31216
+ return 280;
31217
+
31218
+ }
31219
+ // !WITH_GENESYS
31220
+
30217
31221
  setupLightingModel() {
30218
31222
 
30219
31223
  return new VolumetricLightingModel();
@@ -31460,6 +32464,11 @@ class RenderObject {
31460
32464
 
31461
32465
  cacheKey = hash$1( cacheKey, this.renderer.contextNode.id, this.renderer.contextNode.version );
31462
32466
 
32467
+ // WITH_GENESYS
32468
+ // hash() xors each argument as a number, so a view name has to be hashed first.
32469
+ cacheKey = hash$1( cacheKey, hashString( this.renderer.debug.view ), hashString( this.renderer.debug.buffer ), this.renderer.debug.shaderComplexityBudget, this.renderer.debug.quadOverdrawBudget );
32470
+ // !WITH_GENESYS
32471
+
31463
32472
  return cacheKey;
31464
32473
 
31465
32474
  }
@@ -46355,6 +47364,10 @@ const totalSpecular = property( 'vec3', 'totalSpecular' );
46355
47364
  */
46356
47365
  const outgoingLight = property( 'vec3', 'outgoingLight' );
46357
47366
 
47367
+ // WITH_GENESYS
47368
+ const lightingComplexity = property( 'float', 'lightingComplexity' );
47369
+ // !WITH_GENESYS
47370
+
46358
47371
  /**
46359
47372
  * Sorts an array of lights in ascending order by their IDs.
46360
47373
  *
@@ -46708,6 +47721,10 @@ class LightsNode extends Node {
46708
47721
  reflectedLight
46709
47722
  }, builder );
46710
47723
 
47724
+ // WITH_GENESYS
47725
+ this._addLightingComplexity( builder, lightNode, lightData );
47726
+ // !WITH_GENESYS
47727
+
46711
47728
  }
46712
47729
 
46713
47730
  /**
@@ -46727,8 +47744,40 @@ class LightsNode extends Node {
46727
47744
  reflectedLight
46728
47745
  }, builder );
46729
47746
 
47747
+ // WITH_GENESYS
47748
+ this._addLightingComplexity( builder, lightNode, lightData );
47749
+ // !WITH_GENESYS
47750
+
46730
47751
  }
46731
47752
 
47753
+ // WITH_GENESYS
47754
+ /**
47755
+ * Adds this direct light's weight to the lighting-complexity accumulator.
47756
+ * Point, spot, and rect-area lights count only where attenuation is in range.
47757
+ * Directional lights have no falloff, so they always count. Shadow-casting
47758
+ * lights add extra weight even where the shadow map is black.
47759
+ *
47760
+ * @private
47761
+ * @param {NodeBuilder} builder - The current node builder.
47762
+ * @param {LightingNode} lightNode - The light node being shaded.
47763
+ * @param {Object} lightData - Direct light terms, including an optional attenuation node.
47764
+ */
47765
+ _addLightingComplexity( builder, lightNode, lightData ) {
47766
+
47767
+ if ( builder.renderer.debug.view !== DEBUG_VIEW_LIGHTING_COMPLEXITY ) return;
47768
+
47769
+ if ( builder.material && builder.material.isShadowPassMaterial === true ) return;
47770
+
47771
+ const attenuation = lightData.attenuation !== undefined ? lightData.attenuation : float( 1 );
47772
+ const light = lightNode.light;
47773
+ const castsShadow = light !== undefined && light !== null && light.castShadow === true && builder.object.receiveShadow === true;
47774
+ const weight = castsShadow ? float( 1 + LIGHTING_COMPLEXITY_SHADOW_WEIGHT ) : float( 1 );
47775
+
47776
+ lightingComplexity.addAssign( attenuation.greaterThan( LIGHTING_COMPLEXITY_EPSILON ).select( weight, float( 0 ) ) );
47777
+
47778
+ }
47779
+ // !WITH_GENESYS
47780
+
46732
47781
  /**
46733
47782
  * Setups the internal lights by building all respective
46734
47783
  * light nodes.
@@ -46791,6 +47840,14 @@ class LightsNode extends Node {
46791
47840
 
46792
47841
  properties.nodes = stack.nodes;
46793
47842
 
47843
+ // WITH_GENESYS
47844
+ if ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_COMPLEXITY && ( builder.material === null || builder.material.isShadowPassMaterial !== true ) ) {
47845
+
47846
+ lightingComplexity.assign( 0 );
47847
+
47848
+ }
47849
+ // !WITH_GENESYS
47850
+
46794
47851
  lightingModel.start( builder );
46795
47852
 
46796
47853
  const { backdrop, backdropAlpha } = context;
@@ -46815,10 +47872,28 @@ class LightsNode extends Node {
46815
47872
  totalDiffuseNode.assign( totalDiffuse );
46816
47873
  totalSpecularNode.assign( directSpecular.add( indirectSpecular ) );
46817
47874
 
46818
- outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) );
47875
+ // WITH_GENESYS
47876
+ const lightingComplexityView = builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_COMPLEXITY && ( builder.material === null || builder.material.isShadowPassMaterial !== true );
47877
+
47878
+ if ( lightingComplexityView !== true ) {
47879
+
47880
+ outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) );
47881
+
47882
+ }
47883
+ // !WITH_GENESYS
47884
+ // outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) );
46819
47885
 
46820
47886
  lightingModel.finish( builder );
46821
47887
 
47888
+ // WITH_GENESYS
47889
+ // After finish(), so clearcoat and sheen cannot draw over the heatmap.
47890
+ if ( lightingComplexityView === true ) {
47891
+
47892
+ outgoingLightNode.assign( colorizeLightComplexity( lightingComplexity ) );
47893
+
47894
+ }
47895
+ // !WITH_GENESYS
47896
+
46822
47897
  outgoingLightNode = outgoingLightNode.bypass( builder.removeStack() );
46823
47898
 
46824
47899
  } else {
@@ -48910,7 +49985,10 @@ const directPointLight = ( { color, lightVector, cutoffDistance, decayExponent }
48910
49985
 
48911
49986
  const lightColor = color.mul( attenuation );
48912
49987
 
48913
- return { lightDirection, lightColor };
49988
+ // WITH_GENESYS
49989
+ return { lightDirection, lightColor, attenuation };
49990
+ // !WITH_GENESYS
49991
+ // return { lightDirection, lightColor };
48914
49992
 
48915
49993
  };
48916
49994
 
@@ -51842,6 +52920,8 @@ var TSL = /*#__PURE__*/Object.freeze({
51842
52920
  xor: xor
51843
52921
  });
51844
52922
 
52923
+ // !WITH_GENESYS
52924
+
51845
52925
  const _clearColor = /*@__PURE__*/ new Color4();
51846
52926
 
51847
52927
  /**
@@ -52025,7 +53105,15 @@ class Background extends DataMap {
52025
53105
 
52026
53106
  }
52027
53107
 
52028
- renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
53108
+ // WITH_GENESYS
53109
+ // The background is depth-tested off, so additive shader complexity would add it to every pixel.
53110
+ if ( debugViewAccumulates( renderer.debug.view ) !== true ) {
53111
+
53112
+ renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
53113
+
53114
+ }
53115
+ // !WITH_GENESYS
53116
+ // renderList.unshift( backgroundMesh, backgroundMesh.geometry, backgroundMesh.material, 0, 0, null, null );
52029
53117
 
52030
53118
  } else {
52031
53119
 
@@ -52049,6 +53137,14 @@ class Background extends DataMap {
52049
53137
 
52050
53138
  //
52051
53139
 
53140
+ // WITH_GENESYS
53141
+ if ( debugViewAccumulates( renderer.debug.view ) ) {
53142
+
53143
+ _clearColor.set( 0, 0, 0, 1 );
53144
+
53145
+ }
53146
+ // !WITH_GENESYS
53147
+
52052
53148
  if ( renderer.autoClear === true || forceClear === true ) {
52053
53149
 
52054
53150
  const clearColorValue = renderContext.clearColorValue;
@@ -53689,6 +54785,31 @@ class NodeBuilder {
53689
54785
  */
53690
54786
  this.fragmentShader = null;
53691
54787
 
54788
+ // WITH_GENESYS
54789
+ /**
54790
+ * Static material-feature cost for the shader-complexity debug view.
54791
+ *
54792
+ * @type {number}
54793
+ * @default 0
54794
+ */
54795
+ this.shaderComplexityBase = 0;
54796
+
54797
+ /**
54798
+ * Fragment texture samples counted while generating the shader.
54799
+ *
54800
+ * @type {number}
54801
+ * @default 0
54802
+ */
54803
+ this.fragmentTextureSamples = 0;
54804
+
54805
+ /**
54806
+ * Sample sites already counted, so a node that is generated twice is not double-counted.
54807
+ *
54808
+ * @type {Set<string>}
54809
+ */
54810
+ this.shaderComplexitySampleKeys = new Set();
54811
+ // !WITH_GENESYS
54812
+
53692
54813
  /**
53693
54814
  * The generated compute shader.
53694
54815
  *
@@ -54717,6 +55838,46 @@ class NodeBuilder {
54717
55838
 
54718
55839
  }
54719
55840
 
55841
+ // WITH_GENESYS
55842
+ /**
55843
+ * Counts one fragment texture sample toward the shader-complexity proxy.
55844
+ * Depth and cube textures are shadow maps and environment maps, and rect-area
55845
+ * LTC tables belong to the light loop, so they are not material cost.
55846
+ *
55847
+ * @param {?Texture} texture - The texture being sampled.
55848
+ * @param {string} [shaderStage=this.shaderStage] - The stage the sample is emitted for.
55849
+ * @param {string} [key=''] - Stable id for this sample site. Repeated generation of the same site counts once.
55850
+ */
55851
+ recordFragmentTextureSample( texture, shaderStage = this.shaderStage, key = '' ) {
55852
+
55853
+ if ( shaderStage !== 'fragment' ) return;
55854
+
55855
+ if ( texture && ( texture.isDepthTexture === true || texture.isCubeTexture === true || texture.isRectAreaLTC === true ) ) return;
55856
+
55857
+ if ( key !== '' ) {
55858
+
55859
+ if ( this.shaderComplexitySampleKeys.has( key ) ) return;
55860
+
55861
+ this.shaderComplexitySampleKeys.add( key );
55862
+
55863
+ }
55864
+
55865
+ this.fragmentTextureSamples ++;
55866
+
55867
+ }
55868
+
55869
+ /**
55870
+ * Returns the shader-complexity proxy for the material currently being built.
55871
+ *
55872
+ * @return {number} Base feature cost plus weighted fragment texture samples.
55873
+ */
55874
+ getShaderComplexityCost() {
55875
+
55876
+ return this.shaderComplexityBase + this.fragmentTextureSamples * SHADER_COMPLEXITY_TEXTURE_COST;
55877
+
55878
+ }
55879
+ // !WITH_GENESYS
55880
+
54720
55881
  /**
54721
55882
  * Generates a texture LOD shader string for the given texture data.
54722
55883
  *
@@ -56540,6 +57701,12 @@ class NodeBuilder {
56540
57701
  */
56541
57702
  prebuild() {
56542
57703
 
57704
+ // WITH_GENESYS
57705
+ this.shaderComplexityBase = 0;
57706
+ this.fragmentTextureSamples = 0;
57707
+ this.shaderComplexitySampleKeys.clear();
57708
+ // !WITH_GENESYS
57709
+
56543
57710
  const { renderer, material } = this;
56544
57711
 
56545
57712
  // < renderer.contextNode >
@@ -57564,7 +58731,12 @@ class SpotLightNode extends AnalyticLightNode {
57564
58731
  decayExponent: decayExponentNode
57565
58732
  } );
57566
58733
 
57567
- let lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
58734
+ // WITH_GENESYS
58735
+ const attenuation = spotAttenuation.mul( lightAttenuation );
58736
+
58737
+ let lightColor = colorNode.mul( attenuation );
58738
+ // !WITH_GENESYS
58739
+ // let lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
57568
58740
 
57569
58741
  let projected, lightCoord;
57570
58742
 
@@ -57588,7 +58760,10 @@ class SpotLightNode extends AnalyticLightNode {
57588
58760
 
57589
58761
  }
57590
58762
 
57591
- return { lightColor, lightDirection };
58763
+ // WITH_GENESYS
58764
+ return { lightColor, lightDirection, attenuation };
58765
+ // !WITH_GENESYS
58766
+ // return { lightColor, lightDirection };
57592
58767
 
57593
58768
  }
57594
58769
 
@@ -57904,6 +59079,20 @@ class RectAreaLightNode extends AnalyticLightNode {
57904
59079
 
57905
59080
  setupDirectRectArea( builder ) {
57906
59081
 
59082
+ // WITH_GENESYS
59083
+ // LTC lookups are part of the light loop, not the material's shader cost.
59084
+ if ( _ltcLib !== null ) {
59085
+
59086
+ _ltcLib.LTC_FLOAT_1.isRectAreaLTC = true;
59087
+ _ltcLib.LTC_FLOAT_2.isRectAreaLTC = true;
59088
+
59089
+ if ( _ltcLib.LTC_HALF_1 ) _ltcLib.LTC_HALF_1.isRectAreaLTC = true;
59090
+
59091
+ if ( _ltcLib.LTC_HALF_2 ) _ltcLib.LTC_HALF_2.isRectAreaLTC = true;
59092
+
59093
+ }
59094
+ // !WITH_GENESYS
59095
+
57907
59096
  let ltc_1, ltc_2;
57908
59097
 
57909
59098
  if ( builder.isAvailable( 'float32Filterable' ) ) {
@@ -59200,7 +60389,10 @@ class NodeManager extends DataMap {
59200
60389
 
59201
60390
  const renderer = this.renderer;
59202
60391
 
59203
- return renderer.toneMapping + ',' + renderer.currentColorSpace + ',' + renderer.xr.isPresenting;
60392
+ // WITH_GENESYS
60393
+ return renderer.toneMapping + ',' + renderer.currentColorSpace + ',' + renderer.xr.isPresenting + ',' + renderer.debug.view;
60394
+ // !WITH_GENESYS
60395
+ // return renderer.toneMapping + ',' + renderer.currentColorSpace + ',' + renderer.xr.isPresenting;
59204
60396
 
59205
60397
  }
59206
60398
 
@@ -59215,27 +60407,45 @@ class NodeManager extends DataMap {
59215
60407
 
59216
60408
  const renderer = this.renderer;
59217
60409
 
59218
- let output;
60410
+ let sampled;
59219
60411
 
59220
60412
  if ( outputTarget.isArrayTexture ) {
59221
60413
 
59222
60414
  if ( this.backend.isWebGLBackend ) {
59223
60415
 
59224
- output = texture( outputTarget, screenUV ).depth( builtin( 'gl_ViewID_OVR' ) ).renderOutput( renderer.toneMapping, renderer.currentColorSpace );
60416
+ sampled = texture( outputTarget, screenUV ).depth( builtin( 'gl_ViewID_OVR' ) );
59225
60417
 
59226
60418
  } else {
59227
60419
 
59228
- output = texture( outputTarget, screenUV ).depth( _outputLayerIndex ).renderOutput( renderer.toneMapping, renderer.currentColorSpace );
60420
+ sampled = texture( outputTarget, screenUV ).depth( _outputLayerIndex );
59229
60421
 
59230
60422
  }
59231
60423
 
59232
60424
  } else {
59233
60425
 
59234
- output = texture( outputTarget, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace );
60426
+ sampled = texture( outputTarget, screenUV );
59235
60427
 
59236
60428
  }
59237
60429
 
59238
- return output;
60430
+ // WITH_GENESYS
60431
+ if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY || renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS ) {
60432
+
60433
+ const complexity = renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS
60434
+ ? sampled.r.mul( sampled.g ).mul( SHADER_COMPLEXITY_QUAD_COUNT_SCALE )
60435
+ : sampled.r;
60436
+
60437
+ return vec4( colorizeShaderComplexity( complexity ), 1 ).renderOutput( NoToneMapping, renderer.currentColorSpace );
60438
+
60439
+ }
60440
+
60441
+ if ( renderer.debug.view === DEBUG_VIEW_QUAD_OVERDRAW ) {
60442
+
60443
+ return vec4( colorizeQuadOverdraw( sampled.r ), 1 ).renderOutput( NoToneMapping, renderer.currentColorSpace );
60444
+
60445
+ }
60446
+ // !WITH_GENESYS
60447
+
60448
+ return sampled.renderOutput( renderer.toneMapping, renderer.currentColorSpace );
59239
60449
 
59240
60450
  }
59241
60451
 
@@ -63193,6 +64403,10 @@ class Renderer {
63193
64403
  * @property {?Function} onNodeBuilderCreated - A callback function that is executed after a node builder has been created and before it is built.
63194
64404
  * @property {?Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now.
63195
64405
  * @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object.
64406
+ * @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.
64407
+ * @property {string} buffer - Channel drawn by `bufferVisualization`: `baseColor`, `worldNormal`, `roughness`, `metallic`, `ambientOcclusion`, or `emissive`.
64408
+ * @property {number} shaderComplexityBudget - Proxy budget that fills the shader-complexity ramp.
64409
+ * @property {number} quadOverdrawBudget - Overlapping fragments that fill the quad-overdraw ramp.
63196
64410
  */
63197
64411
 
63198
64412
  /**
@@ -63207,6 +64421,12 @@ class Renderer {
63207
64421
  },
63208
64422
  onNodeBuilderCreated: null,
63209
64423
  onShaderError: null,
64424
+ // WITH_GENESYS
64425
+ view: DEBUG_VIEW_NONE,
64426
+ buffer: DEFAULT_BUFFER,
64427
+ shaderComplexityBudget: DEFAULT_SHADER_COMPLEXITY_BUDGET,
64428
+ quadOverdrawBudget: DEFAULT_QUAD_OVERDRAW_BUDGET,
64429
+ // !WITH_GENESYS
63210
64430
  getShaderAsync: async ( scene, camera, object ) => {
63211
64431
 
63212
64432
  await this.compileAsync( object, camera, scene );
@@ -65141,7 +66361,11 @@ class Renderer {
65141
66361
  const useToneMapping = this.currentToneMapping !== NoToneMapping;
65142
66362
  const useColorSpace = this.currentColorSpace !== ColorManagement.workingColorSpace;
65143
66363
 
65144
- return useToneMapping || useColorSpace;
66364
+ // WITH_GENESYS
66365
+ // Accumulating views write a scalar into an intermediate target, then the output pass colorizes it.
66366
+ return useToneMapping || useColorSpace || debugViewAccumulates( this.debug.view );
66367
+ // !WITH_GENESYS
66368
+ // return useToneMapping || useColorSpace;
65145
66369
 
65146
66370
  }
65147
66371
 
@@ -65192,6 +66416,16 @@ class Renderer {
65192
66416
  */
65193
66417
  get currentToneMapping() {
65194
66418
 
66419
+ // WITH_GENESYS
66420
+ const view = this.debug.view;
66421
+
66422
+ 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 ) {
66423
+
66424
+ return NoToneMapping;
66425
+
66426
+ }
66427
+ // !WITH_GENESYS
66428
+
65195
66429
  return this.isOutputTarget ? this.toneMapping : NoToneMapping;
65196
66430
 
65197
66431
  }
@@ -68508,6 +69742,10 @@ ${ flowData.code }
68508
69742
  */
68509
69743
  generateTexture( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet ) {
68510
69744
 
69745
+ // WITH_GENESYS
69746
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet );
69747
+ // !WITH_GENESYS
69748
+
68511
69749
  if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`;
68512
69750
 
68513
69751
  if ( texture.isDepthTexture ) {
@@ -68551,6 +69789,10 @@ ${ flowData.code }
68551
69789
  */
68552
69790
  generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ) {
68553
69791
 
69792
+ // WITH_GENESYS
69793
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
69794
+ // !WITH_GENESYS
69795
+
68554
69796
  if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`;
68555
69797
 
68556
69798
  if ( offsetSnippet ) {
@@ -70981,6 +72223,8 @@ class WebGLAttributeUtils {
70981
72223
 
70982
72224
  }
70983
72225
 
72226
+ // !WITH_GENESYS
72227
+
70984
72228
  let equationToGL, factorToGL;
70985
72229
 
70986
72230
  /**
@@ -71903,9 +73147,25 @@ class WebGLState {
71903
73147
 
71904
73148
  this.setFlipSided( flipSided );
71905
73149
 
71906
- ( material.blending === NormalBlending && material.transparent === false )
71907
- ? this.setBlending( NoBlending )
71908
- : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
73150
+ // WITH_GENESYS
73151
+ // WebGL has no cached render pipeline. One+One is applied on each draw instead.
73152
+ if ( debugViewAccumulates( this.backend.renderer.debug.view ) && material.isShadowPassMaterial !== true && this.backend.renderer.isOutputTarget !== true ) {
73153
+
73154
+ this.setBlending( AdditiveBlending, AddEquation, OneFactor, OneFactor, AddEquation, OneFactor, OneFactor, material.blendColor, material.blendAlpha, true );
73155
+
73156
+ } else if ( material.blending === NormalBlending && material.transparent === false ) {
73157
+
73158
+ this.setBlending( NoBlending );
73159
+
73160
+ } else {
73161
+
73162
+ this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
73163
+
73164
+ }
73165
+ // !WITH_GENESYS
73166
+ // ( material.blending === NormalBlending && material.transparent === false )
73167
+ // ? this.setBlending( NoBlending )
73168
+ // : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
71909
73169
 
71910
73170
  this.setDepthFunc( material.depthFunc );
71911
73171
  this.setDepthTest( material.depthTest );
@@ -82774,6 +84034,10 @@ class WGSLNodeBuilder extends NodeBuilder {
82774
84034
  */
82775
84035
  _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) {
82776
84036
 
84037
+ // WITH_GENESYS
84038
+ if ( shaderStage === 'fragment' ) this.recordFragmentTextureSample( texture, shaderStage, textureProperty + '|' + uvSnippet );
84039
+ // !WITH_GENESYS
84040
+
82777
84041
  if ( shaderStage === 'fragment' ) {
82778
84042
 
82779
84043
  if ( depthSnippet ) {
@@ -83054,6 +84318,10 @@ class WGSLNodeBuilder extends NodeBuilder {
83054
84318
  */
83055
84319
  generateFilteredTexture( texture, textureProperty, uvSnippet, offsetSnippet, levelSnippet = '0u', depthSnippet ) {
83056
84320
 
84321
+ // WITH_GENESYS
84322
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
84323
+ // !WITH_GENESYS
84324
+
83057
84325
  const wrapFunction = this.generateWrapFunction( texture );
83058
84326
  const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet );
83059
84327
 
@@ -83091,6 +84359,10 @@ class WGSLNodeBuilder extends NodeBuilder {
83091
84359
  */
83092
84360
  generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet = '0u' ) {
83093
84361
 
84362
+ // WITH_GENESYS
84363
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
84364
+ // !WITH_GENESYS
84365
+
83094
84366
  // Cube textures cannot use textureLoad in WGSL, must use textureSampleLevel
83095
84367
  if ( texture.isCubeTexture === true ) {
83096
84368
 
@@ -83469,6 +84741,10 @@ class WGSLNodeBuilder extends NodeBuilder {
83469
84741
 
83470
84742
  if ( this.isUnfilterable( texture ) === false ) {
83471
84743
 
84744
+ // WITH_GENESYS
84745
+ this.recordFragmentTextureSample( texture, this.shaderStage, textureProperty + '|' + uvSnippet + '|' + levelSnippet );
84746
+ // !WITH_GENESYS
84747
+
83472
84748
  if ( depthSnippet ) {
83473
84749
 
83474
84750
  if ( offsetSnippet ) {
@@ -86576,6 +87852,26 @@ class WebGPUPipelineUtils {
86576
87852
 
86577
87853
  }
86578
87854
 
87855
+ // WITH_GENESYS
87856
+ // Accumulate shader cost with One+One. Opaque materials normally disable blending.
87857
+ if ( debugViewAccumulates( backend.renderer.debug.view ) && material.isShadowPassMaterial !== true && backend.renderer.isOutputTarget !== true ) {
87858
+
87859
+ materialBlending = {
87860
+ color: {
87861
+ srcFactor: GPUBlendFactor.One,
87862
+ dstFactor: GPUBlendFactor.One,
87863
+ operation: GPUBlendOperation.Add
87864
+ },
87865
+ alpha: {
87866
+ srcFactor: GPUBlendFactor.One,
87867
+ dstFactor: GPUBlendFactor.One,
87868
+ operation: GPUBlendOperation.Add
87869
+ }
87870
+ };
87871
+
87872
+ }
87873
+ // !WITH_GENESYS
87874
+
86579
87875
  // stencil
86580
87876
 
86581
87877
  let stencilFront = {};
@@ -90378,6 +91674,9 @@ class WebGPUBackend extends Backend {
90378
91674
  const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context );
90379
91675
  const primitiveTopology = utils.getPrimitiveTopology( object, material );
90380
91676
  const frontFaceCW = ( object.isMesh && object.matrixWorld.determinantAffine() < 0 );
91677
+ // WITH_GENESYS
91678
+ const debugView = renderObject.renderer.debug.view;
91679
+ // !WITH_GENESYS
90381
91680
 
90382
91681
  let needsUpdate = false;
90383
91682
 
@@ -90395,7 +91694,10 @@ class WebGPUBackend extends Backend {
90395
91694
  data.colorFormat !== colorFormat || data.depthStencilFormat !== depthStencilFormat ||
90396
91695
  data.primitiveTopology !== primitiveTopology ||
90397
91696
  data.frontFaceCW !== frontFaceCW ||
90398
- data.clippingContextCacheKey !== renderObject.clippingContextCacheKey
91697
+ data.clippingContextCacheKey !== renderObject.clippingContextCacheKey ||
91698
+ // WITH_GENESYS
91699
+ data.debugView !== debugView
91700
+ // !WITH_GENESYS
90399
91701
  ) {
90400
91702
 
90401
91703
  data.material = material; data.materialVersion = material.version;
@@ -90416,6 +91718,9 @@ class WebGPUBackend extends Backend {
90416
91718
  data.primitiveTopology = primitiveTopology;
90417
91719
  data.frontFaceCW = frontFaceCW;
90418
91720
  data.clippingContextCacheKey = renderObject.clippingContextCacheKey;
91721
+ // WITH_GENESYS
91722
+ data.debugView = debugView;
91723
+ // !WITH_GENESYS
90419
91724
 
90420
91725
  needsUpdate = true;
90421
91726
 
@@ -90459,7 +91764,10 @@ class WebGPUBackend extends Backend {
90459
91764
  utils.getCurrentColorSpace( renderContext ), utils.getCurrentColorFormat( renderContext ), utils.getCurrentDepthStencilFormat( renderContext ),
90460
91765
  utils.getPrimitiveTopology( object, material ),
90461
91766
  renderObject.getGeometryCacheKey(),
90462
- renderObject.clippingContextCacheKey
91767
+ renderObject.clippingContextCacheKey,
91768
+ // WITH_GENESYS
91769
+ renderObject.renderer.debug.view
91770
+ // !WITH_GENESYS
90463
91771
  ].join();
90464
91772
 
90465
91773
  }