@gnsx/three 0.186.4 → 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.
@@ -137,12 +137,20 @@ class Settings extends Parameters {
137
137
  // WITH_GENESYS
138
138
  // Values match Renderer.debug.view. Not stored with inspector settings.
139
139
  const debugViewState = { view: 'none' };
140
+ const bufferState = { buffer: 'baseColor' };
140
141
 
141
142
  this._debugViewState = debugViewState;
143
+ this._bufferState = bufferState;
142
144
  this._debugViewControl = modesGroup.add( debugViewState, 'view', {
143
145
  'Shaded': 'none',
144
146
  'Shader Complexity': 'shaderComplexity',
145
- 'Lighting Complexity': 'lightingComplexity'
147
+ 'Lighting Complexity': 'lightingComplexity',
148
+ 'Quad Overdraw': 'quadOverdraw',
149
+ 'Shader Complexity & Quads': 'shaderComplexityAndQuads',
150
+ 'Buffer Visualization': 'bufferVisualization',
151
+ 'Lighting Only': 'lightingOnly',
152
+ 'Detail Lighting': 'detailLighting',
153
+ 'Draw Call': 'drawCall'
146
154
  } ).name( 'Debug View' ).onChange( ( view ) => {
147
155
 
148
156
  const renderer = this.inspector.getRenderer();
@@ -150,9 +158,30 @@ class Settings extends Parameters {
150
158
  if ( renderer === null || renderer.debug === undefined ) return;
151
159
 
152
160
  renderer.debug.view = view;
161
+ this._syncBufferRow( view );
153
162
  window.dispatchEvent( new Event( 'genesys-debug-view' ) );
154
163
 
155
- } ).info( 'Shaded color, a shader-cost heatmap, or a direct-light count. Overdraw draws on top when both are enabled.' );
164
+ } ).info( 'Shaded color, a cost heatmap, per-pixel overdraw, shader cost times overdraw, one material channel, lighting on a flat gray surface, or one lit color per draw. The Overdraw toggle above draws on top when both are enabled.' );
165
+
166
+ this._bufferControl = modesGroup.add( bufferState, 'buffer', {
167
+ 'Base Color': 'baseColor',
168
+ 'World Normal': 'worldNormal',
169
+ 'Roughness': 'roughness',
170
+ 'Metallic': 'metallic',
171
+ 'Ambient Occlusion': 'ambientOcclusion',
172
+ 'Emissive': 'emissive'
173
+ } ).name( 'Buffer' ).onChange( ( buffer ) => {
174
+
175
+ const renderer = this.inspector.getRenderer();
176
+
177
+ if ( renderer === null || renderer.debug === undefined ) return;
178
+
179
+ renderer.debug.buffer = buffer;
180
+ window.dispatchEvent( new Event( 'genesys-debug-view' ) );
181
+
182
+ } ).info( 'Channel drawn by Buffer Visualization. Base color, world normal, roughness, metallic, ambient occlusion, or emissive.' );
183
+
184
+ this._bufferControl.hide();
156
185
  // !WITH_GENESYS
157
186
 
158
187
  }
@@ -163,7 +192,7 @@ class Settings extends Parameters {
163
192
  const renderer = this.inspector.getRenderer();
164
193
  const view = renderer !== null && renderer.debug !== undefined ? renderer.debug.view : null;
165
194
 
166
- if ( view === 'none' || view === 'shaderComplexity' || view === 'lightingComplexity' ) {
195
+ if ( view === 'none' || view === 'shaderComplexity' || view === 'lightingComplexity' || view === 'quadOverdraw' || view === 'shaderComplexityAndQuads' || view === 'bufferVisualization' || view === 'lightingOnly' || view === 'detailLighting' || view === 'drawCall' ) {
167
196
 
168
197
  if ( this._debugViewState.view !== view ) {
169
198
 
@@ -171,6 +200,17 @@ class Settings extends Parameters {
171
200
 
172
201
  }
173
202
 
203
+ this._syncBufferRow( view );
204
+
205
+ }
206
+
207
+ const buffer = renderer !== null && renderer.debug !== undefined ? renderer.debug.buffer : null;
208
+ const buffers = [ 'baseColor', 'worldNormal', 'roughness', 'metallic', 'ambientOcclusion', 'emissive' ];
209
+
210
+ if ( buffers.includes( buffer ) && this._bufferState.buffer !== buffer ) {
211
+
212
+ this._bufferControl.setValue( buffer );
213
+
174
214
  }
175
215
  // !WITH_GENESYS
176
216
 
@@ -257,6 +297,27 @@ Shares the same state across any page within the current origin.` );
257
297
 
258
298
  }
259
299
 
300
+ // WITH_GENESYS
301
+ /**
302
+ * Shows the buffer channel row only while buffer visualization is the debug view.
303
+ *
304
+ * @param {string} view - `renderer.debug.view`.
305
+ */
306
+ _syncBufferRow( view ) {
307
+
308
+ if ( view === 'bufferVisualization' ) {
309
+
310
+ this._bufferControl.show();
311
+
312
+ } else {
313
+
314
+ this._bufferControl.hide();
315
+
316
+ }
317
+
318
+ }
319
+ // !WITH_GENESYS
320
+
260
321
  async setActiveExtension( name, value ) {
261
322
 
262
323
  const extension = this.extensions[ name ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gnsx/three",
3
- "version": "0.186.4",
3
+ "version": "0.186.5",
4
4
  "description": "JavaScript 3D library",
5
5
  "type": "module",
6
6
  "main": "./build/three.cjs",
@@ -118,6 +118,19 @@ class MeshBasicNodeMaterial extends NodeMaterial {
118
118
 
119
119
  }
120
120
 
121
+ // WITH_GENESYS
122
+ /**
123
+ * Shader-complexity proxy for {@link BasicLightingModel}.
124
+ *
125
+ * @return {number} The base cost, excluding texture samples.
126
+ */
127
+ getShaderComplexity() {
128
+
129
+ return 80;
130
+
131
+ }
132
+ // !WITH_GENESYS
133
+
121
134
  /**
122
135
  * Setups the lighting model.
123
136
  *
@@ -66,6 +66,19 @@ class MeshLambertNodeMaterial extends NodeMaterial {
66
66
 
67
67
  }
68
68
 
69
+ // WITH_GENESYS
70
+ /**
71
+ * Shader-complexity proxy for Lambert. Specular is forced off.
72
+ *
73
+ * @return {number} The base cost, excluding texture samples.
74
+ */
75
+ getShaderComplexity() {
76
+
77
+ return 140;
78
+
79
+ }
80
+ // !WITH_GENESYS
81
+
69
82
  /**
70
83
  * Setups the lighting model.
71
84
  *
@@ -46,6 +46,19 @@ class MeshMatcapNodeMaterial extends NodeMaterial {
46
46
 
47
47
  }
48
48
 
49
+ // WITH_GENESYS
50
+ /**
51
+ * Shader-complexity proxy for matcap UV shading.
52
+ *
53
+ * @return {number} The base cost, excluding texture samples.
54
+ */
55
+ getShaderComplexity() {
56
+
57
+ return 50;
58
+
59
+ }
60
+ // !WITH_GENESYS
61
+
49
62
  /**
50
63
  * Setups the matcap specific node variables.
51
64
  *
@@ -95,6 +95,19 @@ class MeshPhongNodeMaterial extends NodeMaterial {
95
95
 
96
96
  }
97
97
 
98
+ // WITH_GENESYS
99
+ /**
100
+ * Shader-complexity proxy for Blinn-Phong.
101
+ *
102
+ * @return {number} The base cost, excluding texture samples.
103
+ */
104
+ getShaderComplexity() {
105
+
106
+ return 200;
107
+
108
+ }
109
+ // !WITH_GENESYS
110
+
98
111
  /**
99
112
  * Setups the lighting model.
100
113
  *
@@ -383,6 +383,31 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
383
383
 
384
384
  }
385
385
 
386
+ // WITH_GENESYS
387
+ /**
388
+ * GGX base from {@link MeshStandardNodeMaterial}, plus each enabled physical feature.
389
+ *
390
+ * @return {number} The base cost, excluding texture samples.
391
+ */
392
+ getShaderComplexity() {
393
+
394
+ let cost = super.getShaderComplexity();
395
+
396
+ if ( this.useClearcoat === true ) cost += 30;
397
+
398
+ if ( this.useSheen === true ) cost += 30;
399
+
400
+ if ( this.useIridescence === true ) cost += 30;
401
+
402
+ if ( this.useAnisotropy === true ) cost += 30;
403
+
404
+ if ( this.useTransmission === true ) cost += 60;
405
+
406
+ return cost;
407
+
408
+ }
409
+ // !WITH_GENESYS
410
+
386
411
  /**
387
412
  * Setups the lighting model.
388
413
  *
@@ -146,6 +146,21 @@ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial {
146
146
 
147
147
  }
148
148
 
149
+ // WITH_GENESYS
150
+ /**
151
+ * Physical complexity, plus the subsurface term when it is evaluated.
152
+ *
153
+ * @return {number} The base cost, excluding texture samples.
154
+ */
155
+ getShaderComplexity() {
156
+
157
+ const cost = super.getShaderComplexity();
158
+
159
+ return this.useSSS === true ? cost + 40 : cost;
160
+
161
+ }
162
+ // !WITH_GENESYS
163
+
149
164
  /**
150
165
  * Setups the lighting model.
151
166
  *
@@ -117,6 +117,19 @@ class MeshStandardNodeMaterial extends NodeMaterial {
117
117
 
118
118
  }
119
119
 
120
+ // WITH_GENESYS
121
+ /**
122
+ * Shader-complexity proxy for the Cook-Torrance GGX model.
123
+ *
124
+ * @return {number} The base cost, excluding texture samples.
125
+ */
126
+ getShaderComplexity() {
127
+
128
+ return 240;
129
+
130
+ }
131
+ // !WITH_GENESYS
132
+
120
133
  /**
121
134
  * Setups the lighting model.
122
135
  *
@@ -50,6 +50,19 @@ class MeshToonNodeMaterial extends NodeMaterial {
50
50
 
51
51
  }
52
52
 
53
+ // WITH_GENESYS
54
+ /**
55
+ * Shader-complexity proxy for toon banding.
56
+ *
57
+ * @return {number} The base cost, excluding texture samples.
58
+ */
59
+ getShaderComplexity() {
60
+
61
+ return 170;
62
+
63
+ }
64
+ // !WITH_GENESYS
65
+
53
66
  /**
54
67
  * Setups the lighting model.
55
68
  *
@@ -26,7 +26,10 @@ import { vertexColor } from '../../nodes/accessors/VertexColorNode.js';
26
26
  import { premultiplyAlpha } from '../../nodes/display/PremultiplyAlphaFunctions.js';
27
27
  import { subBuild } from '../../nodes/core/SubBuildNode.js';
28
28
  // WITH_GENESYS
29
- import { DEBUG_VIEW_LIGHTING_COMPLEXITY, DEBUG_VIEW_SHADER_COMPLEXITY, getShaderComplexityBase, shaderComplexityOutput } from '../../nodes/display/ComplexityDebug.js';
29
+ import { DEBUG_VIEW_LIGHTING_COMPLEXITY, DEBUG_VIEW_QUAD_OVERDRAW, DEBUG_VIEW_SHADER_COMPLEXITY, DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS, quadOverdrawOutput, shaderComplexityAndQuadsOutput, shaderComplexityOutput } from '../../nodes/display/ComplexityDebug.js';
30
+ import { DEBUG_VIEW_BUFFER, assignBufferDefaults, bufferVisualizationOutput } from '../../nodes/display/BufferDebug.js';
31
+ import { DEBUG_VIEW_DETAIL_LIGHTING, DEBUG_VIEW_LIGHTING_ONLY, applyLightingDebug, lightingOnlyNormal } from '../../nodes/display/LightingDebug.js';
32
+ import { DEBUG_VIEW_DRAW_CALL, applyDrawCallDebug } from '../../nodes/display/DrawCallDebug.js';
30
33
  // !WITH_GENESYS
31
34
 
32
35
  /**
@@ -527,10 +530,33 @@ class NodeMaterial extends Material {
527
530
 
528
531
  if ( this.fragmentNode === null ) {
529
532
 
533
+ // WITH_GENESYS
534
+ // Fallback for materials that never write the channel. Lit materials overwrite these.
535
+ if ( renderer.debug.view === DEBUG_VIEW_BUFFER && this.isShadowPassMaterial !== true ) {
536
+
537
+ assignBufferDefaults( renderer.debug.buffer );
538
+
539
+ }
540
+ // !WITH_GENESYS
541
+
530
542
  this.setupDiffuseColor( builder );
531
543
  this.setupAmbientOcclusion( builder );
532
544
  this.setupVariants( builder );
533
545
 
546
+ // WITH_GENESYS
547
+ // After the material writes its channels, so roughness and normals already exist
548
+ // for detail lighting and can be replaced for lighting only.
549
+ if ( ( renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || renderer.debug.view === DEBUG_VIEW_DETAIL_LIGHTING ) && this.isShadowPassMaterial !== true ) {
550
+
551
+ applyLightingDebug( builder, renderer.debug.view );
552
+
553
+ } else if ( renderer.debug.view === DEBUG_VIEW_DRAW_CALL && this.isShadowPassMaterial !== true ) {
554
+
555
+ applyDrawCallDebug( builder );
556
+
557
+ }
558
+ // !WITH_GENESYS
559
+
534
560
  const outgoingLightNode = this.setupLighting( builder );
535
561
 
536
562
  if ( clippingNode !== null ) builder.stack.addToStack( clippingNode );
@@ -605,9 +631,24 @@ class NodeMaterial extends Material {
605
631
  // would replace the heatmap with this material's own constant cost.
606
632
  if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY && this.isShadowPassMaterial !== true && renderer.isOutputTarget !== true ) {
607
633
 
608
- builder.shaderComplexityBase = getShaderComplexityBase( this );
634
+ builder.shaderComplexityBase = this.getShaderComplexity();
609
635
  resultNode = shaderComplexityOutput( resultNode );
610
636
 
637
+ } else if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_QUADS && this.isShadowPassMaterial !== true && renderer.isOutputTarget !== true ) {
638
+
639
+ builder.shaderComplexityBase = this.getShaderComplexity();
640
+ resultNode = shaderComplexityAndQuadsOutput( resultNode );
641
+
642
+ } else if ( renderer.debug.view === DEBUG_VIEW_QUAD_OVERDRAW && this.isShadowPassMaterial !== true && renderer.isOutputTarget !== true ) {
643
+
644
+ resultNode = quadOverdrawOutput( resultNode );
645
+
646
+ } else if ( renderer.debug.view === DEBUG_VIEW_BUFFER && this.isShadowPassMaterial !== true && this.fragmentNode === null ) {
647
+
648
+ // The fullscreen output pass sets fragmentNode. Scene materials do not, including
649
+ // when the scene is drawn straight to the canvas.
650
+ resultNode = bufferVisualizationOutput( renderer.debug.buffer );
651
+
611
652
  }
612
653
  // !WITH_GENESYS
613
654
 
@@ -621,6 +662,21 @@ class NodeMaterial extends Material {
621
662
 
622
663
  }
623
664
 
665
+ // WITH_GENESYS
666
+ /**
667
+ * Static shader-complexity proxy for this material's lighting model.
668
+ * Fragment texture samples are counted later, while the shader is generated.
669
+ * Derived materials override this instead of registering a type flag.
670
+ *
671
+ * @return {number} The base cost, excluding texture samples.
672
+ */
673
+ getShaderComplexity() {
674
+
675
+ return this.lights === true ? 40 : 20;
676
+
677
+ }
678
+ // !WITH_GENESYS
679
+
624
680
  /**
625
681
  * Setups the clipping node.
626
682
  *
@@ -945,9 +1001,18 @@ class NodeMaterial extends Material {
945
1001
  /**
946
1002
  * Setups the normal node from the material.
947
1003
  *
1004
+ * @param {NodeBuilder} builder - The current node builder.
948
1005
  * @return {Node<vec3>} The normal node.
949
1006
  */
950
- setupNormal() {
1007
+ setupNormal( builder ) {
1008
+
1009
+ // WITH_GENESYS
1010
+ if ( ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || builder.renderer.debug.view === DEBUG_VIEW_DRAW_CALL ) && this.isShadowPassMaterial !== true && this.fragmentNode === null ) {
1011
+
1012
+ return lightingOnlyNormal();
1013
+
1014
+ }
1015
+ // !WITH_GENESYS
951
1016
 
952
1017
  return this.normalNode ? vec3( this.normalNode ) : materialNormal;
953
1018
 
@@ -1144,6 +1209,16 @@ class NodeMaterial extends Material {
1144
1209
 
1145
1210
  if ( ( emissiveNode && emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) {
1146
1211
 
1212
+ // WITH_GENESYS
1213
+ // Lighting only and draw call substitute a plain lit material, so emissive is dropped.
1214
+ // Detail lighting keeps it.
1215
+ if ( ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || builder.renderer.debug.view === DEBUG_VIEW_DRAW_CALL ) && this.isShadowPassMaterial !== true ) {
1216
+
1217
+ return outgoingLightNode;
1218
+
1219
+ }
1220
+ // !WITH_GENESYS
1221
+
1147
1222
  emissive.assign( vec3( emissiveNode ? emissiveNode : materialEmissive ) );
1148
1223
 
1149
1224
  outgoingLightNode = outgoingLightNode.add( emissive );
@@ -60,6 +60,19 @@ class ShadowNodeMaterial extends NodeMaterial {
60
60
 
61
61
  }
62
62
 
63
+ // WITH_GENESYS
64
+ /**
65
+ * Shader-complexity proxy for the shadow mask.
66
+ *
67
+ * @return {number} The base cost, excluding texture samples.
68
+ */
69
+ getShaderComplexity() {
70
+
71
+ return 110;
72
+
73
+ }
74
+ // !WITH_GENESYS
75
+
63
76
  /**
64
77
  * Setups the lighting model.
65
78
  *
@@ -70,6 +70,19 @@ class VolumeNodeMaterial extends NodeMaterial {
70
70
 
71
71
  }
72
72
 
73
+ // WITH_GENESYS
74
+ /**
75
+ * Shader-complexity proxy for volumetric ray integration.
76
+ *
77
+ * @return {number} The base cost, excluding texture samples.
78
+ */
79
+ getShaderComplexity() {
80
+
81
+ return 280;
82
+
83
+ }
84
+ // !WITH_GENESYS
85
+
73
86
  setupLightingModel() {
74
87
 
75
88
  return new VolumetricLightingModel();
@@ -0,0 +1,143 @@
1
+ // WITH_GENESYS
2
+ // Buffer visualization. Shows one material channel in place of the shaded color.
3
+ // !WITH_GENESYS
4
+
5
+ import { diffuseColor, ambientOcclusion, emissive, metalness, roughness } from '../core/PropertyNode.js';
6
+ import { normalWorld } from '../accessors/Normal.js';
7
+ import { float, vec3, vec4 } from '../tsl/TSLCore.js';
8
+
9
+ /**
10
+ * Buffer visualization. The visible surface wins, and one material channel replaces the shaded color.
11
+ *
12
+ * @type {string}
13
+ */
14
+ export const DEBUG_VIEW_BUFFER = 'bufferVisualization';
15
+
16
+ /**
17
+ * Albedo before lighting, including maps and vertex colors.
18
+ *
19
+ * @type {string}
20
+ */
21
+ export const BUFFER_BASE_COLOR = 'baseColor';
22
+
23
+ /**
24
+ * Shading normal in world space, packed to RGB with `n * 0.5 + 0.5`.
25
+ *
26
+ * @type {string}
27
+ */
28
+ export const BUFFER_WORLD_NORMAL = 'worldNormal';
29
+
30
+ /**
31
+ * Scalar roughness used by the lighting model. Black is smooth.
32
+ *
33
+ * @type {string}
34
+ */
35
+ export const BUFFER_ROUGHNESS = 'roughness';
36
+
37
+ /**
38
+ * Scalar metalness. White is metal. Unreal calls this buffer Metallic.
39
+ *
40
+ * @type {string}
41
+ */
42
+ export const BUFFER_METALLIC = 'metallic';
43
+
44
+ /**
45
+ * Material ambient occlusion. White means no occlusion map.
46
+ *
47
+ * @type {string}
48
+ */
49
+ export const BUFFER_AMBIENT_OCCLUSION = 'ambientOcclusion';
50
+
51
+ /**
52
+ * Emissive color before it is added to the lit result.
53
+ *
54
+ * @type {string}
55
+ */
56
+ export const BUFFER_EMISSIVE = 'emissive';
57
+
58
+ /**
59
+ * Channel drawn when buffer visualization is first enabled.
60
+ *
61
+ * @type {string}
62
+ */
63
+ export const DEFAULT_BUFFER = BUFFER_BASE_COLOR;
64
+
65
+ /**
66
+ * Writes a defined value for channels a material may never assign.
67
+ * Standard and physical materials overwrite roughness and metalness in `setupVariants`,
68
+ * and emissive is overwritten when the material has one.
69
+ *
70
+ * @param {string} buffer - `renderer.debug.buffer`.
71
+ */
72
+ export function assignBufferDefaults( buffer ) {
73
+
74
+ if ( buffer === BUFFER_ROUGHNESS ) {
75
+
76
+ roughness.assign( float( 0 ) );
77
+
78
+ } else if ( buffer === BUFFER_METALLIC ) {
79
+
80
+ metalness.assign( float( 0 ) );
81
+
82
+ } else if ( buffer === BUFFER_EMISSIVE ) {
83
+
84
+ emissive.assign( vec3( 0 ) );
85
+
86
+ }
87
+
88
+ }
89
+
90
+ /**
91
+ * The color for one buffer channel. Scalar channels are copied into RGB.
92
+ *
93
+ * @param {string} buffer - `renderer.debug.buffer`.
94
+ * @return {Node<vec3>} The channel color.
95
+ */
96
+ export function bufferVisualizationColor( buffer ) {
97
+
98
+ if ( buffer === BUFFER_WORLD_NORMAL ) {
99
+
100
+ return normalWorld.mul( 0.5 ).add( 0.5 );
101
+
102
+ }
103
+
104
+ if ( buffer === BUFFER_ROUGHNESS ) {
105
+
106
+ return vec3( roughness );
107
+
108
+ }
109
+
110
+ if ( buffer === BUFFER_METALLIC ) {
111
+
112
+ return vec3( metalness );
113
+
114
+ }
115
+
116
+ if ( buffer === BUFFER_AMBIENT_OCCLUSION ) {
117
+
118
+ return vec3( ambientOcclusion );
119
+
120
+ }
121
+
122
+ if ( buffer === BUFFER_EMISSIVE ) {
123
+
124
+ return emissive;
125
+
126
+ }
127
+
128
+ return diffuseColor.rgb;
129
+
130
+ }
131
+
132
+ /**
133
+ * Replaces the shaded color with the selected buffer. Alpha stays the material's coverage
134
+ * so masked and transparent surfaces keep their shape.
135
+ *
136
+ * @param {string} buffer - `renderer.debug.buffer`.
137
+ * @return {Node<vec4>} The buffer color.
138
+ */
139
+ export function bufferVisualizationOutput( buffer ) {
140
+
141
+ return vec4( bufferVisualizationColor( buffer ), diffuseColor.a );
142
+
143
+ }