@gnsx/three 0.185.4 → 0.185.6
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 +16 -0
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +16 -0
- package/build/three.webgpu.nodes.min.js +1 -1
- package/examples/jsm/lighting/LightProbeGrid.js +40 -43
- package/package.json +1 -1
- package/src/renderers/webgpu/WebGPUBackend.js +5 -0
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +11 -0
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
storageTexture,
|
|
34
34
|
textureStore,
|
|
35
35
|
uniform,
|
|
36
|
+
uint,
|
|
36
37
|
uvec3,
|
|
37
38
|
vec3,
|
|
38
39
|
vec4
|
|
@@ -102,11 +103,11 @@ const ATLAS_PADDING = 1;
|
|
|
102
103
|
* Atlas layout (nz = resolution.z, PADDING = 1):
|
|
103
104
|
* ```
|
|
104
105
|
* slice 0 : padding (copy of sub-volume 0, data slice 0)
|
|
105
|
-
* slices 1
|
|
106
|
+
* slices 1 to nz : sub-volume 0 data
|
|
106
107
|
* slice nz + 1 : padding (copy of sub-volume 0, data slice nz-1)
|
|
107
108
|
* slice nz + 2 : padding (copy of sub-volume 1, data slice 0)
|
|
108
|
-
* slices nz+3
|
|
109
|
-
*
|
|
109
|
+
* slices nz+3 to 2*nz+2 : sub-volume 1 data
|
|
110
|
+
* ...
|
|
110
111
|
* ```
|
|
111
112
|
* Total atlas depth = `7 * ( nz + 2 )`.
|
|
112
113
|
*
|
|
@@ -279,7 +280,7 @@ class LightProbeGrid extends Object3D {
|
|
|
279
280
|
/**
|
|
280
281
|
* Bakes all probes by rendering cubemaps at each probe position
|
|
281
282
|
* and projecting to L2 SH. Optionally iterates additional passes to
|
|
282
|
-
* capture indirect bounces
|
|
283
|
+
* capture indirect bounces - each extra pass samples the previous pass's
|
|
283
284
|
* atlas as indirect light, so a grid added to the scene before baking
|
|
284
285
|
* accumulates one bounce per extra pass.
|
|
285
286
|
*
|
|
@@ -328,7 +329,7 @@ class LightProbeGrid extends Object3D {
|
|
|
328
329
|
renderer.getScissor( _currentScissor );
|
|
329
330
|
const currentScissorTest = renderer.getScissorTest();
|
|
330
331
|
|
|
331
|
-
// Scene is static across the bake
|
|
332
|
+
// Scene is static across the bake - update once and disable per-render auto updates.
|
|
332
333
|
const currentMatrixWorldAutoUpdate = scene.matrixWorldAutoUpdate;
|
|
333
334
|
if ( currentMatrixWorldAutoUpdate === true ) {
|
|
334
335
|
|
|
@@ -337,7 +338,7 @@ class LightProbeGrid extends Object3D {
|
|
|
337
338
|
|
|
338
339
|
}
|
|
339
340
|
|
|
340
|
-
// Disable shadow map auto-update across all passes
|
|
341
|
+
// Disable shadow map auto-update across all passes - lights don't move.
|
|
341
342
|
// Force a single shadow update on the first render so maps are initialized.
|
|
342
343
|
const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
|
|
343
344
|
renderer.shadowMap.autoUpdate = false;
|
|
@@ -351,7 +352,7 @@ class LightProbeGrid extends Object3D {
|
|
|
351
352
|
// const t0 = performance.now();
|
|
352
353
|
|
|
353
354
|
// Pass 0 captures direct light only (grid hidden, so probesSH is not sampled
|
|
354
|
-
//
|
|
355
|
+
// the atlas at this point may be uninitialized or hold a prior bake).
|
|
355
356
|
// Each subsequent pass keeps the grid visible so the cube cameras read the
|
|
356
357
|
// previous pass's atlas as indirect light, accumulating one bounce per pass.
|
|
357
358
|
// Phase 1 writes to the batch target and Phase 2 only swaps it into the atlas
|
|
@@ -439,11 +440,11 @@ class LightProbeGrid extends Object3D {
|
|
|
439
440
|
|
|
440
441
|
}
|
|
441
442
|
|
|
442
|
-
// Phase 2: Repack SH data from batch target into the atlas 3D texture
|
|
443
|
+
// Phase 2: Repack SH data from batch target into the atlas 3D texture on the GPU.
|
|
443
444
|
//
|
|
444
445
|
// For each of the 7 packed sub-volumes (texture index t) we write:
|
|
445
446
|
// - A leading padding slice (copy of data slice iz = 0)
|
|
446
|
-
// - All nz data slices (iz = 0
|
|
447
|
+
// - All nz data slices (iz = 0 to nz-1)
|
|
447
448
|
// - A trailing padding slice (copy of data slice iz = nz-1)
|
|
448
449
|
//
|
|
449
450
|
// In the atlas the slices for sub-volume t occupy the range:
|
|
@@ -675,31 +676,6 @@ class LightProbeGrid extends Object3D {
|
|
|
675
676
|
|
|
676
677
|
renderer.shadowMap.autoUpdate = savedShadowAutoUpdate;
|
|
677
678
|
|
|
678
|
-
// Padding slices (GPU-to-GPU copy of nearest edge data slices).
|
|
679
|
-
const atlas = this.texture;
|
|
680
|
-
|
|
681
|
-
for ( let textureIndex = 0; textureIndex < 7; textureIndex ++ ) {
|
|
682
|
-
|
|
683
|
-
const baseSlice = textureIndex * paddedSlices;
|
|
684
|
-
const dataSlice = baseSlice + ATLAS_PADDING;
|
|
685
|
-
const trailingSlice = dataSlice + nz;
|
|
686
|
-
|
|
687
|
-
renderer.copyTextureToTexture(
|
|
688
|
-
atlas,
|
|
689
|
-
atlas,
|
|
690
|
-
new Box3( new Vector3( 0, 0, dataSlice ), new Vector3( nx, ny, dataSlice + 1 ) ),
|
|
691
|
-
new Vector3( 0, 0, baseSlice )
|
|
692
|
-
);
|
|
693
|
-
|
|
694
|
-
renderer.copyTextureToTexture(
|
|
695
|
-
atlas,
|
|
696
|
-
atlas,
|
|
697
|
-
new Box3( new Vector3( 0, 0, dataSlice + nz - 1 ), new Vector3( nx, ny, dataSlice + nz ) ),
|
|
698
|
-
new Vector3( 0, 0, trailingSlice )
|
|
699
|
-
);
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
|
|
703
679
|
await renderer.backend.device.queue.onSubmittedWorkDone();
|
|
704
680
|
|
|
705
681
|
}
|
|
@@ -1142,7 +1118,7 @@ function _ensureWebGPUComputeResources( cubemapSize, envMapTexture, atlasTexture
|
|
|
1142
1118
|
totalWeight.addAssign( weight );
|
|
1143
1119
|
|
|
1144
1120
|
const dir = coord.normalize();
|
|
1145
|
-
// Pass explicit direction
|
|
1121
|
+
// Pass explicit direction; omitting UV would default to reflectVector (needs camera).
|
|
1146
1122
|
const cw = cubeTexture( envMapTexture, coord ).rgb.mul( weight );
|
|
1147
1123
|
|
|
1148
1124
|
accum0.addAssign( cw.mul( 0.282095 ) );
|
|
@@ -1172,35 +1148,56 @@ function _ensureWebGPUComputeResources( cubemapSize, envMapTexture, atlasTexture
|
|
|
1172
1148
|
|
|
1173
1149
|
Loop( { end: 7, name: 't', type: 'int' }, ( { t } ) => {
|
|
1174
1150
|
|
|
1175
|
-
const
|
|
1151
|
+
const baseSlice = paddedSlices.mul( t );
|
|
1152
|
+
const atlasZ = baseSlice.add( 1 ).add( probeIz );
|
|
1153
|
+
const trailingSlice = baseSlice.add( paddedSlices ).sub( 1 );
|
|
1154
|
+
const lastDataSlice = paddedSlices.sub( 3 );
|
|
1155
|
+
const storeProbeValue = ( value ) => {
|
|
1156
|
+
|
|
1157
|
+
textureStore( atlas, uvec3( probeIx, probeIy, atlasZ ), value ).toWriteOnly();
|
|
1158
|
+
|
|
1159
|
+
// Write padding during the compute pass; WebGPU validation rejects atlas-to-itself copies.
|
|
1160
|
+
If( probeIz.equal( uint( 0 ) ), () => {
|
|
1161
|
+
|
|
1162
|
+
textureStore( atlas, uvec3( probeIx, probeIy, baseSlice ), value ).toWriteOnly();
|
|
1163
|
+
|
|
1164
|
+
} );
|
|
1165
|
+
|
|
1166
|
+
If( probeIz.equal( lastDataSlice ), () => {
|
|
1167
|
+
|
|
1168
|
+
textureStore( atlas, uvec3( probeIx, probeIy, trailingSlice ), value ).toWriteOnly();
|
|
1169
|
+
|
|
1170
|
+
} );
|
|
1171
|
+
|
|
1172
|
+
};
|
|
1176
1173
|
|
|
1177
1174
|
If( t.equal( int( 0 ) ), () => {
|
|
1178
1175
|
|
|
1179
|
-
|
|
1176
|
+
storeProbeValue( vec4( c0.x, c0.y, c0.z, c1.x ) );
|
|
1180
1177
|
|
|
1181
1178
|
} ).ElseIf( t.equal( int( 1 ) ), () => {
|
|
1182
1179
|
|
|
1183
|
-
|
|
1180
|
+
storeProbeValue( vec4( c1.y, c1.z, c2.x, c2.y ) );
|
|
1184
1181
|
|
|
1185
1182
|
} ).ElseIf( t.equal( int( 2 ) ), () => {
|
|
1186
1183
|
|
|
1187
|
-
|
|
1184
|
+
storeProbeValue( vec4( c2.z, c3.x, c3.y, c3.z ) );
|
|
1188
1185
|
|
|
1189
1186
|
} ).ElseIf( t.equal( int( 3 ) ), () => {
|
|
1190
1187
|
|
|
1191
|
-
|
|
1188
|
+
storeProbeValue( vec4( c4.x, c4.y, c4.z, c5.x ) );
|
|
1192
1189
|
|
|
1193
1190
|
} ).ElseIf( t.equal( int( 4 ) ), () => {
|
|
1194
1191
|
|
|
1195
|
-
|
|
1192
|
+
storeProbeValue( vec4( c5.y, c5.z, c6.x, c6.y ) );
|
|
1196
1193
|
|
|
1197
1194
|
} ).ElseIf( t.equal( int( 5 ) ), () => {
|
|
1198
1195
|
|
|
1199
|
-
|
|
1196
|
+
storeProbeValue( vec4( c6.z, c7.x, c7.y, c7.z ) );
|
|
1200
1197
|
|
|
1201
1198
|
} ).Else( () => {
|
|
1202
1199
|
|
|
1203
|
-
|
|
1200
|
+
storeProbeValue( vec4( c8.x, c8.y, c8.z, float( 0 ) ) );
|
|
1204
1201
|
|
|
1205
1202
|
} );
|
|
1206
1203
|
|
package/package.json
CHANGED
|
@@ -2267,6 +2267,11 @@ class WebGPUBackend extends Backend {
|
|
|
2267
2267
|
|
|
2268
2268
|
const baseOffset = timestampQueryPool.allocateQueriesForContext( uid );
|
|
2269
2269
|
|
|
2270
|
+
// WITH_GENESYS
|
|
2271
|
+
// If query allocation fails, leave timestampWrites unset so WebGPU doesn't receive a null querySet.
|
|
2272
|
+
if ( baseOffset === null || timestampQueryPool.querySet === null ) return;
|
|
2273
|
+
// !WITH_GENESYS
|
|
2274
|
+
|
|
2270
2275
|
_renderPassTimestampWrites.querySet = timestampQueryPool.querySet;
|
|
2271
2276
|
_renderPassTimestampWrites.beginningOfPassWriteIndex = baseOffset;
|
|
2272
2277
|
_renderPassTimestampWrites.endOfPassWriteIndex = baseOffset + 1;
|
|
@@ -250,6 +250,17 @@ class WebGPUTextureUtils {
|
|
|
250
250
|
if ( bindingData.sampler !== undefined ) {
|
|
251
251
|
|
|
252
252
|
const samplerData = this._samplerCache.get( bindingData.samplerKey );
|
|
253
|
+
// WITH_GENESYS
|
|
254
|
+
// Binding disposal can be reached more than once during renderer teardown; tolerate stale sampler cache data.
|
|
255
|
+
if ( samplerData === undefined ) {
|
|
256
|
+
|
|
257
|
+
bindingData.sampler = undefined;
|
|
258
|
+
bindingData.samplerKey = undefined;
|
|
259
|
+
return;
|
|
260
|
+
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// !WITH_GENESYS
|
|
253
264
|
samplerData.usedTimes --;
|
|
254
265
|
|
|
255
266
|
if ( samplerData.usedTimes === 0 ) {
|