@gnsx/three 0.186.10 → 0.186.11
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 +774 -15
- package/build/three.webgpu.nodes.js +774 -15
- package/examples/jsm/inspector/tabs/Settings.js +2 -1
- package/package.json +1 -1
- package/src/materials/nodes/NodeMaterial.js +7 -2
- package/src/nodes/display/LODColorationDebug.js +162 -0
- package/src/renderers/common/DebugViewLegend.js +560 -0
- package/src/renderers/common/Renderer.js +40 -1
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
// WITH_GENESYS
|
|
2
|
+
// Viewport legend for renderer.debug views that use fixed ramps or symbolic colors.
|
|
3
|
+
// !WITH_GENESYS
|
|
4
|
+
|
|
5
|
+
const SHADER_COMPLEXITY_COLORS = [
|
|
6
|
+
[ 0.0, 1.0, 0.127 ],
|
|
7
|
+
[ 0.0, 1.0, 0.0 ],
|
|
8
|
+
[ 0.046, 0.52, 0.0 ],
|
|
9
|
+
[ 0.215, 0.215, 0.0 ],
|
|
10
|
+
[ 0.52, 0.046, 0.0 ],
|
|
11
|
+
[ 0.7, 0.0, 0.0 ],
|
|
12
|
+
[ 1.0, 0.0, 0.0 ],
|
|
13
|
+
[ 1.0, 0.0, 0.5 ],
|
|
14
|
+
[ 1.0, 0.9, 0.9 ]
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const QUAD_OVERDRAW_COLORS = [
|
|
18
|
+
[ 0.0, 0.0, 0.0 ],
|
|
19
|
+
[ 0.0, 0.0, 0.4 ],
|
|
20
|
+
[ 0.0, 0.3, 1.0 ],
|
|
21
|
+
[ 0.0, 0.7, 0.4 ],
|
|
22
|
+
[ 0.0, 1.0, 0.0 ],
|
|
23
|
+
[ 0.8, 0.8, 0.0 ],
|
|
24
|
+
[ 1.0, 0.3, 0.0 ],
|
|
25
|
+
[ 0.7, 0.0, 0.0 ],
|
|
26
|
+
[ 0.5, 0.0, 0.5 ],
|
|
27
|
+
[ 0.7, 0.3, 0.7 ],
|
|
28
|
+
[ 1.0, 0.9, 0.9 ]
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const LIGHT_COMPLEXITY_COLORS = QUAD_OVERDRAW_COLORS;
|
|
32
|
+
|
|
33
|
+
const DEFAULT_LOD_LABELS = [
|
|
34
|
+
'LOD 0',
|
|
35
|
+
'LOD 1',
|
|
36
|
+
'LOD 2',
|
|
37
|
+
'LOD 3',
|
|
38
|
+
'LOD 4',
|
|
39
|
+
'LOD 5',
|
|
40
|
+
'LOD 6',
|
|
41
|
+
'LOD 7'
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const DEFAULT_LOD_COLORS = [
|
|
45
|
+
[ 1, 1, 1 ],
|
|
46
|
+
[ 1, 0, 0 ],
|
|
47
|
+
[ 0, 1, 0 ],
|
|
48
|
+
[ 0, 0, 1 ],
|
|
49
|
+
[ 1, 1, 0 ],
|
|
50
|
+
[ 1, 0, 1 ],
|
|
51
|
+
[ 0, 1, 1 ],
|
|
52
|
+
[ 0.5, 0, 0.5 ]
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
const LEGEND_DEBUG_KEYS = new Set( [
|
|
56
|
+
'view',
|
|
57
|
+
'buffer',
|
|
58
|
+
'shaderComplexityBudget',
|
|
59
|
+
'quadOverdrawBudget'
|
|
60
|
+
] );
|
|
61
|
+
|
|
62
|
+
let _stylesInjected = false;
|
|
63
|
+
|
|
64
|
+
function injectStyles() {
|
|
65
|
+
|
|
66
|
+
if ( _stylesInjected === true || typeof document === 'undefined' ) return;
|
|
67
|
+
|
|
68
|
+
_stylesInjected = true;
|
|
69
|
+
|
|
70
|
+
const style = document.createElement( 'style' );
|
|
71
|
+
style.textContent = `
|
|
72
|
+
.three-debug-view-legend {
|
|
73
|
+
position: absolute;
|
|
74
|
+
left: 12px;
|
|
75
|
+
bottom: 12px;
|
|
76
|
+
z-index: 900;
|
|
77
|
+
max-width: min( 420px, calc( 100% - 24px ) );
|
|
78
|
+
padding: 10px 12px;
|
|
79
|
+
border-radius: 8px;
|
|
80
|
+
border: 1px solid rgba( 74, 74, 90, 0.55 );
|
|
81
|
+
background: rgba( 30, 30, 36, 0.88 );
|
|
82
|
+
color: #e0e0e0;
|
|
83
|
+
font: 12px/1.35 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
84
|
+
pointer-events: none;
|
|
85
|
+
backdrop-filter: blur( 8px );
|
|
86
|
+
box-shadow: 0 4px 15px rgba( 0, 0, 0, 0.35 );
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.three-debug-view-legend[ hidden ] {
|
|
90
|
+
display: none !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.three-debug-view-legend-title {
|
|
94
|
+
font-size: 11px;
|
|
95
|
+
font-weight: 600;
|
|
96
|
+
letter-spacing: 0.02em;
|
|
97
|
+
text-transform: uppercase;
|
|
98
|
+
color: #9a9aab;
|
|
99
|
+
margin-bottom: 6px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.three-debug-view-legend-caption {
|
|
103
|
+
margin-top: 6px;
|
|
104
|
+
color: #9a9aab;
|
|
105
|
+
font-size: 11px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.three-debug-view-legend-ramp {
|
|
109
|
+
height: 10px;
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
border: 1px solid rgba( 255, 255, 255, 0.12 );
|
|
112
|
+
margin: 4px 0 6px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.three-debug-view-legend-items {
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-wrap: wrap;
|
|
118
|
+
gap: 8px 12px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.three-debug-view-legend-item {
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
gap: 6px;
|
|
125
|
+
white-space: nowrap;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.three-debug-view-legend-swatch {
|
|
129
|
+
width: 10px;
|
|
130
|
+
height: 10px;
|
|
131
|
+
border-radius: 2px;
|
|
132
|
+
border: 1px solid rgba( 255, 255, 255, 0.2 );
|
|
133
|
+
flex-shrink: 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.three-debug-view-legend-textonly {
|
|
137
|
+
color: #c8c8d4;
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
document.head.appendChild( style );
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function rgbToCss( rgb ) {
|
|
146
|
+
|
|
147
|
+
const r = Math.round( rgb[ 0 ] * 255 );
|
|
148
|
+
const g = Math.round( rgb[ 1 ] * 255 );
|
|
149
|
+
const b = Math.round( rgb[ 2 ] * 255 );
|
|
150
|
+
|
|
151
|
+
return `rgb( ${ r }, ${ g }, ${ b } )`;
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function rampGradient( colors ) {
|
|
156
|
+
|
|
157
|
+
const stops = colors.map( ( c, i ) => `${ rgbToCss( c ) } ${ ( i / ( colors.length - 1 ) ) * 100 }%` );
|
|
158
|
+
|
|
159
|
+
return `linear-gradient( to right, ${ stops.join( ', ' ) } )`;
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function legendRamp( labelLow, labelHigh, colors, caption ) {
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
title: null,
|
|
167
|
+
ramp: rampGradient( colors ),
|
|
168
|
+
rampLabels: [ labelLow, labelHigh ],
|
|
169
|
+
items: null,
|
|
170
|
+
caption
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function legendItems( title, items, caption ) {
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
title,
|
|
179
|
+
ramp: null,
|
|
180
|
+
rampLabels: null,
|
|
181
|
+
items,
|
|
182
|
+
caption
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param {Renderer~DebugConfig} debug
|
|
189
|
+
* @return {?object}
|
|
190
|
+
*/
|
|
191
|
+
function getLegendSpec( debug ) {
|
|
192
|
+
|
|
193
|
+
const view = debug.view;
|
|
194
|
+
const buffer = debug.buffer;
|
|
195
|
+
|
|
196
|
+
if ( view === 'shaderComplexity' || view === 'shaderComplexityAndOverdraw' ) {
|
|
197
|
+
|
|
198
|
+
const budget = debug.shaderComplexityBudget ?? 800;
|
|
199
|
+
|
|
200
|
+
return legendRamp(
|
|
201
|
+
'Low cost',
|
|
202
|
+
`Budget (${ budget })`,
|
|
203
|
+
SHADER_COMPLEXITY_COLORS,
|
|
204
|
+
view === 'shaderComplexityAndOverdraw'
|
|
205
|
+
? 'Shader cost multiplied by overlapping fragment count.'
|
|
206
|
+
: 'Estimated material shading cost.'
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if ( view === 'lightingComplexity' ) {
|
|
212
|
+
|
|
213
|
+
return legendRamp(
|
|
214
|
+
'No lights',
|
|
215
|
+
'~10 lights',
|
|
216
|
+
LIGHT_COMPLEXITY_COLORS,
|
|
217
|
+
'Direct lights per pixel. Shadow casters count as 1.5.'
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if ( view === 'overdraw' ) {
|
|
223
|
+
|
|
224
|
+
const budget = debug.quadOverdrawBudget ?? 10;
|
|
225
|
+
|
|
226
|
+
return legendRamp(
|
|
227
|
+
'1 fragment',
|
|
228
|
+
`Budget (${ budget })`,
|
|
229
|
+
QUAD_OVERDRAW_COLORS,
|
|
230
|
+
'Fragments that pass the depth test per pixel.'
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if ( view === 'lodColoration' ) {
|
|
236
|
+
|
|
237
|
+
const palette = debug.lodColorationColors;
|
|
238
|
+
const items = [];
|
|
239
|
+
|
|
240
|
+
for ( let i = 0; i < DEFAULT_LOD_LABELS.length; i ++ ) {
|
|
241
|
+
|
|
242
|
+
const color = palette && palette[ i ] ? palette[ i ] : DEFAULT_LOD_COLORS[ i ];
|
|
243
|
+
const rgb = color.isColor ? [ color.r, color.g, color.b ] : DEFAULT_LOD_COLORS[ i ];
|
|
244
|
+
|
|
245
|
+
items.push( { color: rgbToCss( rgb ), label: DEFAULT_LOD_LABELS[ i ] } );
|
|
246
|
+
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return legendItems( 'LOD coloration', items, 'Palette matches Unreal LODColorationColors.' );
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if ( view === 'doubleSide' ) {
|
|
254
|
+
|
|
255
|
+
return legendItems( 'Double side', [
|
|
256
|
+
{ color: rgbToCss( [ 0.5, 0.5, 0.5 ] ), label: 'Single-sided or front' },
|
|
257
|
+
{ color: rgbToCss( [ 0.25, 0.45, 0.85 ] ), label: 'Visible back face' },
|
|
258
|
+
{ color: rgbToCss( [ 0.85, 0.12, 0.1 ] ), label: 'Hidden back face' }
|
|
259
|
+
], null );
|
|
260
|
+
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if ( view === 'drawCall' ) {
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
title: 'Draw call',
|
|
267
|
+
ramp: null,
|
|
268
|
+
rampLabels: null,
|
|
269
|
+
items: null,
|
|
270
|
+
caption: 'Each color is one submitted draw. Instanced meshes share one color.'
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if ( view === 'shadowCaster' ) {
|
|
276
|
+
|
|
277
|
+
return legendItems( 'Shadow caster', [
|
|
278
|
+
{ color: rgbToCss( [ 0, 1, 0 ] ), label: 'Casts shadows' },
|
|
279
|
+
{ color: rgbToCss( [ 0.5, 0.5, 0.5 ] ), label: 'Does not cast' }
|
|
280
|
+
], null );
|
|
281
|
+
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if ( view === 'frontBackFace' ) {
|
|
285
|
+
|
|
286
|
+
return legendItems( 'Front / back face', [
|
|
287
|
+
{ color: rgbToCss( [ 0.72, 0.70, 0.66 ] ), label: 'Facing camera' },
|
|
288
|
+
{ color: rgbToCss( [ 0.25, 0.45, 0.85 ] ), label: 'Opposite winding' }
|
|
289
|
+
], null );
|
|
290
|
+
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if ( view === 'bufferVisualization' ) {
|
|
294
|
+
|
|
295
|
+
if ( buffer === 'worldNormal' ) {
|
|
296
|
+
|
|
297
|
+
return legendItems( 'World normal', [
|
|
298
|
+
{ color: rgbToCss( [ 0.5, 0.5, 1 ] ), label: '+X' },
|
|
299
|
+
{ color: rgbToCss( [ 0.5, 1, 0.5 ] ), label: '+Y (up)' },
|
|
300
|
+
{ color: rgbToCss( [ 1, 0.5, 0.5 ] ), label: '+Z' }
|
|
301
|
+
], 'Encoded as normal × 0.5 + 0.5.' );
|
|
302
|
+
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if ( buffer === 'roughness' ) {
|
|
306
|
+
|
|
307
|
+
return legendRamp( 'Smooth', 'Rough', [[ 0, 0, 0 ], [ 1, 1, 1 ]], null );
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if ( buffer === 'metallic' ) {
|
|
312
|
+
|
|
313
|
+
return legendRamp( 'Dielectric', 'Metal', [[ 0, 0, 0 ], [ 1, 1, 1 ]], null );
|
|
314
|
+
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if ( buffer === 'ambientOcclusion' ) {
|
|
318
|
+
|
|
319
|
+
return legendRamp( 'Occluded', 'None', [[ 0.2, 0.2, 0.2 ], [ 1, 1, 1 ]], 'White when no AO map is applied.' );
|
|
320
|
+
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if ( buffer === 'emissive' ) {
|
|
324
|
+
|
|
325
|
+
return legendRamp( 'None', 'Bright', [[ 0, 0, 0 ], [ 1, 1, 1 ]], 'Emissive color only, no lighting.' );
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return null;
|
|
332
|
+
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function renderSpec( root, spec ) {
|
|
336
|
+
|
|
337
|
+
root.replaceChildren();
|
|
338
|
+
|
|
339
|
+
if ( spec.title ) {
|
|
340
|
+
|
|
341
|
+
const title = document.createElement( 'div' );
|
|
342
|
+
title.className = 'three-debug-view-legend-title';
|
|
343
|
+
title.textContent = spec.title;
|
|
344
|
+
root.appendChild( title );
|
|
345
|
+
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if ( spec.ramp ) {
|
|
349
|
+
|
|
350
|
+
const ramp = document.createElement( 'div' );
|
|
351
|
+
ramp.className = 'three-debug-view-legend-ramp';
|
|
352
|
+
ramp.style.background = spec.ramp;
|
|
353
|
+
root.appendChild( ramp );
|
|
354
|
+
|
|
355
|
+
if ( spec.rampLabels ) {
|
|
356
|
+
|
|
357
|
+
const labels = document.createElement( 'div' );
|
|
358
|
+
labels.className = 'three-debug-view-legend-items';
|
|
359
|
+
labels.style.justifyContent = 'space-between';
|
|
360
|
+
labels.style.width = '100%';
|
|
361
|
+
|
|
362
|
+
for ( const label of spec.rampLabels ) {
|
|
363
|
+
|
|
364
|
+
const item = document.createElement( 'span' );
|
|
365
|
+
item.className = 'three-debug-view-legend-item';
|
|
366
|
+
item.textContent = label;
|
|
367
|
+
labels.appendChild( item );
|
|
368
|
+
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
root.appendChild( labels );
|
|
372
|
+
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if ( spec.items ) {
|
|
378
|
+
|
|
379
|
+
const row = document.createElement( 'div' );
|
|
380
|
+
row.className = 'three-debug-view-legend-items';
|
|
381
|
+
|
|
382
|
+
for ( const entry of spec.items ) {
|
|
383
|
+
|
|
384
|
+
const item = document.createElement( 'span' );
|
|
385
|
+
item.className = 'three-debug-view-legend-item';
|
|
386
|
+
|
|
387
|
+
const swatch = document.createElement( 'span' );
|
|
388
|
+
swatch.className = 'three-debug-view-legend-swatch';
|
|
389
|
+
swatch.style.background = entry.color;
|
|
390
|
+
|
|
391
|
+
const text = document.createElement( 'span' );
|
|
392
|
+
text.textContent = entry.label;
|
|
393
|
+
|
|
394
|
+
item.append( swatch, text );
|
|
395
|
+
row.appendChild( item );
|
|
396
|
+
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
root.appendChild( row );
|
|
400
|
+
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if ( spec.caption ) {
|
|
404
|
+
|
|
405
|
+
const caption = document.createElement( 'div' );
|
|
406
|
+
caption.className = spec.items === null && spec.ramp === null
|
|
407
|
+
? 'three-debug-view-legend-textonly'
|
|
408
|
+
: 'three-debug-view-legend-caption';
|
|
409
|
+
caption.textContent = spec.caption;
|
|
410
|
+
root.appendChild( caption );
|
|
411
|
+
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Wraps `renderer.debug` so legend-related assignments refresh the overlay immediately.
|
|
418
|
+
*
|
|
419
|
+
* @param {Renderer} renderer
|
|
420
|
+
* @param {Renderer~DebugConfig} debug
|
|
421
|
+
* @return {Renderer~DebugConfig}
|
|
422
|
+
*/
|
|
423
|
+
function wrapDebugConfigForLegend( renderer, debug ) {
|
|
424
|
+
|
|
425
|
+
return new Proxy( debug, {
|
|
426
|
+
|
|
427
|
+
set( target, prop, value ) {
|
|
428
|
+
|
|
429
|
+
const changed = target[ prop ] !== value;
|
|
430
|
+
|
|
431
|
+
target[ prop ] = value;
|
|
432
|
+
|
|
433
|
+
if ( changed === true && LEGEND_DEBUG_KEYS.has( prop ) ) {
|
|
434
|
+
|
|
435
|
+
renderer._syncDebugViewLegend();
|
|
436
|
+
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return true;
|
|
440
|
+
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
} );
|
|
444
|
+
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* DOM overlay that explains the active `renderer.debug` view.
|
|
449
|
+
*/
|
|
450
|
+
class DebugViewLegend {
|
|
451
|
+
|
|
452
|
+
constructor() {
|
|
453
|
+
|
|
454
|
+
if ( typeof document === 'undefined' ) {
|
|
455
|
+
|
|
456
|
+
this.domElement = null;
|
|
457
|
+
this._parent = null;
|
|
458
|
+
this._signature = '';
|
|
459
|
+
return;
|
|
460
|
+
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
injectStyles();
|
|
464
|
+
|
|
465
|
+
this.domElement = document.createElement( 'div' );
|
|
466
|
+
this.domElement.className = 'three-debug-view-legend';
|
|
467
|
+
this.domElement.hidden = true;
|
|
468
|
+
|
|
469
|
+
this._parent = null;
|
|
470
|
+
this._signature = '';
|
|
471
|
+
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* @param {HTMLElement} parent - Usually the canvas container.
|
|
476
|
+
*/
|
|
477
|
+
_mountParent( parent ) {
|
|
478
|
+
|
|
479
|
+
if ( this.domElement === null || parent === this._parent ) return;
|
|
480
|
+
|
|
481
|
+
if ( this._parent !== null ) {
|
|
482
|
+
|
|
483
|
+
this.domElement.remove();
|
|
484
|
+
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
this._parent = parent;
|
|
488
|
+
|
|
489
|
+
if ( getComputedStyle( parent ).position === 'static' ) {
|
|
490
|
+
|
|
491
|
+
parent.style.position = 'relative';
|
|
492
|
+
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
parent.appendChild( this.domElement );
|
|
496
|
+
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @param {Renderer} renderer
|
|
501
|
+
*/
|
|
502
|
+
sync( renderer ) {
|
|
503
|
+
|
|
504
|
+
if ( this.domElement === null ) return;
|
|
505
|
+
|
|
506
|
+
if ( renderer === null || renderer.debug === undefined ) {
|
|
507
|
+
|
|
508
|
+
this.domElement.hidden = true;
|
|
509
|
+
return;
|
|
510
|
+
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const parent = renderer.domElement.parentElement;
|
|
514
|
+
|
|
515
|
+
if ( parent !== null ) {
|
|
516
|
+
|
|
517
|
+
this._mountParent( parent );
|
|
518
|
+
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const debug = renderer.debug;
|
|
522
|
+
const signature = `${ debug.view }:${ debug.buffer ?? '' }:${ debug.shaderComplexityBudget }:${ debug.quadOverdrawBudget }`;
|
|
523
|
+
|
|
524
|
+
const spec = getLegendSpec( debug );
|
|
525
|
+
|
|
526
|
+
if ( spec === null ) {
|
|
527
|
+
|
|
528
|
+
this.domElement.hidden = true;
|
|
529
|
+
this._signature = '';
|
|
530
|
+
return;
|
|
531
|
+
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
this.domElement.hidden = false;
|
|
535
|
+
|
|
536
|
+
if ( signature !== this._signature ) {
|
|
537
|
+
|
|
538
|
+
renderSpec( this.domElement, spec );
|
|
539
|
+
this._signature = signature;
|
|
540
|
+
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
dispose() {
|
|
546
|
+
|
|
547
|
+
if ( this.domElement !== null ) {
|
|
548
|
+
|
|
549
|
+
this.domElement.remove();
|
|
550
|
+
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
this._parent = null;
|
|
554
|
+
this._signature = '';
|
|
555
|
+
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export { DebugViewLegend, getLegendSpec, wrapDebugConfigForLegend };
|
|
@@ -38,8 +38,10 @@ 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 { DEFAULT_LOD_COLORATION_COLORS } from '../../nodes/display/LODColorationDebug.js';
|
|
41
42
|
import { DEBUG_VIEW_DOUBLE_SIDE, meshCanHideOwnBack } from '../../nodes/display/DoubleSideDebug.js';
|
|
42
43
|
import { DEFAULT_BUFFER } from '../../nodes/display/BufferDebug.js';
|
|
44
|
+
import { DebugViewLegend, wrapDebugConfigForLegend } from './DebugViewLegend.js';
|
|
43
45
|
// !WITH_GENESYS
|
|
44
46
|
import { reference } from '../../nodes/accessors/ReferenceNode.js';
|
|
45
47
|
import { highpModelNormalViewMatrix, highpModelViewMatrix } from '../../nodes/accessors/ModelNode.js';
|
|
@@ -746,7 +748,8 @@ class Renderer {
|
|
|
746
748
|
* @property {?Function} onNodeBuilderCreated - A callback function that is executed after a node builder has been created and before it is built.
|
|
747
749
|
* @property {?Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now.
|
|
748
750
|
* @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object.
|
|
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. `wireframe` draws each mesh as lines along its triangle edges. Lighting stays the same as the shaded view. Shadow passes and fullscreen quads stay triangles.
|
|
751
|
+
* @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. `lodColoration` lights geometry with the palette entry for its LOD index. `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. `wireframe` draws each mesh as lines along its triangle edges. Lighting stays the same as the shaded view. Shadow passes and fullscreen quads stay triangles.
|
|
752
|
+
* @property {Color[]} lodColorationColors - Palette for `lodColoration`. Defaults to Unreal `LODColorationColors`.
|
|
750
753
|
* @property {string} buffer - Channel drawn by `bufferVisualization`: `baseColor`, `worldNormal`, `roughness`, `metallic`, `ambientOcclusion`, or `emissive`.
|
|
751
754
|
* @property {number} shaderComplexityBudget - Proxy budget that fills the shader-complexity ramp.
|
|
752
755
|
* @property {number} quadOverdrawBudget - Overlapping fragments that fill the quad-overdraw ramp.
|
|
@@ -771,6 +774,7 @@ class Renderer {
|
|
|
771
774
|
quadOverdrawBudget: DEFAULT_QUAD_OVERDRAW_BUDGET,
|
|
772
775
|
doubleSideHidden: false,
|
|
773
776
|
doubleSideBack: false,
|
|
777
|
+
lodColorationColors: DEFAULT_LOD_COLORATION_COLORS.map( color => color.clone() ),
|
|
774
778
|
// !WITH_GENESYS
|
|
775
779
|
getShaderAsync: async ( scene, camera, object ) => {
|
|
776
780
|
|
|
@@ -793,8 +797,30 @@ class Renderer {
|
|
|
793
797
|
}
|
|
794
798
|
};
|
|
795
799
|
|
|
800
|
+
this._debugViewLegend = typeof document !== 'undefined' ? new DebugViewLegend() : null;
|
|
801
|
+
this.debug = wrapDebugConfigForLegend( this, this.debug );
|
|
802
|
+
|
|
796
803
|
}
|
|
797
804
|
|
|
805
|
+
// WITH_GENESYS
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Keeps the debug-view legend aligned with `renderer.debug`.
|
|
809
|
+
*
|
|
810
|
+
* @private
|
|
811
|
+
*/
|
|
812
|
+
_syncDebugViewLegend() {
|
|
813
|
+
|
|
814
|
+
if ( this._debugViewLegend !== null ) {
|
|
815
|
+
|
|
816
|
+
this._debugViewLegend.sync( this );
|
|
817
|
+
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// !WITH_GENESYS
|
|
823
|
+
|
|
798
824
|
/**
|
|
799
825
|
* Initializes the renderer so it is ready for usage.
|
|
800
826
|
*
|
|
@@ -862,6 +888,10 @@ class Renderer {
|
|
|
862
888
|
this._animation.start();
|
|
863
889
|
this._initialized = true;
|
|
864
890
|
|
|
891
|
+
// WITH_GENESYS
|
|
892
|
+
this._syncDebugViewLegend();
|
|
893
|
+
// !WITH_GENESYS
|
|
894
|
+
|
|
865
895
|
resolve( this );
|
|
866
896
|
|
|
867
897
|
} );
|
|
@@ -2811,6 +2841,15 @@ class Renderer {
|
|
|
2811
2841
|
|
|
2812
2842
|
this.info.dispose();
|
|
2813
2843
|
|
|
2844
|
+
// WITH_GENESYS
|
|
2845
|
+
if ( this._debugViewLegend !== null ) {
|
|
2846
|
+
|
|
2847
|
+
this._debugViewLegend.dispose();
|
|
2848
|
+
this._debugViewLegend = null;
|
|
2849
|
+
|
|
2850
|
+
}
|
|
2851
|
+
// !WITH_GENESYS
|
|
2852
|
+
|
|
2814
2853
|
this._inspector.dispose();
|
|
2815
2854
|
this._animation.dispose();
|
|
2816
2855
|
this._objects.dispose();
|