@gnsx/three 0.186.6 → 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 +477 -27
- package/build/three.webgpu.nodes.js +477 -27
- package/examples/jsm/inspector/tabs/Settings.js +9 -6
- package/package.json +1 -1
- package/src/materials/nodes/NodeMaterial.js +20 -5
- package/src/nodes/display/ComplexityDebug.js +24 -7
- package/src/nodes/display/DoubleSideDebug.js +152 -0
- package/src/nodes/display/FrontBackFaceDebug.js +88 -0
- 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/Renderer.js +85 -2
- package/src/renderers/common/nodes/NodeManager.js +4 -4
- package/src/renderers/webgl-fallback/WebGLBackend.js +4 -1
- package/src/renderers/webgl-fallback/utils/WebGLState.js +34 -5
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +15 -5
|
@@ -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,11 +26,14 @@ 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,
|
|
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
30
|
import { mrt } from '../../nodes/core/MRTNode.js';
|
|
31
31
|
import { DEBUG_VIEW_BUFFER, assignBufferDefaults, bufferVisualizationOutput } from '../../nodes/display/BufferDebug.js';
|
|
32
32
|
import { DEBUG_VIEW_DETAIL_LIGHTING, DEBUG_VIEW_LIGHTING_ONLY, applyLightingDebug, lightingOnlyNormal } from '../../nodes/display/LightingDebug.js';
|
|
33
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';
|
|
34
37
|
|
|
35
38
|
/**
|
|
36
39
|
* Replaces the color a material writes with a debug output. With MRT, only the `output`
|
|
@@ -574,6 +577,18 @@ class NodeMaterial extends Material {
|
|
|
574
577
|
|
|
575
578
|
applyDrawCallDebug( builder, this );
|
|
576
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 );
|
|
591
|
+
|
|
577
592
|
}
|
|
578
593
|
// !WITH_GENESYS
|
|
579
594
|
|
|
@@ -657,10 +672,10 @@ class NodeMaterial extends Material {
|
|
|
657
672
|
builder.shaderComplexityBase = this.getShaderComplexity();
|
|
658
673
|
resultNode = replaceColorOutput( resultNode, shaderComplexityOutput );
|
|
659
674
|
|
|
660
|
-
} else if ( renderer.debug.view ===
|
|
675
|
+
} else if ( renderer.debug.view === DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW ) {
|
|
661
676
|
|
|
662
677
|
builder.shaderComplexityBase = this.getShaderComplexity();
|
|
663
|
-
resultNode = replaceColorOutput( resultNode,
|
|
678
|
+
resultNode = replaceColorOutput( resultNode, shaderComplexityAndOverdrawOutput );
|
|
664
679
|
|
|
665
680
|
} else {
|
|
666
681
|
|
|
@@ -1032,7 +1047,7 @@ class NodeMaterial extends Material {
|
|
|
1032
1047
|
setupNormal( builder ) {
|
|
1033
1048
|
|
|
1034
1049
|
// WITH_GENESYS
|
|
1035
|
-
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 ) {
|
|
1036
1051
|
|
|
1037
1052
|
return lightingOnlyNormal();
|
|
1038
1053
|
|
|
@@ -1237,7 +1252,7 @@ class NodeMaterial extends Material {
|
|
|
1237
1252
|
// WITH_GENESYS
|
|
1238
1253
|
// Lighting only and draw call substitute a plain lit material, so emissive is dropped.
|
|
1239
1254
|
// Detail lighting keeps it.
|
|
1240
|
-
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 ) {
|
|
1241
1256
|
|
|
1242
1257
|
return outgoingLightNode;
|
|
1243
1258
|
|
|
@@ -15,7 +15,8 @@ import { DEBUG_VIEW_BUFFER } from './BufferDebug.js';
|
|
|
15
15
|
export const DEBUG_VIEW_NONE = 'none';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* 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.
|
|
19
20
|
*
|
|
20
21
|
* @type {string}
|
|
21
22
|
*/
|
|
@@ -34,16 +35,16 @@ export const DEBUG_VIEW_LIGHTING_COMPLEXITY = 'lightingComplexity';
|
|
|
34
35
|
*
|
|
35
36
|
* @type {string}
|
|
36
37
|
*/
|
|
37
|
-
export const
|
|
38
|
+
export const DEBUG_VIEW_OVERDRAW = 'overdraw';
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* Shader cost multiplied by the number of fragments that shaded the pixel, then the shader-complexity ramp.
|
|
41
|
-
* 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.
|
|
42
43
|
* WebGPU cannot count wasted lanes in a 2×2 quad, so the count is fragments that pass the depth test.
|
|
43
44
|
*
|
|
44
45
|
* @type {string}
|
|
45
46
|
*/
|
|
46
|
-
export const
|
|
47
|
+
export const DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW = 'shaderComplexityAndOverdraw';
|
|
47
48
|
|
|
48
49
|
/**
|
|
49
50
|
* Proxy budget that fills the shader-complexity ramp.
|
|
@@ -63,7 +64,7 @@ export const DEFAULT_SHADER_COMPLEXITY_BUDGET = 800;
|
|
|
63
64
|
export const DEFAULT_QUAD_OVERDRAW_BUDGET = 10;
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
|
-
* Storage scale for the overdraw count in {@link
|
|
67
|
+
* Storage scale for the overdraw count in {@link DEBUG_VIEW_SHADER_COMPLEXITY_AND_OVERDRAW}.
|
|
67
68
|
* Each fragment adds `1 / scale`, so an 8-bit target can hold this many layers.
|
|
68
69
|
* The output pass multiplies that channel back to a count. Half-float targets hold the same count exactly.
|
|
69
70
|
*
|
|
@@ -221,7 +222,7 @@ export const colorizeQuadOverdraw = ( cost ) => {
|
|
|
221
222
|
*/
|
|
222
223
|
export function debugViewAccumulates( view ) {
|
|
223
224
|
|
|
224
|
-
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;
|
|
225
226
|
|
|
226
227
|
}
|
|
227
228
|
|
|
@@ -244,6 +245,22 @@ export function debugDrawAccumulates( renderer, material, object ) {
|
|
|
244
245
|
|
|
245
246
|
}
|
|
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
|
+
|
|
247
264
|
/**
|
|
248
265
|
* Views that output data or a heatmap, so tone mapping would distort them.
|
|
249
266
|
*
|
|
@@ -375,7 +392,7 @@ export function shaderComplexityOutput( resultNode ) {
|
|
|
375
392
|
* @param {Node} resultNode - The material's shaded output.
|
|
376
393
|
* @return {Node<vec4>} Cost ratio in red, one scaled fragment in green.
|
|
377
394
|
*/
|
|
378
|
-
export function
|
|
395
|
+
export function shaderComplexityAndOverdrawOutput( resultNode ) {
|
|
379
396
|
|
|
380
397
|
const shaded = vec4( resultNode ).toVar();
|
|
381
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
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -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;
|
|
@@ -30,7 +30,7 @@ import { Matrix4 } from '../../math/Matrix4.js';
|
|
|
30
30
|
import { Vector2 } from '../../math/Vector2.js';
|
|
31
31
|
import { Vector4 } from '../../math/Vector4.js';
|
|
32
32
|
import { RenderTarget } from '../../core/RenderTarget.js';
|
|
33
|
-
import { DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping, LinearFilter, HalfFloatType, RGBAFormat, PCFShadowMap, PCFSoftShadowMap, VSMShadowMap, RenderObjectRefreshType } from '../../constants.js';
|
|
33
|
+
import { DoubleSide, BackSide, FrontSide, EqualDepth, SRGBColorSpace, NoToneMapping, LinearFilter, HalfFloatType, RGBAFormat, PCFShadowMap, PCFSoftShadowMap, VSMShadowMap, RenderObjectRefreshType } from '../../constants.js';
|
|
34
34
|
|
|
35
35
|
import { float, vec3, vec4, Fn } from '../../nodes/tsl/TSLCore.js';
|
|
36
36
|
// WITH_GENESYS
|
|
@@ -38,6 +38,7 @@ import { detachRendererReference } from '../../nodes/accessors/RendererReference
|
|
|
38
38
|
import { toneMappingExposure } from '../../nodes/display/ToneMappingNode.js';
|
|
39
39
|
import { ProfilerService } from '../../profiler/ProfilerService.js';
|
|
40
40
|
import { DEBUG_VIEW_NONE, DEFAULT_QUAD_OVERDRAW_BUDGET, DEFAULT_SHADER_COMPLEXITY_BUDGET, debugViewAccumulates, debugViewSkipsToneMapping } from '../../nodes/display/ComplexityDebug.js';
|
|
41
|
+
import { DEBUG_VIEW_DOUBLE_SIDE, meshCanHideOwnBack } from '../../nodes/display/DoubleSideDebug.js';
|
|
41
42
|
import { DEFAULT_BUFFER } from '../../nodes/display/BufferDebug.js';
|
|
42
43
|
// !WITH_GENESYS
|
|
43
44
|
import { reference } from '../../nodes/accessors/ReferenceNode.js';
|
|
@@ -745,7 +746,7 @@ class Renderer {
|
|
|
745
746
|
* @property {?Function} onNodeBuilderCreated - A callback function that is executed after a node builder has been created and before it is built.
|
|
746
747
|
* @property {?Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now.
|
|
747
748
|
* @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object.
|
|
748
|
-
* @property {string} view - Debug view. `shaderComplexity`, `lightingComplexity`, `
|
|
749
|
+
* @property {string} view - Debug view. `shaderComplexity`, `lightingComplexity`, `overdraw`, and `shaderComplexityAndOverdraw` replace the shaded color with a heatmap. `shaderComplexityAndOverdraw` 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. `frontBackFace` draws both windings and tints the side facing the camera. `shadowCaster` lights a mesh green when it casts shadows and gray when it does not. `doubleSide` lights a single-sided surface gray, a visible double-sided back face blue, and a hidden double-sided back face red.
|
|
749
750
|
* @property {string} buffer - Channel drawn by `bufferVisualization`: `baseColor`, `worldNormal`, `roughness`, `metallic`, `ambientOcclusion`, or `emissive`.
|
|
750
751
|
* @property {number} shaderComplexityBudget - Proxy budget that fills the shader-complexity ramp.
|
|
751
752
|
* @property {number} quadOverdrawBudget - Overlapping fragments that fill the quad-overdraw ramp.
|
|
@@ -768,6 +769,8 @@ class Renderer {
|
|
|
768
769
|
buffer: DEFAULT_BUFFER,
|
|
769
770
|
shaderComplexityBudget: DEFAULT_SHADER_COMPLEXITY_BUDGET,
|
|
770
771
|
quadOverdrawBudget: DEFAULT_QUAD_OVERDRAW_BUDGET,
|
|
772
|
+
doubleSideHidden: false,
|
|
773
|
+
doubleSideBack: false,
|
|
771
774
|
// !WITH_GENESYS
|
|
772
775
|
getShaderAsync: async ( scene, camera, object ) => {
|
|
773
776
|
|
|
@@ -1988,6 +1991,10 @@ class Renderer {
|
|
|
1988
1991
|
if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
|
|
1989
1992
|
if ( this.transparent === true && transparentObjects.length > 0 ) this._renderTransparents( transparentObjects, transparentDoublePassObjects, camera, sceneRef, lightsNode );
|
|
1990
1993
|
|
|
1994
|
+
// WITH_GENESYS
|
|
1995
|
+
this._renderDoubleSideHidden( opaqueObjects, transparentObjects, camera, sceneRef, lightsNode );
|
|
1996
|
+
// !WITH_GENESYS
|
|
1997
|
+
|
|
1991
1998
|
// finish render pass
|
|
1992
1999
|
|
|
1993
2000
|
this.backend.finishRender( renderContext );
|
|
@@ -3558,6 +3565,82 @@ class Renderer {
|
|
|
3558
3565
|
|
|
3559
3566
|
}
|
|
3560
3567
|
|
|
3568
|
+
// WITH_GENESYS
|
|
3569
|
+
/**
|
|
3570
|
+
* Paints a double-sided mesh red where its own front face is the nearest surface and the
|
|
3571
|
+
* mesh has faces pointing the other way. A different mesh in front keeps its own color.
|
|
3572
|
+
* A flat card has no opposing faces, so it stays gray or blue. A shadow pass is left alone.
|
|
3573
|
+
*
|
|
3574
|
+
* @private
|
|
3575
|
+
* @param {Array<Object>} opaqueObjects - The opaque render list.
|
|
3576
|
+
* @param {Array<Object>} transparentObjects - The transparent render list.
|
|
3577
|
+
* @param {Camera} camera - The camera.
|
|
3578
|
+
* @param {Scene} scene - The scene.
|
|
3579
|
+
* @param {LightsNode} lightsNode - The current lights node.
|
|
3580
|
+
*/
|
|
3581
|
+
_renderDoubleSideHidden( opaqueObjects, transparentObjects, camera, scene, lightsNode ) {
|
|
3582
|
+
|
|
3583
|
+
if ( this.debug.view !== DEBUG_VIEW_DOUBLE_SIDE ) return;
|
|
3584
|
+
|
|
3585
|
+
if ( scene.overrideMaterial !== null && scene.overrideMaterial.isShadowPassMaterial === true ) return;
|
|
3586
|
+
|
|
3587
|
+
const list = [];
|
|
3588
|
+
const saved = new Map();
|
|
3589
|
+
|
|
3590
|
+
const collect = ( objects ) => {
|
|
3591
|
+
|
|
3592
|
+
for ( let i = 0, l = objects.length; i < l; i ++ ) {
|
|
3593
|
+
|
|
3594
|
+
const entry = objects[ i ];
|
|
3595
|
+
const material = entry.material;
|
|
3596
|
+
const geometry = entry.object.geometry;
|
|
3597
|
+
|
|
3598
|
+
if ( entry.object.isMesh !== true || material.side !== DoubleSide || material.isShadowPassMaterial === true ) continue;
|
|
3599
|
+
|
|
3600
|
+
if ( geometry === undefined || meshCanHideOwnBack( geometry ) !== true ) continue;
|
|
3601
|
+
|
|
3602
|
+
list.push( entry );
|
|
3603
|
+
|
|
3604
|
+
if ( saved.has( material ) ) continue;
|
|
3605
|
+
|
|
3606
|
+
saved.set( material, {
|
|
3607
|
+
side: material.side,
|
|
3608
|
+
depthFunc: material.depthFunc,
|
|
3609
|
+
depthWrite: material.depthWrite
|
|
3610
|
+
} );
|
|
3611
|
+
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3614
|
+
};
|
|
3615
|
+
|
|
3616
|
+
collect( opaqueObjects );
|
|
3617
|
+
collect( transparentObjects );
|
|
3618
|
+
|
|
3619
|
+
if ( list.length === 0 ) return;
|
|
3620
|
+
|
|
3621
|
+
for ( const material of saved.keys() ) {
|
|
3622
|
+
|
|
3623
|
+
material.side = FrontSide;
|
|
3624
|
+
material.depthFunc = EqualDepth;
|
|
3625
|
+
material.depthWrite = false;
|
|
3626
|
+
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
this.debug.doubleSideHidden = true;
|
|
3630
|
+
this._renderObjects( list, camera, scene, lightsNode, 'doubleSideHidden' );
|
|
3631
|
+
this.debug.doubleSideHidden = false;
|
|
3632
|
+
|
|
3633
|
+
for ( const [ material, state ] of saved ) {
|
|
3634
|
+
|
|
3635
|
+
material.side = state.side;
|
|
3636
|
+
material.depthFunc = state.depthFunc;
|
|
3637
|
+
material.depthWrite = state.depthWrite;
|
|
3638
|
+
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
}
|
|
3642
|
+
// !WITH_GENESYS
|
|
3643
|
+
|
|
3561
3644
|
/**
|
|
3562
3645
|
* Renders the transparent objects from the given render lists.
|
|
3563
3646
|
*
|