@gnsx/three 0.186.5 → 0.186.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/three.webgpu.js +1454 -917
- package/build/three.webgpu.nodes.js +1454 -917
- package/examples/jsm/inspector/tabs/Settings.js +9 -6
- package/package.json +1 -1
- package/src/materials/nodes/NodeMaterial.js +56 -16
- package/src/nodes/display/ComplexityDebug.js +56 -7
- package/src/nodes/display/DoubleSideDebug.js +152 -0
- package/src/nodes/display/DrawCallDebug.js +3 -2
- package/src/nodes/display/FrontBackFaceDebug.js +88 -0
- package/src/nodes/display/LightingDebug.js +3 -2
- package/src/nodes/display/ShadowCasterDebug.js +69 -0
- package/src/renderers/common/Background.js +3 -1
- package/src/renderers/common/RenderObject.js +1 -1
- package/src/renderers/common/RenderPipeline.js +34 -5
- package/src/renderers/common/Renderer.js +90 -8
- package/src/renderers/common/nodes/NodeManager.js +4 -4
- package/src/renderers/webgl-fallback/WebGLBackend.js +8 -2
- package/src/renderers/webgl-fallback/utils/WebGLState.js +37 -7
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +16 -6
|
@@ -143,14 +143,17 @@ class Settings extends Parameters {
|
|
|
143
143
|
this._bufferState = bufferState;
|
|
144
144
|
this._debugViewControl = modesGroup.add( debugViewState, 'view', {
|
|
145
145
|
'Shaded': 'none',
|
|
146
|
+
'Draw Call': 'drawCall',
|
|
146
147
|
'Shader Complexity': 'shaderComplexity',
|
|
147
148
|
'Lighting Complexity': 'lightingComplexity',
|
|
148
|
-
'
|
|
149
|
-
'
|
|
150
|
-
'
|
|
149
|
+
'Shadow Caster': 'shadowCaster',
|
|
150
|
+
'Double Side': 'doubleSide',
|
|
151
|
+
'Overdraw': 'overdraw',
|
|
152
|
+
'Shader Complexity & Overdraw': 'shaderComplexityAndOverdraw',
|
|
151
153
|
'Lighting Only': 'lightingOnly',
|
|
152
154
|
'Detail Lighting': 'detailLighting',
|
|
153
|
-
'
|
|
155
|
+
'Front/Back Face': 'frontBackFace',
|
|
156
|
+
'Buffer Visualization': 'bufferVisualization',
|
|
154
157
|
} ).name( 'Debug View' ).onChange( ( view ) => {
|
|
155
158
|
|
|
156
159
|
const renderer = this.inspector.getRenderer();
|
|
@@ -161,7 +164,7 @@ class Settings extends Parameters {
|
|
|
161
164
|
this._syncBufferRow( view );
|
|
162
165
|
window.dispatchEvent( new Event( 'genesys-debug-view' ) );
|
|
163
166
|
|
|
164
|
-
} ).info( 'Shaded color, a cost heatmap, per-pixel overdraw, shader cost times overdraw, one material channel, lighting on a flat gray surface,
|
|
167
|
+
} ).info( 'Shaded color, a cost heatmap, per-pixel overdraw, shader cost times overdraw, one material channel, lighting on a flat gray surface, one lit color per draw, a tint for the front and back of each face, green and gray for objects that do and do not cast shadows, or red where a double-sided back face is hidden. The Overdraw toggle above draws on top when both are enabled.' );
|
|
165
168
|
|
|
166
169
|
this._bufferControl = modesGroup.add( bufferState, 'buffer', {
|
|
167
170
|
'Base Color': 'baseColor',
|
|
@@ -192,7 +195,7 @@ class Settings extends Parameters {
|
|
|
192
195
|
const renderer = this.inspector.getRenderer();
|
|
193
196
|
const view = renderer !== null && renderer.debug !== undefined ? renderer.debug.view : null;
|
|
194
197
|
|
|
195
|
-
if ( view === 'none' || view === 'shaderComplexity' || view === 'lightingComplexity' || view === '
|
|
198
|
+
if ( view === 'none' || view === 'shaderComplexity' || view === 'lightingComplexity' || view === 'overdraw' || view === 'shaderComplexityAndOverdraw' || view === 'bufferVisualization' || view === 'lightingOnly' || view === 'detailLighting' || view === 'drawCall' || view === 'frontBackFace' || view === 'shadowCaster' || view === 'doubleSide' ) {
|
|
196
199
|
|
|
197
200
|
if ( this._debugViewState.view !== view ) {
|
|
198
201
|
|
package/package.json
CHANGED
|
@@ -26,10 +26,33 @@ 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,
|
|
29
|
+
import { DEBUG_VIEW_LIGHTING_COMPLEXITY, DEBUG_VIEW_SHADER_COMPLEXITY, DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW, debugDrawAccumulates, quadOverdrawOutput, shaderComplexityAndOverdrawOutput, shaderComplexityOutput } from '../../nodes/display/ComplexityDebug.js';
|
|
30
|
+
import { mrt } from '../../nodes/core/MRTNode.js';
|
|
30
31
|
import { DEBUG_VIEW_BUFFER, assignBufferDefaults, bufferVisualizationOutput } from '../../nodes/display/BufferDebug.js';
|
|
31
32
|
import { DEBUG_VIEW_DETAIL_LIGHTING, DEBUG_VIEW_LIGHTING_ONLY, applyLightingDebug, lightingOnlyNormal } from '../../nodes/display/LightingDebug.js';
|
|
32
33
|
import { DEBUG_VIEW_DRAW_CALL, applyDrawCallDebug } from '../../nodes/display/DrawCallDebug.js';
|
|
34
|
+
import { DEBUG_VIEW_FRONT_BACK_FACE, applyFrontBackFaceDebug } from '../../nodes/display/FrontBackFaceDebug.js';
|
|
35
|
+
import { DEBUG_VIEW_SHADOW_CASTER, applyShadowCasterDebug } from '../../nodes/display/ShadowCasterDebug.js';
|
|
36
|
+
import { DEBUG_VIEW_DOUBLE_SIDE, applyDoubleSideDebug } from '../../nodes/display/DoubleSideDebug.js';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Replaces the color a material writes with a debug output. With MRT, only the `output`
|
|
40
|
+
* attachment is replaced so the other attachments keep their members. Converting the
|
|
41
|
+
* whole MRT struct to a color leaves WGSL with an empty output struct.
|
|
42
|
+
*
|
|
43
|
+
* @param {Node} resultNode - The material's fragment result, possibly an MRT node.
|
|
44
|
+
* @param {function(Node): Node} createOutput - Builds the debug color from the shaded color.
|
|
45
|
+
* @return {Node} The fragment result with the debug color in place.
|
|
46
|
+
*/
|
|
47
|
+
function replaceColorOutput( resultNode, createOutput ) {
|
|
48
|
+
|
|
49
|
+
if ( resultNode.isMRTNode !== true ) return createOutput( resultNode );
|
|
50
|
+
|
|
51
|
+
if ( resultNode.has( 'output' ) !== true ) return resultNode;
|
|
52
|
+
|
|
53
|
+
return resultNode.merge( mrt( { output: createOutput( resultNode.get( 'output' ) ) } ) );
|
|
54
|
+
|
|
55
|
+
}
|
|
33
56
|
// !WITH_GENESYS
|
|
34
57
|
|
|
35
58
|
/**
|
|
@@ -548,11 +571,23 @@ class NodeMaterial extends Material {
|
|
|
548
571
|
// for detail lighting and can be replaced for lighting only.
|
|
549
572
|
if ( ( renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || renderer.debug.view === DEBUG_VIEW_DETAIL_LIGHTING ) && this.isShadowPassMaterial !== true ) {
|
|
550
573
|
|
|
551
|
-
applyLightingDebug( builder, renderer.debug.view );
|
|
574
|
+
applyLightingDebug( builder, this, renderer.debug.view );
|
|
552
575
|
|
|
553
576
|
} else if ( renderer.debug.view === DEBUG_VIEW_DRAW_CALL && this.isShadowPassMaterial !== true ) {
|
|
554
577
|
|
|
555
|
-
applyDrawCallDebug( builder );
|
|
578
|
+
applyDrawCallDebug( builder, this );
|
|
579
|
+
|
|
580
|
+
} else if ( renderer.debug.view === DEBUG_VIEW_FRONT_BACK_FACE && this.isShadowPassMaterial !== true ) {
|
|
581
|
+
|
|
582
|
+
applyFrontBackFaceDebug( builder, this );
|
|
583
|
+
|
|
584
|
+
} else if ( renderer.debug.view === DEBUG_VIEW_SHADOW_CASTER && this.isShadowPassMaterial !== true ) {
|
|
585
|
+
|
|
586
|
+
applyShadowCasterDebug( builder, this );
|
|
587
|
+
|
|
588
|
+
} else if ( renderer.debug.view === DEBUG_VIEW_DOUBLE_SIDE && this.isShadowPassMaterial !== true ) {
|
|
589
|
+
|
|
590
|
+
applyDoubleSideDebug( builder, this );
|
|
556
591
|
|
|
557
592
|
}
|
|
558
593
|
// !WITH_GENESYS
|
|
@@ -627,27 +662,32 @@ class NodeMaterial extends Material {
|
|
|
627
662
|
}
|
|
628
663
|
|
|
629
664
|
// WITH_GENESYS
|
|
630
|
-
// The screen output pass colorizes the accumulated ratio. Wrapping that pass
|
|
631
|
-
//
|
|
632
|
-
|
|
665
|
+
// The screen output pass colorizes the accumulated ratio. Wrapping that pass, or a
|
|
666
|
+
// post-processing quad that copies the scene target, would replace the heatmap with
|
|
667
|
+
// that quad's own constant cost.
|
|
668
|
+
if ( debugDrawAccumulates( renderer, this, builder.object ) ) {
|
|
633
669
|
|
|
634
|
-
|
|
635
|
-
resultNode = shaderComplexityOutput( resultNode );
|
|
670
|
+
if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY ) {
|
|
636
671
|
|
|
637
|
-
|
|
672
|
+
builder.shaderComplexityBase = this.getShaderComplexity();
|
|
673
|
+
resultNode = replaceColorOutput( resultNode, shaderComplexityOutput );
|
|
638
674
|
|
|
639
|
-
|
|
640
|
-
resultNode = shaderComplexityAndQuadsOutput( resultNode );
|
|
675
|
+
} else if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW ) {
|
|
641
676
|
|
|
642
|
-
|
|
677
|
+
builder.shaderComplexityBase = this.getShaderComplexity();
|
|
678
|
+
resultNode = replaceColorOutput( resultNode, shaderComplexityAndOverdrawOutput );
|
|
643
679
|
|
|
644
|
-
|
|
680
|
+
} else {
|
|
681
|
+
|
|
682
|
+
resultNode = replaceColorOutput( resultNode, quadOverdrawOutput );
|
|
683
|
+
|
|
684
|
+
}
|
|
645
685
|
|
|
646
686
|
} else if ( renderer.debug.view === DEBUG_VIEW_BUFFER && this.isShadowPassMaterial !== true && this.fragmentNode === null ) {
|
|
647
687
|
|
|
648
688
|
// The fullscreen output pass sets fragmentNode. Scene materials do not, including
|
|
649
689
|
// when the scene is drawn straight to the canvas.
|
|
650
|
-
resultNode = bufferVisualizationOutput( renderer.debug.buffer );
|
|
690
|
+
resultNode = replaceColorOutput( resultNode, () => bufferVisualizationOutput( renderer.debug.buffer ) );
|
|
651
691
|
|
|
652
692
|
}
|
|
653
693
|
// !WITH_GENESYS
|
|
@@ -1007,7 +1047,7 @@ class NodeMaterial extends Material {
|
|
|
1007
1047
|
setupNormal( builder ) {
|
|
1008
1048
|
|
|
1009
1049
|
// 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 ) {
|
|
1050
|
+
if ( ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || builder.renderer.debug.view === DEBUG_VIEW_DRAW_CALL || builder.renderer.debug.view === DEBUG_VIEW_FRONT_BACK_FACE || builder.renderer.debug.view === DEBUG_VIEW_SHADOW_CASTER || builder.renderer.debug.view === DEBUG_VIEW_DOUBLE_SIDE ) && this.isShadowPassMaterial !== true && this.fragmentNode === null ) {
|
|
1011
1051
|
|
|
1012
1052
|
return lightingOnlyNormal();
|
|
1013
1053
|
|
|
@@ -1212,7 +1252,7 @@ class NodeMaterial extends Material {
|
|
|
1212
1252
|
// WITH_GENESYS
|
|
1213
1253
|
// Lighting only and draw call substitute a plain lit material, so emissive is dropped.
|
|
1214
1254
|
// 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 ) {
|
|
1255
|
+
if ( ( builder.renderer.debug.view === DEBUG_VIEW_LIGHTING_ONLY || builder.renderer.debug.view === DEBUG_VIEW_DRAW_CALL || builder.renderer.debug.view === DEBUG_VIEW_FRONT_BACK_FACE || builder.renderer.debug.view === DEBUG_VIEW_SHADOW_CASTER || builder.renderer.debug.view === DEBUG_VIEW_DOUBLE_SIDE ) && this.isShadowPassMaterial !== true ) {
|
|
1216
1256
|
|
|
1217
1257
|
return outgoingLightNode;
|
|
1218
1258
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import Node from '../core/Node.js';
|
|
6
6
|
import { float, vec3, vec4, If, Fn } from '../tsl/TSLCore.js';
|
|
7
7
|
import { fract, min, mix, round } from '../math/MathNode.js';
|
|
8
|
+
import { DEBUG_VIEW_BUFFER } from './BufferDebug.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Shaded output. No complexity debug view.
|
|
@@ -14,7 +15,8 @@ import { fract, min, mix, round } from '../math/MathNode.js';
|
|
|
14
15
|
export const DEBUG_VIEW_NONE = 'none';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Material-cost heatmap.
|
|
18
|
+
* Material-cost heatmap. The nearest opaque surface wins, translucent draws add on top,
|
|
19
|
+
* then a fullscreen pass applies the ramp.
|
|
18
20
|
*
|
|
19
21
|
* @type {string}
|
|
20
22
|
*/
|
|
@@ -33,16 +35,16 @@ export const DEBUG_VIEW_LIGHTING_COMPLEXITY = 'lightingComplexity';
|
|
|
33
35
|
*
|
|
34
36
|
* @type {string}
|
|
35
37
|
*/
|
|
36
|
-
export const
|
|
38
|
+
export const DEBUG_VIEW_OVERDRAW = 'overdraw';
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* Shader cost multiplied by the number of fragments that shaded the pixel, then the shader-complexity ramp.
|
|
40
|
-
* One opaque surface matches {@link DEBUG_VIEW_SHADER_COMPLEXITY}. Each extra
|
|
42
|
+
* One opaque surface matches {@link DEBUG_VIEW_SHADER_COMPLEXITY}. Each extra translucent fragment scales the summed cost.
|
|
41
43
|
* WebGPU cannot count wasted lanes in a 2×2 quad, so the count is fragments that pass the depth test.
|
|
42
44
|
*
|
|
43
45
|
* @type {string}
|
|
44
46
|
*/
|
|
45
|
-
export const
|
|
47
|
+
export const DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW = 'shaderComplexityAndOverdraw';
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Proxy budget that fills the shader-complexity ramp.
|
|
@@ -62,7 +64,7 @@ export const DEFAULT_SHADER_COMPLEXITY_BUDGET = 800;
|
|
|
62
64
|
export const DEFAULT_QUAD_OVERDRAW_BUDGET = 10;
|
|
63
65
|
|
|
64
66
|
/**
|
|
65
|
-
* Storage scale for the overdraw count in {@link
|
|
67
|
+
* Storage scale for the overdraw count in {@link DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW}.
|
|
66
68
|
* Each fragment adds `1 / scale`, so an 8-bit target can hold this many layers.
|
|
67
69
|
* The output pass multiplies that channel back to a count. Half-float targets hold the same count exactly.
|
|
68
70
|
*
|
|
@@ -220,7 +222,54 @@ export const colorizeQuadOverdraw = ( cost ) => {
|
|
|
220
222
|
*/
|
|
221
223
|
export function debugViewAccumulates( view ) {
|
|
222
224
|
|
|
223
|
-
return view === DEBUG_VIEW_SHADER_COMPLEXITY || view ===
|
|
225
|
+
return view === DEBUG_VIEW_SHADER_COMPLEXITY || view === DEBUG_VIEW_OVERDRAW || view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW;
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Whether a draw adds its scalar to the accumulating target instead of shading normally.
|
|
231
|
+
* Shadow passes, draws to the screen, and fullscreen quads draw normally. A post-processing
|
|
232
|
+
* quad copies the accumulated scene target, so its own cost must not replace it.
|
|
233
|
+
*
|
|
234
|
+
* @param {Renderer} renderer - The renderer.
|
|
235
|
+
* @param {Material} material - The material being drawn.
|
|
236
|
+
* @param {?Object3D} object - The object being drawn.
|
|
237
|
+
* @return {boolean} `true` when the draw accumulates.
|
|
238
|
+
*/
|
|
239
|
+
export function debugDrawAccumulates( renderer, material, object ) {
|
|
240
|
+
|
|
241
|
+
return debugViewAccumulates( renderer.debug.view ) &&
|
|
242
|
+
material.isShadowPassMaterial !== true &&
|
|
243
|
+
renderer.isOutputTarget !== true &&
|
|
244
|
+
( object === null || object === undefined || object.isQuadMesh !== true );
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Whether an accumulating draw replaces the stored cost instead of adding to it.
|
|
250
|
+
* Three.js has no depth pre-pass, so adding every opaque fragment counts hidden surfaces
|
|
251
|
+
* and changes as the camera reorders draws. Replacing, with the material's own depth test
|
|
252
|
+
* and depth write, leaves the nearest opaque surface. Translucent draws and quad overdraw still add.
|
|
253
|
+
*
|
|
254
|
+
* @param {string} view - `renderer.debug.view`.
|
|
255
|
+
* @param {Material} material - The material being drawn.
|
|
256
|
+
* @return {boolean} `true` when the draw replaces the stored cost.
|
|
257
|
+
*/
|
|
258
|
+
export function debugDrawReplacesCost( view, material ) {
|
|
259
|
+
|
|
260
|
+
return ( view === DEBUG_VIEW_SHADER_COMPLEXITY || view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW ) && material.transparent !== true;
|
|
261
|
+
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Views that output data or a heatmap, so tone mapping would distort them.
|
|
266
|
+
*
|
|
267
|
+
* @param {string} view - `renderer.debug.view`.
|
|
268
|
+
* @return {boolean} `true` when the view is drawn without tone mapping.
|
|
269
|
+
*/
|
|
270
|
+
export function debugViewSkipsToneMapping( view ) {
|
|
271
|
+
|
|
272
|
+
return debugViewAccumulates( view ) || view === DEBUG_VIEW_LIGHTING_COMPLEXITY || view === DEBUG_VIEW_BUFFER;
|
|
224
273
|
|
|
225
274
|
}
|
|
226
275
|
|
|
@@ -343,7 +392,7 @@ export function shaderComplexityOutput( resultNode ) {
|
|
|
343
392
|
* @param {Node} resultNode - The material's shaded output.
|
|
344
393
|
* @return {Node<vec4>} Cost ratio in red, one scaled fragment in green.
|
|
345
394
|
*/
|
|
346
|
-
export function
|
|
395
|
+
export function shaderComplexityAndOverdrawOutput( resultNode ) {
|
|
347
396
|
|
|
348
397
|
const shaded = vec4( resultNode ).toVar();
|
|
349
398
|
const ratio = new ShaderComplexityRatioNode();
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// WITH_GENESYS
|
|
2
|
+
// Double sided. Gray is a single-sided surface or the front of a double-sided one.
|
|
3
|
+
// Blue is a double-sided back face you can see. Red is a double-sided back face hidden behind the front.
|
|
4
|
+
// !WITH_GENESYS
|
|
5
|
+
|
|
6
|
+
import Node from '../core/Node.js';
|
|
7
|
+
import { nodeImmutable } from '../tsl/TSLBase.js';
|
|
8
|
+
import { select } from '../math/ConditionalNode.js';
|
|
9
|
+
import { diffuseColor, diffuseContribution, metalness, roughness, specularColor, specularColorBlended, specularF90, clearcoat, sheen, iridescence, anisotropy, transmission, retroreflectivity } from '../core/PropertyNode.js';
|
|
10
|
+
import { float, vec3 } from '../tsl/TSLCore.js';
|
|
11
|
+
import { DoubleSide } from '../../constants.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Double sided. A single-sided material is gray. A double-sided front face is gray.
|
|
15
|
+
* A double-sided back face that is the nearest surface is blue. A later pass paints
|
|
16
|
+
* a hidden double-sided back face red over the front.
|
|
17
|
+
*
|
|
18
|
+
* @type {string}
|
|
19
|
+
*/
|
|
20
|
+
export const DEBUG_VIEW_DOUBLE_SIDE = 'doubleSide';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Rasterizer front face, ignoring the material side shortcut in {@link frontFacing}.
|
|
24
|
+
*/
|
|
25
|
+
class GeometricFrontFacingNode extends Node {
|
|
26
|
+
|
|
27
|
+
static get type() {
|
|
28
|
+
|
|
29
|
+
return 'GeometricFrontFacingNode';
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
constructor() {
|
|
34
|
+
|
|
35
|
+
super( 'bool' );
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
generate( builder ) {
|
|
40
|
+
|
|
41
|
+
if ( builder.shaderStage !== 'fragment' ) return 'true';
|
|
42
|
+
|
|
43
|
+
return builder.getFrontFacing();
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const geometricFrontFacing = /*@__PURE__*/ nodeImmutable( GeometricFrontFacingNode );
|
|
50
|
+
|
|
51
|
+
const hideCache = new WeakMap();
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A flat card or wall has normals that all point the same way, so its back face is the same
|
|
55
|
+
* surface. A box or a closed shell has normals that face each other, so one side can hide the other.
|
|
56
|
+
*
|
|
57
|
+
* @param {BufferGeometry} geometry - The mesh geometry.
|
|
58
|
+
* @return {boolean} `true` when some normals oppose the first one.
|
|
59
|
+
*/
|
|
60
|
+
export function meshCanHideOwnBack( geometry ) {
|
|
61
|
+
|
|
62
|
+
const normal = geometry.getAttribute( 'normal' );
|
|
63
|
+
const cached = hideCache.get( geometry );
|
|
64
|
+
|
|
65
|
+
if ( cached !== undefined && cached.version === geometry.version ) return cached.hides;
|
|
66
|
+
|
|
67
|
+
let hides = false;
|
|
68
|
+
|
|
69
|
+
if ( normal !== undefined && normal.count > 1 ) {
|
|
70
|
+
|
|
71
|
+
const ax = normal.getX( 0 );
|
|
72
|
+
const ay = normal.getY( 0 );
|
|
73
|
+
const az = normal.getZ( 0 );
|
|
74
|
+
const step = Math.max( 1, Math.floor( normal.count / 64 ) );
|
|
75
|
+
|
|
76
|
+
for ( let i = step; i < normal.count; i += step ) {
|
|
77
|
+
|
|
78
|
+
if ( ax * normal.getX( i ) + ay * normal.getY( i ) + az * normal.getZ( i ) < 0.25 ) {
|
|
79
|
+
|
|
80
|
+
hides = true;
|
|
81
|
+
break;
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
hideCache.set( geometry, { version: geometry.version, hides } );
|
|
90
|
+
|
|
91
|
+
return hides;
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const FRONT_COLOR = /*@__PURE__*/ vec3( 0.5, 0.5, 0.5 );
|
|
96
|
+
const BACK_COLOR = /*@__PURE__*/ vec3( 0.25, 0.45, 0.85 );
|
|
97
|
+
const HIDDEN_COLOR = /*@__PURE__*/ vec3( 0.85, 0.12, 0.1 );
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Makes a lit material a matte dielectric in the debug color. An unlit material stays flat.
|
|
101
|
+
*
|
|
102
|
+
* @param {NodeBuilder} builder - The current node builder.
|
|
103
|
+
* @param {NodeMaterial} material - The node material being set up.
|
|
104
|
+
* @param {Node} colorNode - The albedo written for this fragment.
|
|
105
|
+
*/
|
|
106
|
+
function assignLitColor( builder, material, colorNode ) {
|
|
107
|
+
|
|
108
|
+
diffuseColor.rgb.assign( colorNode );
|
|
109
|
+
|
|
110
|
+
if ( material.lights !== true ) return;
|
|
111
|
+
|
|
112
|
+
metalness.assign( float( 0 ) );
|
|
113
|
+
diffuseContribution.assign( colorNode );
|
|
114
|
+
roughness.assign( float( 1 ) );
|
|
115
|
+
specularColor.assign( vec3( 0 ) );
|
|
116
|
+
specularColorBlended.assign( vec3( 0 ) );
|
|
117
|
+
specularF90.assign( float( 0 ) );
|
|
118
|
+
|
|
119
|
+
builder.context.ambientOcclusion = null;
|
|
120
|
+
|
|
121
|
+
if ( material.useClearcoat === true ) clearcoat.assign( float( 0 ) );
|
|
122
|
+
|
|
123
|
+
if ( material.useSheen === true ) sheen.assign( vec3( 0 ) );
|
|
124
|
+
|
|
125
|
+
if ( material.useIridescence === true ) iridescence.assign( float( 0 ) );
|
|
126
|
+
|
|
127
|
+
if ( material.useAnisotropy === true ) anisotropy.assign( float( 0 ) );
|
|
128
|
+
|
|
129
|
+
if ( material.useTransmission === true ) transmission.assign( float( 0 ) );
|
|
130
|
+
|
|
131
|
+
if ( material.useRetroreflection === true ) retroreflectivity.assign( float( 0 ) );
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Replaces albedo after the material has written its channels.
|
|
137
|
+
* The hidden pass forces red. The first pass uses gray, or blue on a visible double-sided back face.
|
|
138
|
+
*
|
|
139
|
+
* @param {NodeBuilder} builder - The current node builder.
|
|
140
|
+
* @param {NodeMaterial} material - The node material being set up. `builder.material` can be the
|
|
141
|
+
* source material of a converted one, such as a glTF `MeshStandardMaterial`.
|
|
142
|
+
*/
|
|
143
|
+
export function applyDoubleSideDebug( builder, material ) {
|
|
144
|
+
|
|
145
|
+
const hidden = builder.renderer.debug.doubleSideHidden === true;
|
|
146
|
+
const visibleBack = builder.renderer.debug.doubleSideBack === true;
|
|
147
|
+
const doubleSided = material.side === DoubleSide;
|
|
148
|
+
const colorNode = hidden ? HIDDEN_COLOR : ( visibleBack ? BACK_COLOR : ( doubleSided ? select( geometricFrontFacing, FRONT_COLOR, BACK_COLOR ) : FRONT_COLOR ) );
|
|
149
|
+
|
|
150
|
+
assignLitColor( builder, material, colorNode );
|
|
151
|
+
|
|
152
|
+
}
|
|
@@ -77,10 +77,11 @@ function writeDrawCallColor( color, object, material ) {
|
|
|
77
77
|
* The color is an object uniform, so meshes that share a material still differ.
|
|
78
78
|
*
|
|
79
79
|
* @param {NodeBuilder} builder - The current node builder.
|
|
80
|
+
* @param {NodeMaterial} material - The node material being set up. `builder.material` can be the
|
|
81
|
+
* source material of a converted one, such as a glTF `MeshStandardMaterial`.
|
|
80
82
|
*/
|
|
81
|
-
export function applyDrawCallDebug( builder ) {
|
|
83
|
+
export function applyDrawCallDebug( builder, material ) {
|
|
82
84
|
|
|
83
|
-
const material = builder.material;
|
|
84
85
|
const colorNode = uniform( new Color() ).onObjectUpdate( ( { object, material: drawnMaterial }, self ) => {
|
|
85
86
|
|
|
86
87
|
if ( object === null || drawnMaterial === null ) return;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// WITH_GENESYS
|
|
2
|
+
// Front/back face. Both windings are drawn. The side facing the camera uses one color, the other side another.
|
|
3
|
+
// !WITH_GENESYS
|
|
4
|
+
|
|
5
|
+
import Node from '../core/Node.js';
|
|
6
|
+
import { nodeImmutable } from '../tsl/TSLBase.js';
|
|
7
|
+
import { select } from '../math/ConditionalNode.js';
|
|
8
|
+
import { diffuseColor, diffuseContribution, metalness, roughness, specularColor, specularColorBlended, specularF90, clearcoat, sheen, iridescence, anisotropy, transmission, retroreflectivity } from '../core/PropertyNode.js';
|
|
9
|
+
import { float, vec3 } from '../tsl/TSLCore.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Front/back face. Culling is off. A fragment whose winding faces the camera is one color.
|
|
13
|
+
* The opposite winding is another. Depth still hides a face behind the shell.
|
|
14
|
+
*
|
|
15
|
+
* @type {string}
|
|
16
|
+
*/
|
|
17
|
+
export const DEBUG_VIEW_FRONT_BACK_FACE = 'frontBackFace';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Rasterizer front face, ignoring the material side shortcut in {@link frontFacing}.
|
|
21
|
+
* `BackSide` materials otherwise report every fragment as back facing.
|
|
22
|
+
*/
|
|
23
|
+
class GeometricFrontFacingNode extends Node {
|
|
24
|
+
|
|
25
|
+
static get type() {
|
|
26
|
+
|
|
27
|
+
return 'GeometricFrontFacingNode';
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
|
|
33
|
+
super( 'bool' );
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
generate( builder ) {
|
|
38
|
+
|
|
39
|
+
if ( builder.shaderStage !== 'fragment' ) return 'true';
|
|
40
|
+
|
|
41
|
+
return builder.getFrontFacing();
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const geometricFrontFacing = /*@__PURE__*/ nodeImmutable( GeometricFrontFacingNode );
|
|
48
|
+
|
|
49
|
+
const FRONT_COLOR = /*@__PURE__*/ vec3( 0.72, 0.70, 0.66 );
|
|
50
|
+
const BACK_COLOR = /*@__PURE__*/ vec3( 0.25, 0.45, 0.85 );
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Replaces albedo with the front or back color after the material has written its channels.
|
|
54
|
+
* Lit materials become a matte dielectric. Unlit materials become flat.
|
|
55
|
+
*
|
|
56
|
+
* @param {NodeBuilder} builder - The current node builder.
|
|
57
|
+
* @param {NodeMaterial} material - The node material being set up.
|
|
58
|
+
*/
|
|
59
|
+
export function applyFrontBackFaceDebug( builder, material ) {
|
|
60
|
+
|
|
61
|
+
const colorNode = select( geometricFrontFacing, FRONT_COLOR, BACK_COLOR );
|
|
62
|
+
|
|
63
|
+
diffuseColor.rgb.assign( colorNode );
|
|
64
|
+
|
|
65
|
+
if ( material.lights !== true ) return;
|
|
66
|
+
|
|
67
|
+
metalness.assign( float( 0 ) );
|
|
68
|
+
diffuseContribution.assign( colorNode );
|
|
69
|
+
roughness.assign( float( 1 ) );
|
|
70
|
+
specularColor.assign( vec3( 0 ) );
|
|
71
|
+
specularColorBlended.assign( vec3( 0 ) );
|
|
72
|
+
specularF90.assign( float( 0 ) );
|
|
73
|
+
|
|
74
|
+
builder.context.ambientOcclusion = null;
|
|
75
|
+
|
|
76
|
+
if ( material.useClearcoat === true ) clearcoat.assign( float( 0 ) );
|
|
77
|
+
|
|
78
|
+
if ( material.useSheen === true ) sheen.assign( vec3( 0 ) );
|
|
79
|
+
|
|
80
|
+
if ( material.useIridescence === true ) iridescence.assign( float( 0 ) );
|
|
81
|
+
|
|
82
|
+
if ( material.useAnisotropy === true ) anisotropy.assign( float( 0 ) );
|
|
83
|
+
|
|
84
|
+
if ( material.useTransmission === true ) transmission.assign( float( 0 ) );
|
|
85
|
+
|
|
86
|
+
if ( material.useRetroreflection === true ) retroreflectivity.assign( float( 0 ) );
|
|
87
|
+
|
|
88
|
+
}
|
|
@@ -59,11 +59,12 @@ export const lightingOnlyNormal = /*@__PURE__*/ Fn( ( builder ) => {
|
|
|
59
59
|
* Lit materials become a dielectric gray. Unlit materials become flat gray.
|
|
60
60
|
*
|
|
61
61
|
* @param {NodeBuilder} builder - The current node builder.
|
|
62
|
+
* @param {NodeMaterial} material - The node material being set up. `builder.material` can be the
|
|
63
|
+
* source material of a converted one, such as a glTF `MeshStandardMaterial`.
|
|
62
64
|
* @param {string} view - `renderer.debug.view`.
|
|
63
65
|
*/
|
|
64
|
-
export function applyLightingDebug( builder, view ) {
|
|
66
|
+
export function applyLightingDebug( builder, material, view ) {
|
|
65
67
|
|
|
66
|
-
const material = builder.material;
|
|
67
68
|
const gray = vec3( LIGHTING_ONLY_BRIGHTNESS );
|
|
68
69
|
|
|
69
70
|
diffuseColor.rgb.assign( gray );
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// WITH_GENESYS
|
|
2
|
+
// Shadow casters. Green when the object casts a shadow, gray when it does not.
|
|
3
|
+
// !WITH_GENESYS
|
|
4
|
+
|
|
5
|
+
import { Color } from '../../math/Color.js';
|
|
6
|
+
import { diffuseColor, diffuseContribution, metalness, roughness, specularColor, specularColorBlended, specularF90, clearcoat, sheen, iridescence, anisotropy, transmission, retroreflectivity } from '../core/PropertyNode.js';
|
|
7
|
+
import { uniform } from '../core/UniformNode.js';
|
|
8
|
+
import { float, vec3 } from '../tsl/TSLCore.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Shadow casters. A mesh that casts shadows is green. One that does not is gray.
|
|
12
|
+
* The color is lit, so form stays readable.
|
|
13
|
+
*
|
|
14
|
+
* Matches Unreal's simplified shadow-caster view (`GetCachedShadowCasterColorSimplified`):
|
|
15
|
+
* green `(0, 1, 0)` casts, gray `(0.5, 0.5, 0.5)` does not. Contact-shadow yellow is omitted;
|
|
16
|
+
* Three.js has no per-object contact-shadow flag.
|
|
17
|
+
*
|
|
18
|
+
* @type {string}
|
|
19
|
+
*/
|
|
20
|
+
export const DEBUG_VIEW_SHADOW_CASTER = 'shadowCaster';
|
|
21
|
+
|
|
22
|
+
const CASTS_COLOR = new Color( 0, 1, 0 );
|
|
23
|
+
const NONE_COLOR = new Color( 0.5, 0.5, 0.5 );
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Replaces albedo with the caster color after the material has written its channels.
|
|
27
|
+
* Lit materials become a matte dielectric. Unlit materials become flat.
|
|
28
|
+
* The color is an object uniform, so meshes that share a material still differ.
|
|
29
|
+
*
|
|
30
|
+
* @param {NodeBuilder} builder - The current node builder.
|
|
31
|
+
* @param {NodeMaterial} material - The node material being set up. `builder.material` can be the
|
|
32
|
+
* source material of a converted one, such as a glTF `MeshStandardMaterial`.
|
|
33
|
+
*/
|
|
34
|
+
export function applyShadowCasterDebug( builder, material ) {
|
|
35
|
+
|
|
36
|
+
const colorNode = uniform( new Color() ).onObjectUpdate( ( { object }, self ) => {
|
|
37
|
+
|
|
38
|
+
if ( object === null ) return;
|
|
39
|
+
|
|
40
|
+
return self.value.copy( object.castShadow === true ? CASTS_COLOR : NONE_COLOR );
|
|
41
|
+
|
|
42
|
+
} );
|
|
43
|
+
|
|
44
|
+
diffuseColor.rgb.assign( colorNode );
|
|
45
|
+
|
|
46
|
+
if ( material.lights !== true ) return;
|
|
47
|
+
|
|
48
|
+
metalness.assign( float( 0 ) );
|
|
49
|
+
diffuseContribution.assign( colorNode );
|
|
50
|
+
roughness.assign( float( 1 ) );
|
|
51
|
+
specularColor.assign( vec3( 0 ) );
|
|
52
|
+
specularColorBlended.assign( vec3( 0 ) );
|
|
53
|
+
specularF90.assign( float( 0 ) );
|
|
54
|
+
|
|
55
|
+
builder.context.ambientOcclusion = null;
|
|
56
|
+
|
|
57
|
+
if ( material.useClearcoat === true ) clearcoat.assign( float( 0 ) );
|
|
58
|
+
|
|
59
|
+
if ( material.useSheen === true ) sheen.assign( vec3( 0 ) );
|
|
60
|
+
|
|
61
|
+
if ( material.useIridescence === true ) iridescence.assign( float( 0 ) );
|
|
62
|
+
|
|
63
|
+
if ( material.useAnisotropy === true ) anisotropy.assign( float( 0 ) );
|
|
64
|
+
|
|
65
|
+
if ( material.useTransmission === true ) transmission.assign( float( 0 ) );
|
|
66
|
+
|
|
67
|
+
if ( material.useRetroreflection === true ) retroreflectivity.assign( float( 0 ) );
|
|
68
|
+
|
|
69
|
+
}
|
|
@@ -227,9 +227,11 @@ class Background extends DataMap {
|
|
|
227
227
|
//
|
|
228
228
|
|
|
229
229
|
// WITH_GENESYS
|
|
230
|
+
// Accumulating views start from zero cost. Alpha keeps the shaded pass coverage, so an
|
|
231
|
+
// overlay pass such as a HUD stays transparent where it draws nothing when composited.
|
|
230
232
|
if ( debugViewAccumulates( renderer.debug.view ) ) {
|
|
231
233
|
|
|
232
|
-
_clearColor.set( 0, 0, 0, 1 );
|
|
234
|
+
_clearColor.set( 0, 0, 0, background !== null ? 1 : _clearColor.a );
|
|
233
235
|
|
|
234
236
|
}
|
|
235
237
|
// !WITH_GENESYS
|
|
@@ -952,7 +952,7 @@ class RenderObject {
|
|
|
952
952
|
|
|
953
953
|
// WITH_GENESYS
|
|
954
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 );
|
|
955
|
+
cacheKey = hash( cacheKey, hashString( this.renderer.debug.view ), hashString( this.renderer.debug.buffer ), this.renderer.debug.shaderComplexityBudget, this.renderer.debug.quadOverdrawBudget, this.renderer.debug.doubleSideHidden === true ? 1 : 0, this.renderer.debug.doubleSideBack === true ? 1 : 0 );
|
|
956
956
|
// !WITH_GENESYS
|
|
957
957
|
|
|
958
958
|
return cacheKey;
|