@driftengine/core 4.7.2 → 4.7.4
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/CHANGELOG.json +42 -0
- package/dist/geometry/meshBuilder.js +3 -2
- package/dist/math/exact.js +3 -3
- package/dist/render/backend/webgl2/renderer.js +7 -17
- package/dist/render/backend/webgpu/clusterBinner.js +5 -41
- package/dist/render/backend/webgpu/renderer.js +9 -17
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.js +9 -5
- package/dist/render/clusteredLights.d.ts +136 -13
- package/dist/render/clusteredLights.js +225 -51
- package/dist/render/lightBudget.d.ts +8 -0
- package/dist/render/lightBudget.js +10 -3
- package/dist/render/mesh.js +0 -2
- package/dist/render/plumeRenderer.js +0 -29
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +77 -38
- package/dist/render/shaders/flat/preamble.js +2 -1
- package/dist/render/shaders/generated/flat.wgsl.js +1 -1
- package/dist/scene/node.js +1 -1
- package/package.json +6 -6
- package/src/geometry/meshBuilder.ts +3 -2
- package/src/math/exact.ts +3 -3
- package/src/render/backend/webgl2/renderer.ts +10 -26
- package/src/render/backend/webgpu/clusterBinner.ts +11 -44
- package/src/render/backend/webgpu/linePass.ts +0 -1
- package/src/render/backend/webgpu/renderer.ts +14 -25
- package/src/render/backend/webgpu/shaders/clusterBin.wgsl.ts +9 -5
- package/src/render/clusteredLights.ts +272 -58
- package/src/render/lightBudget.ts +23 -3
- package/src/render/mesh.ts +0 -2
- package/src/render/plumeRenderer.ts +0 -30
- package/src/render/shaders/flat/main.ts +77 -38
- package/src/render/shaders/flat/preamble.ts +2 -0
- package/src/render/shaders/generated/flat.wgsl.ts +1 -1
- package/src/scene/node.ts +1 -1
package/dist/scene/node.js
CHANGED
|
@@ -122,7 +122,7 @@ export class SceneNode {
|
|
|
122
122
|
attachChild(child) {
|
|
123
123
|
if (child === this)
|
|
124
124
|
throw new Error('SceneNode: a node cannot be its own child (cycle)');
|
|
125
|
-
for (let at = this; at !== null; at = at.parent) {
|
|
125
|
+
for (let at = this.parent; at !== null; at = at.parent) {
|
|
126
126
|
if (at === child)
|
|
127
127
|
throw new Error('SceneNode: that would make a cycle');
|
|
128
128
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@driftengine/core",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.4",
|
|
4
4
|
"description": "The runtime of DriftEngine, a WebGPU game engine with a WebGL2 fallback: renderer, loop, input, cameras, scene graph and physics",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@driftengine/drft": "4.7.
|
|
33
|
-
"@driftengine/physics": "4.7.
|
|
32
|
+
"@driftengine/drft": "4.7.4",
|
|
33
|
+
"@driftengine/physics": "4.7.4",
|
|
34
34
|
"gl-matrix": "^3.4.3"
|
|
35
35
|
},
|
|
36
36
|
"author": "Drift Technologies",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"prepack": "node ../../scripts/build.mjs @driftengine/core"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@driftengine/nav": "4.7.
|
|
71
|
-
"@driftengine/network": "4.7.
|
|
72
|
-
"@driftengine/texture": "4.7.
|
|
70
|
+
"@driftengine/nav": "4.7.4",
|
|
71
|
+
"@driftengine/network": "4.7.4",
|
|
72
|
+
"@driftengine/texture": "4.7.4"
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -969,8 +969,9 @@ export class MeshBuilder {
|
|
|
969
969
|
// later one is transported from it, so the choice never shows.
|
|
970
970
|
const ax = Math.abs(tx) < 0.9 ? 1 : 0;
|
|
971
971
|
const ay = Math.abs(tx) < 0.9 ? 0 : 1;
|
|
972
|
-
|
|
973
|
-
|
|
972
|
+
// (ax, ay, 0) x tangent, with the terms the zero removes left out.
|
|
973
|
+
ux = ay * tz;
|
|
974
|
+
uy = -ax * tz;
|
|
974
975
|
uz = ax * ty - ay * tx;
|
|
975
976
|
seeded = true;
|
|
976
977
|
}
|
package/src/math/exact.ts
CHANGED
|
@@ -69,7 +69,7 @@ const PI = 3.141592653589793;
|
|
|
69
69
|
|
|
70
70
|
/* fdlibm's `__kernel_sin` coefficients. */
|
|
71
71
|
const S1 = -1.6666666666666632e-1;
|
|
72
|
-
const S2 = 8.
|
|
72
|
+
const S2 = 8.33333333332249e-3;
|
|
73
73
|
const S3 = -1.984126982985795e-4;
|
|
74
74
|
const S4 = 2.7557313707070068e-6;
|
|
75
75
|
const S5 = -2.5050760253406863e-8;
|
|
@@ -77,7 +77,7 @@ const S6 = 1.5896909952115501e-10;
|
|
|
77
77
|
|
|
78
78
|
/* fdlibm's `__kernel_cos` coefficients. */
|
|
79
79
|
const C1 = 4.1666666666666602e-2;
|
|
80
|
-
const C2 = -1.
|
|
80
|
+
const C2 = -1.388888888887411e-3;
|
|
81
81
|
const C3 = 2.480158728947673e-5;
|
|
82
82
|
const C4 = -2.7557314351390663e-7;
|
|
83
83
|
const C5 = 2.0875723212981748e-9;
|
|
@@ -286,7 +286,7 @@ export function exactLog(x: number): number {
|
|
|
286
286
|
if ((0x000fffff & (2 + hx)) < 3) {
|
|
287
287
|
/* |f| < 2^-20: two terms of the series are the whole answer. */
|
|
288
288
|
if (f === 0) return k === 0 ? 0 : k * LN2_HI + k * LN2_LO;
|
|
289
|
-
const r = f * f * (0.5 - 0.
|
|
289
|
+
const r = f * f * (0.5 - 0.3333333333333333 * f);
|
|
290
290
|
return k === 0 ? f - r : k * LN2_HI - (r - k * LN2_LO - f);
|
|
291
291
|
}
|
|
292
292
|
const s = f / (2 + f);
|
|
@@ -56,12 +56,13 @@ import { boundsVisible } from '../../visibility.ts';
|
|
|
56
56
|
import { createPassRegistry, drainRegistry, passAt, registerIn, unregisterIn } from '../../pass.ts';
|
|
57
57
|
import type { ComputeDefinition, ComputeHandle } from '../../compute.ts';
|
|
58
58
|
import {
|
|
59
|
-
MAX_CLUSTERED_LIGHTS,
|
|
60
59
|
TABLE_HEIGHT,
|
|
61
60
|
TABLE_WIDTH,
|
|
62
61
|
buildLightClusters,
|
|
62
|
+
clusteredMode,
|
|
63
|
+
createClusterLightSet,
|
|
63
64
|
createClusterTable,
|
|
64
|
-
|
|
65
|
+
fillClusterLightSet,
|
|
65
66
|
} from '../../clusteredLights.ts';
|
|
66
67
|
import type {
|
|
67
68
|
PassContext,
|
|
@@ -2211,21 +2212,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2211
2212
|
private clusterTexture: WebGLTexture | null = null;
|
|
2212
2213
|
private clusterTable: Uint32Array | null = null;
|
|
2213
2214
|
/** Refilled per frame; holds references and allocates nothing. See `resolvePointLights`. */
|
|
2214
|
-
private readonly clusterLights
|
|
2215
|
-
count: number;
|
|
2216
|
-
positions: Float32Array;
|
|
2217
|
-
colors: Float32Array;
|
|
2218
|
-
radii: Float32Array;
|
|
2219
|
-
sourceRadii: Float32Array;
|
|
2220
|
-
weights: Float32Array;
|
|
2221
|
-
} = {
|
|
2222
|
-
count: 0,
|
|
2223
|
-
positions: new Float32Array(0),
|
|
2224
|
-
colors: new Float32Array(0),
|
|
2225
|
-
radii: new Float32Array(0),
|
|
2226
|
-
sourceRadii: new Float32Array(0),
|
|
2227
|
-
weights: new Float32Array(0),
|
|
2228
|
-
};
|
|
2215
|
+
private readonly clusterLights = createClusterLightSet();
|
|
2229
2216
|
/** near, far, tan(fovY/2), aspect — written per frame, uploaded as one vec4. */
|
|
2230
2217
|
private readonly clusterFrustum = new Float32Array(4);
|
|
2231
2218
|
|
|
@@ -2378,15 +2365,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2378
2365
|
gl.uniformMatrix4fv(u['uView'] ?? null, false, camera.view);
|
|
2379
2366
|
|
|
2380
2367
|
this.clusterTable ??= createClusterTable();
|
|
2381
|
-
const lights = this.clusterLights;
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
lights.colors = env.lightColors;
|
|
2385
|
-
lights.radii = env.lightRadii;
|
|
2386
|
-
lights.sourceRadii = env.lightSourceRadii ?? env.lightRadii;
|
|
2387
|
-
lights.weights = env.lightWeights;
|
|
2368
|
+
const lights = fillClusterLightSet(env, this.clusterLights);
|
|
2369
|
+
/* A slot is read only under `POINT_SHADOWS`; see `lightHasFixture`. */
|
|
2370
|
+
const shadowSlots = this.quality.pointShadows ? this.lightBudget.maxLights : 0;
|
|
2388
2371
|
buildLightClusters(
|
|
2389
|
-
lights
|
|
2372
|
+
lights,
|
|
2390
2373
|
camera.view as Float32Array,
|
|
2391
2374
|
near,
|
|
2392
2375
|
far,
|
|
@@ -2400,8 +2383,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2400
2383
|
* to name, and saying so here is what stops the shader having to discover it. The shader
|
|
2401
2384
|
* guards the read as well, for a build that reaches it another way.
|
|
2402
2385
|
*/
|
|
2403
|
-
|
|
2386
|
+
shadowSlots,
|
|
2404
2387
|
);
|
|
2388
|
+
gl.uniform1i(u['uClustered'] ?? null, clusteredMode(lights, lights.count, shadowSlots));
|
|
2405
2389
|
gl.texSubImage2D(
|
|
2406
2390
|
gl.TEXTURE_2D,
|
|
2407
2391
|
0,
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CLUSTER_COUNT,
|
|
3
|
-
LIGHT_RECORD,
|
|
4
3
|
LIGHT_TEXELS,
|
|
5
|
-
NO_IES_PROFILE,
|
|
6
|
-
POINT_LIGHT_COS_INNER,
|
|
7
|
-
POINT_LIGHT_COS_OUTER,
|
|
8
4
|
MAX_CLUSTERED_LIGHTS,
|
|
9
5
|
TABLE_HEIGHT,
|
|
10
6
|
TABLE_WIDTH,
|
|
11
7
|
type ClusterLightSet,
|
|
8
|
+
writeLightRecord,
|
|
12
9
|
} from '../../clusteredLights.ts';
|
|
13
10
|
import { MAX_POINT_LIGHTS } from '../../lightBudget.ts';
|
|
14
11
|
import type { ComputeContext, ComputeDefinition, ComputeDevice } from '../../compute.ts';
|
|
@@ -77,7 +74,8 @@ export class ClusterBinner {
|
|
|
77
74
|
private readonly paramsStaging = new ArrayBuffer(PARAMS_BYTES);
|
|
78
75
|
private readonly paramsFloats = new Float32Array(this.paramsStaging);
|
|
79
76
|
private readonly paramsUints = new Uint32Array(this.paramsStaging);
|
|
80
|
-
|
|
77
|
+
/* The records as bits, because one slot holds two halves that must not pass through a float. */
|
|
78
|
+
private readonly lightStaging = new Uint32Array(MAX_CLUSTERED_LIGHTS * LIGHT_TEXELS * 4);
|
|
81
79
|
|
|
82
80
|
private frame: ClusterBinnerFrame | null = null;
|
|
83
81
|
|
|
@@ -172,48 +170,17 @@ export class ClusterBinner {
|
|
|
172
170
|
const count = Math.min(frame.lights.count, MAX_CLUSTERED_LIGHTS);
|
|
173
171
|
|
|
174
172
|
/*
|
|
175
|
-
* The records,
|
|
173
|
+
* The records, by the function `buildLightClusters` writes them with, because the shader
|
|
176
174
|
* copies them into the table verbatim and the lit pass reads one layout on both backends.
|
|
177
175
|
*/
|
|
178
176
|
for (let light = 0; light < count; light++) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
this.lightStaging[at + 6] = frame.lights.colors[light * 3 + 2] ?? 0;
|
|
187
|
-
this.lightStaging[at + 7] = frame.lights.sourceRadii[light] ?? 0;
|
|
188
|
-
this.lightStaging[at + LIGHT_RECORD.weight] = frame.lights.weights[light] ?? 1;
|
|
189
|
-
this.lightStaging[at + LIGHT_RECORD.shadowSlot] = light < frame.shadowSlots ? light : -1;
|
|
190
|
-
/*
|
|
191
|
-
* The cone, addressed through `LIGHT_RECORD` rather than by number. Two writers fill this
|
|
192
|
-
* record — the CPU binner in `clusteredLights.ts` and this — and the 2026-08-17 rule is that
|
|
193
|
-
* two implementations of one decision drift invisibly when the constants are identical. They
|
|
194
|
-
* now read the same table of offsets, so a field can only move in both at once.
|
|
195
|
-
*
|
|
196
|
-
* `POINT_LIGHT_COS_OUTER` and its inner twin are what make a light with no cone collapse to
|
|
197
|
-
* exactly the arithmetic a point light had. `scripts/cluster-check.mjs` compares the two
|
|
198
|
-
* tables byte for byte and is what would catch this being wrong anyway.
|
|
199
|
-
*/
|
|
200
|
-
const directions = frame.lights.directions;
|
|
201
|
-
const cone = frame.lights.coneCos;
|
|
202
|
-
this.lightStaging[at + LIGHT_RECORD.directionX] = directions?.[light * 3] ?? 0;
|
|
203
|
-
this.lightStaging[at + LIGHT_RECORD.directionY] = directions?.[light * 3 + 1] ?? 0;
|
|
204
|
-
this.lightStaging[at + LIGHT_RECORD.directionZ] = directions?.[light * 3 + 2] ?? 0;
|
|
205
|
-
this.lightStaging[at + LIGHT_RECORD.cosInner] = cone?.[light * 2] ?? POINT_LIGHT_COS_INNER;
|
|
206
|
-
this.lightStaging[at + LIGHT_RECORD.cosOuter] =
|
|
207
|
-
cone?.[light * 2 + 1] ?? POINT_LIGHT_COS_OUTER;
|
|
208
|
-
this.lightStaging[at + LIGHT_RECORD.iesProfile] =
|
|
209
|
-
frame.lights.iesProfiles?.[light] ?? NO_IES_PROFILE;
|
|
210
|
-
/* The azimuth reference an asymmetric profile is oriented by; zero where a consumer gave
|
|
211
|
-
none, which the shader reads as no usable reference and leaves on the first plane. */
|
|
212
|
-
const axes = frame.lights.iesAxes;
|
|
213
|
-
this.lightStaging[at + LIGHT_RECORD.iesAxisX] = axes?.[light * 3] ?? 0;
|
|
214
|
-
this.lightStaging[at + LIGHT_RECORD.iesAxisY] = axes?.[light * 3 + 1] ?? 0;
|
|
215
|
-
this.lightStaging[at + LIGHT_RECORD.iesAxisZ] = axes?.[light * 3 + 2] ?? 0;
|
|
216
|
-
this.lightStaging[at + LIGHT_RECORD.cookie] = frame.lights.cookies?.[light] ?? NO_IES_PROFILE;
|
|
177
|
+
writeLightRecord(
|
|
178
|
+
frame.lights,
|
|
179
|
+
light,
|
|
180
|
+
frame.shadowSlots,
|
|
181
|
+
this.lightStaging,
|
|
182
|
+
light * LIGHT_TEXELS * 4,
|
|
183
|
+
);
|
|
217
184
|
}
|
|
218
185
|
|
|
219
186
|
this.paramsFloats.set(frame.view, 0);
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
LINE_VERT_WGSL,
|
|
6
6
|
} from '../../shaders/generated/line.wgsl.ts';
|
|
7
7
|
import { buildSegmentQuads } from '../../segmentQuads.ts';
|
|
8
|
-
import type { LineSegments } from '../../linePoints.ts';
|
|
9
8
|
import type { UniformFields } from './scatterPass.ts';
|
|
10
9
|
import { DEPTH_FORMAT } from './flatPass.ts';
|
|
11
10
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
@@ -553,7 +553,11 @@ import { OcclusionBuffer } from '../../occlusion.ts';
|
|
|
553
553
|
import { boundsVisible } from '../../visibility.ts';
|
|
554
554
|
import { createPassRegistry, drainRegistry, passAt, registerIn, unregisterIn } from '../../pass.ts';
|
|
555
555
|
import { ClusterBinner } from './clusterBinner.ts';
|
|
556
|
-
import {
|
|
556
|
+
import {
|
|
557
|
+
clusteredMode,
|
|
558
|
+
createClusterLightSet,
|
|
559
|
+
fillClusterLightSet,
|
|
560
|
+
} from '../../clusteredLights.ts';
|
|
557
561
|
import {
|
|
558
562
|
computeAt,
|
|
559
563
|
createComputeRegistry,
|
|
@@ -5169,6 +5173,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
5169
5173
|
iesProfiles: new Float32Array(0),
|
|
5170
5174
|
iesAxes: new Float32Array(0),
|
|
5171
5175
|
cookies: new Float32Array(0),
|
|
5176
|
+
heldSourceRadii: new Float32Array(MAX_POINT_LIGHTS),
|
|
5177
|
+
heldWeights: new Float32Array(MAX_POINT_LIGHTS),
|
|
5172
5178
|
};
|
|
5173
5179
|
/** Refilled per frame rather than allocated; see `resolveAtmosphere`. */
|
|
5174
5180
|
private readonly medium: ResolvedAtmosphere = {
|
|
@@ -13548,21 +13554,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
13548
13554
|
/** near, far, tan(fovY/2), aspect. Written per frame into the fragment block. */
|
|
13549
13555
|
private readonly clusterFrustum = new Float32Array(4);
|
|
13550
13556
|
/** Refilled per frame; holds references and allocates nothing. */
|
|
13551
|
-
private readonly clusterLights
|
|
13552
|
-
count: number;
|
|
13553
|
-
positions: Float32Array;
|
|
13554
|
-
colors: Float32Array;
|
|
13555
|
-
radii: Float32Array;
|
|
13556
|
-
sourceRadii: Float32Array;
|
|
13557
|
-
weights: Float32Array;
|
|
13558
|
-
} = {
|
|
13559
|
-
count: 0,
|
|
13560
|
-
positions: new Float32Array(0),
|
|
13561
|
-
colors: new Float32Array(0),
|
|
13562
|
-
radii: new Float32Array(0),
|
|
13563
|
-
sourceRadii: new Float32Array(0),
|
|
13564
|
-
weights: new Float32Array(0),
|
|
13565
|
-
};
|
|
13557
|
+
private readonly clusterLights = createClusterLightSet();
|
|
13566
13558
|
|
|
13567
13559
|
/**
|
|
13568
13560
|
* Reused per dispatch rather than allocated, for the reason `passContext` gives beside it: a
|
|
@@ -13662,21 +13654,18 @@ export class WebGPURenderer implements RendererApi {
|
|
|
13662
13654
|
f[frustumAt + 3] = aspect;
|
|
13663
13655
|
f.set(camera.view as Float32Array, at('uView'));
|
|
13664
13656
|
|
|
13665
|
-
const set = this.clusterLights;
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
set.radii = env.lightRadii;
|
|
13670
|
-
set.sourceRadii = env.lightSourceRadii ?? env.lightRadii;
|
|
13671
|
-
set.weights = env.lightWeights;
|
|
13657
|
+
const set = fillClusterLightSet(env, this.clusterLights);
|
|
13658
|
+
/* A slot is read only under `POINT_SHADOWS`; see `lightHasFixture`. */
|
|
13659
|
+
const shadowSlots = this.quality.pointShadows ? MAX_POINT_LIGHTS : 0;
|
|
13660
|
+
i[at('uClustered')] = clusteredMode(set, set.count, shadowSlots);
|
|
13672
13661
|
binner.setFrame({
|
|
13673
|
-
lights: set
|
|
13662
|
+
lights: set,
|
|
13674
13663
|
view: camera.view as Float32Array,
|
|
13675
13664
|
near,
|
|
13676
13665
|
far,
|
|
13677
13666
|
tanHalfFovY,
|
|
13678
13667
|
aspect,
|
|
13679
|
-
shadowSlots
|
|
13668
|
+
shadowSlots,
|
|
13680
13669
|
});
|
|
13681
13670
|
this.dispatchCompute(this.clusterHandle);
|
|
13682
13671
|
}
|
|
@@ -54,8 +54,12 @@ struct Params {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
@group(0) @binding(0) var<uniform> params: Params;
|
|
57
|
-
/**
|
|
58
|
-
|
|
57
|
+
/**
|
|
58
|
+
* The records as \`writeLightRecord\` lays them out, as bits. **\`u32\`, not \`f32\`**, because one
|
|
59
|
+
* slot holds two halves, and a zero weight read as a float would be a subnormal a GPU is free to
|
|
60
|
+
* flush on the way through; read as bits, the copy into the table cannot change them.
|
|
61
|
+
*/
|
|
62
|
+
@group(0) @binding(1) var<storage, read> lights: array<vec4<u32>>;
|
|
59
63
|
/**
|
|
60
64
|
* Write-only, which is all core WGSL offers and all the fixed-slot layout needs.
|
|
61
65
|
*
|
|
@@ -81,7 +85,7 @@ fn distanceSqToBounds(p: vec3<f32>, lo: vec3<f32>, hi: vec3<f32>) -> f32 {
|
|
|
81
85
|
|
|
82
86
|
/** A light's view-space centre, with depth positive along the view direction. */
|
|
83
87
|
fn viewOf(light: u32) -> vec3<f32> {
|
|
84
|
-
let world = lights[light * LIGHT_TEXELS];
|
|
88
|
+
let world = bitcast<vec4<f32>>(lights[light * LIGHT_TEXELS]);
|
|
85
89
|
let v = params.view * vec4<f32>(world.xyz, 1.0);
|
|
86
90
|
return vec3<f32>(v.x, v.y, -v.z);
|
|
87
91
|
}
|
|
@@ -113,7 +117,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
113
117
|
if (id < params.lightCount) {
|
|
114
118
|
let record = id * LIGHT_TEXELS;
|
|
115
119
|
for (var t: u32 = 0u; t < LIGHT_TEXELS; t = t + 1u) {
|
|
116
|
-
textureStore(table, texelAt(record + t),
|
|
120
|
+
textureStore(table, texelAt(record + t), lights[record + t]);
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -157,7 +161,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
157
161
|
|
|
158
162
|
/* Increasing light index, which is what makes the list sorted without a sort. */
|
|
159
163
|
for (var light: u32 = 0u; light < params.lightCount; light = light + 1u) {
|
|
160
|
-
let radius = lights[light * LIGHT_TEXELS].w;
|
|
164
|
+
let radius = bitcast<f32>(lights[light * LIGHT_TEXELS].w);
|
|
161
165
|
let v = viewOf(light);
|
|
162
166
|
if (v.z + radius <= 0.0) {
|
|
163
167
|
continue;
|