@footgun/cobalt 0.8.0 → 0.8.1
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.md +4 -0
- package/bundle.js +3 -3
- package/package.json +1 -1
- package/src/cobalt.js +1 -0
- package/src/displacement/{displacement-composition.ts → displacement-composition.js} +21 -57
- package/src/displacement/displacement-parameters-buffer.js +21 -0
- package/src/displacement/{displacement-texture.ts → displacement-texture.js} +29 -87
- package/src/displacement/{triangles-buffer.ts → triangles-buffer.js} +18 -44
- package/src/light/{lights-buffer.ts → lights-buffer.js} +13 -36
- package/src/light/{lights-renderer.ts → lights-renderer.js} +24 -72
- package/src/light/texture/{lights-texture-initializer.ts → lights-texture-initializer.js} +11 -27
- package/src/light/texture/{lights-texture-mask.ts → lights-texture-mask.js} +36 -87
- package/src/light/texture/{lights-texture.ts → lights-texture.js} +16 -52
- package/src/light/{viewport.ts → viewport.js} +11 -34
- package/src/displacement/displacement-parameters-buffer.ts +0 -44
- package/src/light/types.ts +0 -23
|
@@ -1,57 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import * as wgpuMatrix from "wgpu-matrix";
|
|
4
|
-
import { LightsBuffer } from "./lights-buffer";
|
|
5
|
-
import { LightsTexture, type LightsTextureProperties } from "./texture/lights-texture";
|
|
6
|
-
import { type LightObstacleSegment } from "./texture/lights-texture-mask";
|
|
7
|
-
|
|
8
|
-
type TextureSamplable = {
|
|
9
|
-
readonly view: GPUTextureView;
|
|
10
|
-
readonly sampler: GPUSampler;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
type TextureRenderable = {
|
|
14
|
-
readonly format: GPUTextureFormat;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type Parameters = {
|
|
18
|
-
readonly device: GPUDevice;
|
|
19
|
-
readonly albedo: TextureSamplable;
|
|
20
|
-
readonly targetTexture: TextureRenderable;
|
|
21
|
-
readonly lightsBuffer: LightsBuffer;
|
|
22
|
-
readonly lightsTextureProperties: LightsTextureProperties;
|
|
23
|
-
};
|
|
1
|
+
import { LightsBuffer } from "./lights-buffer.js";
|
|
2
|
+
import { LightsTexture } from "./texture/lights-texture.js";
|
|
24
3
|
|
|
25
4
|
class LightsRenderer {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
private readonly lightsBuffer: LightsBuffer;
|
|
39
|
-
private readonly lightsTexture: LightsTexture;
|
|
40
|
-
|
|
41
|
-
public constructor(params: Parameters) {
|
|
5
|
+
device;
|
|
6
|
+
ambientLight = [0.2, 0.2, 0.2];
|
|
7
|
+
targetTexture;
|
|
8
|
+
renderPipeline;
|
|
9
|
+
uniformsBufferGpu;
|
|
10
|
+
bindgroup0;
|
|
11
|
+
bindgroup1;
|
|
12
|
+
renderBundle;
|
|
13
|
+
lightsBuffer;
|
|
14
|
+
lightsTexture;
|
|
15
|
+
constructor(params) {
|
|
42
16
|
this.device = params.device;
|
|
43
|
-
|
|
44
17
|
this.targetTexture = params.targetTexture;
|
|
45
18
|
this.lightsBuffer = params.lightsBuffer;
|
|
46
|
-
|
|
47
19
|
this.lightsTexture = new LightsTexture(params.device, params.lightsBuffer, params.lightsTextureProperties);
|
|
48
|
-
|
|
49
20
|
this.uniformsBufferGpu = params.device.createBuffer({
|
|
50
21
|
label: "LightsRenderer uniforms buffer",
|
|
51
22
|
size: 80,
|
|
52
23
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
53
24
|
});
|
|
54
|
-
|
|
55
25
|
const shaderModule = params.device.createShaderModule({
|
|
56
26
|
label: "LightsRenderer shader module",
|
|
57
27
|
code: `
|
|
@@ -154,7 +124,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
154
124
|
}
|
|
155
125
|
`,
|
|
156
126
|
});
|
|
157
|
-
|
|
158
127
|
this.renderPipeline = params.device.createRenderPipeline({
|
|
159
128
|
label: "LightsRenderer renderpipeline",
|
|
160
129
|
layout: "auto",
|
|
@@ -166,17 +135,15 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
166
135
|
module: shaderModule,
|
|
167
136
|
entryPoint: "main_fragment",
|
|
168
137
|
targets: [{
|
|
169
|
-
|
|
170
|
-
|
|
138
|
+
format: this.targetTexture.format,
|
|
139
|
+
}],
|
|
171
140
|
},
|
|
172
141
|
primitive: {
|
|
173
142
|
cullMode: "none",
|
|
174
143
|
topology: "triangle-strip",
|
|
175
144
|
},
|
|
176
145
|
});
|
|
177
|
-
|
|
178
146
|
const bindgroupLayout = this.renderPipeline.getBindGroupLayout(0);
|
|
179
|
-
|
|
180
147
|
this.bindgroup0 = params.device.createBindGroup({
|
|
181
148
|
label: "LightsRenderer bindgroup 0",
|
|
182
149
|
layout: bindgroupLayout,
|
|
@@ -205,44 +172,34 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
205
172
|
},
|
|
206
173
|
]
|
|
207
174
|
});
|
|
208
|
-
|
|
209
175
|
this.bindgroup1 = this.buildBindgroup1(params.albedo);
|
|
210
176
|
this.renderBundle = this.buildRenderBundle();
|
|
211
177
|
}
|
|
212
|
-
|
|
213
|
-
public computeLightsTexture(commandEncoder: GPUCommandEncoder): void {
|
|
178
|
+
computeLightsTexture(commandEncoder) {
|
|
214
179
|
this.lightsTexture.update(commandEncoder);
|
|
215
180
|
}
|
|
216
|
-
|
|
217
|
-
public render(renderpassEncoder: GPURenderPassEncoder, invertVpMatrix: wgpuMatrix.Mat4Arg): void {
|
|
181
|
+
render(renderpassEncoder, invertVpMatrix) {
|
|
218
182
|
const uniformsBufferCpu = new ArrayBuffer(80);
|
|
219
183
|
new Float32Array(uniformsBufferCpu, 0, 16).set(invertVpMatrix);
|
|
220
184
|
new Float32Array(uniformsBufferCpu, 64, 3).set(this.ambientLight);
|
|
221
185
|
this.device.queue.writeBuffer(this.uniformsBufferGpu, 0, uniformsBufferCpu);
|
|
222
|
-
|
|
223
186
|
renderpassEncoder.executeBundles([this.renderBundle]);
|
|
224
187
|
}
|
|
225
|
-
|
|
226
|
-
public setAlbedo(albedo: TextureSamplable): void {
|
|
188
|
+
setAlbedo(albedo) {
|
|
227
189
|
this.bindgroup1 = this.buildBindgroup1(albedo);
|
|
228
190
|
this.renderBundle = this.buildRenderBundle();
|
|
229
191
|
}
|
|
230
|
-
|
|
231
|
-
public setAmbientLight(color: [number, number, number]): void {
|
|
192
|
+
setAmbientLight(color) {
|
|
232
193
|
this.ambientLight = [...color];
|
|
233
194
|
}
|
|
234
|
-
|
|
235
|
-
public setObstacles(segments: ReadonlyArray<LightObstacleSegment>): void {
|
|
195
|
+
setObstacles(segments) {
|
|
236
196
|
this.lightsTexture.setObstacles(segments);
|
|
237
197
|
}
|
|
238
|
-
|
|
239
|
-
public destroy(): void {
|
|
198
|
+
destroy() {
|
|
240
199
|
this.uniformsBufferGpu.destroy();
|
|
241
|
-
|
|
242
200
|
this.lightsTexture.destroy();
|
|
243
201
|
}
|
|
244
|
-
|
|
245
|
-
private buildBindgroup1(albedo: TextureSamplable): GPUBindGroup {
|
|
202
|
+
buildBindgroup1(albedo) {
|
|
246
203
|
return this.device.createBindGroup({
|
|
247
204
|
label: "LightsRenderer bindgroup 1",
|
|
248
205
|
layout: this.renderPipeline.getBindGroupLayout(1),
|
|
@@ -258,8 +215,7 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
258
215
|
]
|
|
259
216
|
});
|
|
260
217
|
}
|
|
261
|
-
|
|
262
|
-
private buildRenderBundle(): GPURenderBundle {
|
|
218
|
+
buildRenderBundle() {
|
|
263
219
|
const renderBundleEncoder = this.device.createRenderBundleEncoder({
|
|
264
220
|
label: "LightsRenderer renderbundle encoder",
|
|
265
221
|
colorFormats: [this.targetTexture.format],
|
|
@@ -271,8 +227,4 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
271
227
|
return renderBundleEncoder.finish({ label: "LightsRenderer renderbundle" });
|
|
272
228
|
}
|
|
273
229
|
}
|
|
274
|
-
|
|
275
|
-
export {
|
|
276
|
-
LightsRenderer
|
|
277
|
-
};
|
|
278
|
-
|
|
230
|
+
export { LightsRenderer };
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { LightsBuffer } from "../lights-buffer";
|
|
4
|
-
import { type ILightsTexture } from "./lights-texture";
|
|
1
|
+
import { LightsBuffer } from "../lights-buffer.js";
|
|
5
2
|
|
|
6
3
|
class LightsTextureInitializer {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
private readonly renderBundle: GPURenderBundle;
|
|
13
|
-
|
|
14
|
-
public constructor(device: GPUDevice, lightsBuffer: LightsBuffer, lightsTexture: ILightsTexture, maxLightSize: number) {
|
|
4
|
+
lightsBuffer;
|
|
5
|
+
renderPipeline;
|
|
6
|
+
bindgroup;
|
|
7
|
+
renderBundle;
|
|
8
|
+
constructor(device, lightsBuffer, lightsTexture, maxLightSize) {
|
|
15
9
|
this.lightsBuffer = lightsBuffer;
|
|
16
|
-
|
|
17
10
|
const shaderModule = device.createShaderModule({
|
|
18
11
|
label: "LightsTextureInitializer shader module",
|
|
19
12
|
code: `
|
|
@@ -130,7 +123,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
130
123
|
}
|
|
131
124
|
`,
|
|
132
125
|
});
|
|
133
|
-
|
|
134
126
|
this.renderPipeline = device.createRenderPipeline({
|
|
135
127
|
label: "LightsTextureInitializer renderpipeline",
|
|
136
128
|
layout: "auto",
|
|
@@ -142,8 +134,8 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
142
134
|
module: shaderModule,
|
|
143
135
|
entryPoint: "main_fragment",
|
|
144
136
|
targets: [{
|
|
145
|
-
|
|
146
|
-
|
|
137
|
+
format: lightsTexture.format,
|
|
138
|
+
}],
|
|
147
139
|
},
|
|
148
140
|
primitive: {
|
|
149
141
|
cullMode: "none",
|
|
@@ -153,7 +145,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
153
145
|
count: lightsTexture.sampleCount,
|
|
154
146
|
},
|
|
155
147
|
});
|
|
156
|
-
|
|
157
148
|
this.bindgroup = device.createBindGroup({
|
|
158
149
|
label: "LightsTextureInitializer bindgroup 0",
|
|
159
150
|
layout: this.renderPipeline.getBindGroupLayout(0),
|
|
@@ -164,7 +155,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
164
155
|
},
|
|
165
156
|
]
|
|
166
157
|
});
|
|
167
|
-
|
|
168
158
|
const renderBundleEncoder = device.createRenderBundleEncoder({
|
|
169
159
|
label: "LightsTextureInitializer renderbundle encoder",
|
|
170
160
|
colorFormats: [lightsTexture.format],
|
|
@@ -175,17 +165,11 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
175
165
|
renderBundleEncoder.draw(4);
|
|
176
166
|
this.renderBundle = renderBundleEncoder.finish({ label: "LightsTextureInitializer renderbundle" });
|
|
177
167
|
}
|
|
178
|
-
|
|
179
|
-
public getRenderBundle(): GPURenderBundle {
|
|
168
|
+
getRenderBundle() {
|
|
180
169
|
return this.renderBundle;
|
|
181
170
|
}
|
|
182
|
-
|
|
183
|
-
public destroy(): void {
|
|
171
|
+
destroy() {
|
|
184
172
|
// nothing to do
|
|
185
173
|
}
|
|
186
174
|
}
|
|
187
|
-
|
|
188
|
-
export {
|
|
189
|
-
LightsTextureInitializer
|
|
190
|
-
};
|
|
191
|
-
|
|
175
|
+
export { LightsTextureInitializer };
|
|
@@ -1,37 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { LightsBuffer } from "../lights-buffer";
|
|
4
|
-
import { type Point } from "../types";
|
|
5
|
-
import { type ILightsTexture } from "./lights-texture";
|
|
6
|
-
|
|
7
|
-
type LightObstacleSegment = [Point, Point];
|
|
1
|
+
import { LightsBuffer } from "../lights-buffer.js";
|
|
8
2
|
|
|
9
3
|
class LightsTextureMask {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
private readonly indirectDrawing: {
|
|
20
|
-
readonly bufferCpu: ArrayBuffer;
|
|
21
|
-
readonly bufferGpu: GPUBuffer;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
private obstacles: {
|
|
25
|
-
readonly positionsBufferGpu: GPUBuffer;
|
|
26
|
-
readonly indexBufferGpu: GPUBuffer;
|
|
27
|
-
} | null = null;
|
|
28
|
-
|
|
29
|
-
public constructor(device: GPUDevice, lightsBuffer: LightsBuffer, lightsTexture: ILightsTexture, uniformLightSize: number) {
|
|
4
|
+
device;
|
|
5
|
+
renderPipeline;
|
|
6
|
+
renderBundleEncoderDescriptor;
|
|
7
|
+
renderBundle;
|
|
8
|
+
lightsBuffer;
|
|
9
|
+
indirectDrawing;
|
|
10
|
+
obstacles = null;
|
|
11
|
+
constructor(device, lightsBuffer, lightsTexture, uniformLightSize) {
|
|
30
12
|
this.device = device;
|
|
31
13
|
this.lightsBuffer = lightsBuffer;
|
|
32
|
-
|
|
33
|
-
const obstaclesAreTwoWay = true as boolean;
|
|
34
|
-
|
|
14
|
+
const obstaclesAreTwoWay = true;
|
|
35
15
|
const shaderModule = device.createShaderModule({
|
|
36
16
|
label: "LightsTextureMask shader module",
|
|
37
17
|
code: `
|
|
@@ -94,7 +74,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
94
74
|
}
|
|
95
75
|
`,
|
|
96
76
|
});
|
|
97
|
-
|
|
98
77
|
this.renderPipeline = device.createRenderPipeline({
|
|
99
78
|
label: "LightsTextureMask renderpipeline",
|
|
100
79
|
layout: "auto",
|
|
@@ -135,20 +114,20 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
135
114
|
module: shaderModule,
|
|
136
115
|
entryPoint: "main_fragment",
|
|
137
116
|
targets: [{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
117
|
+
format: lightsTexture.format,
|
|
118
|
+
blend: {
|
|
119
|
+
color: {
|
|
120
|
+
operation: "min",
|
|
121
|
+
srcFactor: "one",
|
|
122
|
+
dstFactor: "one",
|
|
123
|
+
},
|
|
124
|
+
alpha: {
|
|
125
|
+
operation: "min",
|
|
126
|
+
srcFactor: "one",
|
|
127
|
+
dstFactor: "one",
|
|
128
|
+
},
|
|
149
129
|
},
|
|
150
|
-
},
|
|
151
|
-
}],
|
|
130
|
+
}],
|
|
152
131
|
},
|
|
153
132
|
primitive: {
|
|
154
133
|
cullMode: obstaclesAreTwoWay ? "none" : "back",
|
|
@@ -158,7 +137,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
158
137
|
count: lightsTexture.sampleCount,
|
|
159
138
|
},
|
|
160
139
|
});
|
|
161
|
-
|
|
162
140
|
this.indirectDrawing = {
|
|
163
141
|
bufferCpu: new ArrayBuffer(20),
|
|
164
142
|
bufferGpu: device.createBuffer({
|
|
@@ -168,7 +146,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
168
146
|
}),
|
|
169
147
|
};
|
|
170
148
|
this.uploadIndirectDrawingBuffer();
|
|
171
|
-
|
|
172
149
|
this.renderBundleEncoderDescriptor = {
|
|
173
150
|
label: "LightsTextureMask renderbundle encoder",
|
|
174
151
|
colorFormats: [lightsTexture.format],
|
|
@@ -176,32 +153,18 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
176
153
|
};
|
|
177
154
|
this.renderBundle = this.buildRenderBundle();
|
|
178
155
|
}
|
|
179
|
-
|
|
180
|
-
public getRenderBundle(): GPURenderBundle {
|
|
156
|
+
getRenderBundle() {
|
|
181
157
|
return this.renderBundle;
|
|
182
158
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
const indices: number[] = [];
|
|
159
|
+
setObstacles(segments) {
|
|
160
|
+
const positions = [];
|
|
161
|
+
const indices = [];
|
|
187
162
|
for (const segment of segments) {
|
|
188
163
|
const firstQuadIndex = positions.length / 3;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
...segment[0], 0,
|
|
192
|
-
...segment[1], 0,
|
|
193
|
-
...segment[0], 1,
|
|
194
|
-
...segment[1], 1,
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
indices.push(
|
|
198
|
-
firstQuadIndex + 0, firstQuadIndex + 1, firstQuadIndex + 3,
|
|
199
|
-
firstQuadIndex + 0, firstQuadIndex + 3, firstQuadIndex + 2,
|
|
200
|
-
);
|
|
164
|
+
positions.push(...segment[0], 0, ...segment[1], 0, ...segment[0], 1, ...segment[1], 1);
|
|
165
|
+
indices.push(firstQuadIndex + 0, firstQuadIndex + 1, firstQuadIndex + 3, firstQuadIndex + 0, firstQuadIndex + 3, firstQuadIndex + 2);
|
|
201
166
|
}
|
|
202
|
-
|
|
203
167
|
let gpuBuffersChanged = false;
|
|
204
|
-
|
|
205
168
|
const positionsArray = new Float32Array(positions);
|
|
206
169
|
let positionsBufferGpu = this.obstacles?.positionsBufferGpu;
|
|
207
170
|
if (!positionsBufferGpu || positionsBufferGpu.size < positionsArray.byteLength) {
|
|
@@ -214,7 +177,6 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
214
177
|
gpuBuffersChanged = true;
|
|
215
178
|
}
|
|
216
179
|
this.device.queue.writeBuffer(positionsBufferGpu, 0, positionsArray);
|
|
217
|
-
|
|
218
180
|
const indicesArray = new Uint16Array(indices);
|
|
219
181
|
let indexBufferGpu = this.obstacles?.indexBufferGpu;
|
|
220
182
|
if (!indexBufferGpu || indexBufferGpu.size < indicesArray.byteLength) {
|
|
@@ -227,43 +189,35 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
227
189
|
gpuBuffersChanged = true;
|
|
228
190
|
}
|
|
229
191
|
this.device.queue.writeBuffer(indexBufferGpu, 0, indicesArray);
|
|
230
|
-
|
|
231
192
|
this.obstacles = { positionsBufferGpu, indexBufferGpu };
|
|
232
|
-
|
|
233
193
|
this.setIndirectIndexCount(indices.length);
|
|
234
|
-
|
|
235
194
|
if (gpuBuffersChanged) {
|
|
236
195
|
this.renderBundle = this.buildRenderBundle();
|
|
237
196
|
}
|
|
238
197
|
}
|
|
239
|
-
|
|
240
|
-
public setLightsCount(count: number): void {
|
|
198
|
+
setLightsCount(count) {
|
|
241
199
|
this.setIndirectInstanceCount(count);
|
|
242
200
|
}
|
|
243
|
-
|
|
244
|
-
public destroy(): void {
|
|
201
|
+
destroy() {
|
|
245
202
|
this.indirectDrawing.bufferGpu.destroy();
|
|
246
203
|
this.obstacles?.positionsBufferGpu.destroy();
|
|
247
204
|
this.obstacles?.indexBufferGpu.destroy();
|
|
248
205
|
}
|
|
249
|
-
|
|
250
|
-
private setIndirectIndexCount(indexCount: number): void {
|
|
206
|
+
setIndirectIndexCount(indexCount) {
|
|
251
207
|
const drawIndexedIndirectParameters = new Uint32Array(this.indirectDrawing.bufferCpu);
|
|
252
208
|
if (drawIndexedIndirectParameters[0] !== indexCount) {
|
|
253
209
|
drawIndexedIndirectParameters[0] = indexCount;
|
|
254
210
|
this.uploadIndirectDrawingBuffer();
|
|
255
211
|
}
|
|
256
212
|
}
|
|
257
|
-
|
|
258
|
-
private setIndirectInstanceCount(instanceCount: number): void {
|
|
213
|
+
setIndirectInstanceCount(instanceCount) {
|
|
259
214
|
const drawIndexedIndirectParameters = new Uint32Array(this.indirectDrawing.bufferCpu);
|
|
260
215
|
if (drawIndexedIndirectParameters[1] !== instanceCount) {
|
|
261
216
|
drawIndexedIndirectParameters[1] = instanceCount;
|
|
262
217
|
this.uploadIndirectDrawingBuffer();
|
|
263
218
|
}
|
|
264
219
|
}
|
|
265
|
-
|
|
266
|
-
private buildRenderBundle(): GPURenderBundle {
|
|
220
|
+
buildRenderBundle() {
|
|
267
221
|
const renderBundleEncoder = this.device.createRenderBundleEncoder(this.renderBundleEncoderDescriptor);
|
|
268
222
|
if (this.obstacles) {
|
|
269
223
|
renderBundleEncoder.setPipeline(this.renderPipeline);
|
|
@@ -274,13 +228,8 @@ fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
|
274
228
|
}
|
|
275
229
|
return renderBundleEncoder.finish({ label: "LightsTextureMask renderbundle" });
|
|
276
230
|
}
|
|
277
|
-
|
|
278
|
-
private uploadIndirectDrawingBuffer(): void {
|
|
231
|
+
uploadIndirectDrawingBuffer() {
|
|
279
232
|
this.device.queue.writeBuffer(this.indirectDrawing.bufferGpu, 0, this.indirectDrawing.bufferCpu);
|
|
280
233
|
}
|
|
281
234
|
}
|
|
282
|
-
|
|
283
|
-
export {
|
|
284
|
-
LightsTextureMask, type LightObstacleSegment
|
|
285
|
-
};
|
|
286
|
-
|
|
235
|
+
export { LightsTextureMask };
|
|
@@ -1,37 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { type LightsBuffer } from "../lights-buffer";
|
|
4
|
-
import { LightsTextureInitializer } from "./lights-texture-initializer";
|
|
5
|
-
import { type LightObstacleSegment, LightsTextureMask } from "./lights-texture-mask";
|
|
6
|
-
|
|
7
|
-
type ILightsTexture = {
|
|
8
|
-
readonly gridSize: { readonly x: number, readonly y: number };
|
|
9
|
-
readonly format: GPUTextureFormat;
|
|
10
|
-
readonly sampleCount: number;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
type LightsTextureProperties = {
|
|
14
|
-
readonly resolutionPerLight: number;
|
|
15
|
-
readonly maxLightSize: number;
|
|
16
|
-
readonly antialiased: boolean;
|
|
17
|
-
readonly filtering: GPUFilterMode;
|
|
18
|
-
};
|
|
1
|
+
import { LightsTextureInitializer } from "./lights-texture-initializer.js";
|
|
2
|
+
import { LightsTextureMask } from "./lights-texture-mask.js";
|
|
19
3
|
|
|
20
4
|
class LightsTexture {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
private readonly textureInitializer: LightsTextureInitializer;
|
|
30
|
-
private readonly textureMask: LightsTextureMask;
|
|
31
|
-
|
|
32
|
-
public constructor(device: GPUDevice, lightsBuffer: LightsBuffer, lightsTextureProperties: LightsTextureProperties) {
|
|
5
|
+
lightsBuffer;
|
|
6
|
+
texture;
|
|
7
|
+
gridSize;
|
|
8
|
+
textureMultisampled = null;
|
|
9
|
+
textureRenderpassDescriptor;
|
|
10
|
+
textureInitializer;
|
|
11
|
+
textureMask;
|
|
12
|
+
constructor(device, lightsBuffer, lightsTextureProperties) {
|
|
33
13
|
this.lightsBuffer = lightsBuffer;
|
|
34
|
-
|
|
35
14
|
const cellsCount = this.lightsBuffer.maxLightsCount / 4;
|
|
36
15
|
const gridSize = {
|
|
37
16
|
x: Math.ceil(Math.sqrt(cellsCount)),
|
|
@@ -39,12 +18,10 @@ class LightsTexture {
|
|
|
39
18
|
};
|
|
40
19
|
gridSize.y = Math.ceil(cellsCount / gridSize.x);
|
|
41
20
|
this.gridSize = gridSize;
|
|
42
|
-
|
|
43
21
|
const lightTextureSize = {
|
|
44
22
|
width: gridSize.x * lightsTextureProperties.resolutionPerLight,
|
|
45
23
|
height: gridSize.y * lightsTextureProperties.resolutionPerLight,
|
|
46
24
|
};
|
|
47
|
-
|
|
48
25
|
const format = lightsTextureProperties.textureFormat;
|
|
49
26
|
this.texture = device.createTexture({
|
|
50
27
|
label: "LightsTextureMask texture",
|
|
@@ -52,7 +29,6 @@ class LightsTexture {
|
|
|
52
29
|
format,
|
|
53
30
|
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
54
31
|
});
|
|
55
|
-
|
|
56
32
|
if (lightsTextureProperties.antialiased) {
|
|
57
33
|
this.textureMultisampled = device.createTexture({
|
|
58
34
|
label: "LightsTextureMask texture multisampled",
|
|
@@ -62,10 +38,8 @@ class LightsTexture {
|
|
|
62
38
|
sampleCount: 4,
|
|
63
39
|
});
|
|
64
40
|
}
|
|
65
|
-
|
|
66
41
|
const textureToRenderTo = this.textureMultisampled ?? this.texture;
|
|
67
|
-
|
|
68
|
-
const textureRenderpassColorAttachment: GPURenderPassColorAttachment = {
|
|
42
|
+
const textureRenderpassColorAttachment = {
|
|
69
43
|
view: textureToRenderTo.createView(),
|
|
70
44
|
clearValue: [0, 0, 0, 1],
|
|
71
45
|
loadOp: "load",
|
|
@@ -78,8 +52,7 @@ class LightsTexture {
|
|
|
78
52
|
label: "lights-renderer render to texture renderpass",
|
|
79
53
|
colorAttachments: [textureRenderpassColorAttachment],
|
|
80
54
|
};
|
|
81
|
-
|
|
82
|
-
const lightsTexture: ILightsTexture = {
|
|
55
|
+
const lightsTexture = {
|
|
83
56
|
gridSize,
|
|
84
57
|
format,
|
|
85
58
|
sampleCount: this.textureMultisampled?.sampleCount ?? 1,
|
|
@@ -87,10 +60,8 @@ class LightsTexture {
|
|
|
87
60
|
this.textureInitializer = new LightsTextureInitializer(device, lightsBuffer, lightsTexture, lightsTextureProperties.maxLightSize);
|
|
88
61
|
this.textureMask = new LightsTextureMask(device, lightsBuffer, lightsTexture, lightsTextureProperties.maxLightSize);
|
|
89
62
|
}
|
|
90
|
-
|
|
91
|
-
public update(commandEncoder: GPUCommandEncoder): void {
|
|
63
|
+
update(commandEncoder) {
|
|
92
64
|
this.textureMask.setLightsCount(this.lightsBuffer.lightsCount);
|
|
93
|
-
|
|
94
65
|
const renderpassEncoder = commandEncoder.beginRenderPass(this.textureRenderpassDescriptor);
|
|
95
66
|
const [textureWidth, textureHeight] = [this.texture.width, this.texture.height];
|
|
96
67
|
renderpassEncoder.setViewport(0, 0, textureWidth, textureHeight, 0, 1);
|
|
@@ -101,21 +72,14 @@ class LightsTexture {
|
|
|
101
72
|
]);
|
|
102
73
|
renderpassEncoder.end();
|
|
103
74
|
}
|
|
104
|
-
|
|
105
|
-
public setObstacles(segments: ReadonlyArray<LightObstacleSegment>): void {
|
|
75
|
+
setObstacles(segments) {
|
|
106
76
|
this.textureMask.setObstacles(segments);
|
|
107
77
|
}
|
|
108
|
-
|
|
109
|
-
public destroy(): void {
|
|
78
|
+
destroy() {
|
|
110
79
|
this.texture.destroy();
|
|
111
80
|
this.textureMultisampled?.destroy();
|
|
112
|
-
|
|
113
81
|
this.textureInitializer.destroy();
|
|
114
82
|
this.textureMask.destroy();
|
|
115
83
|
}
|
|
116
84
|
}
|
|
117
|
-
|
|
118
|
-
export {
|
|
119
|
-
LightsTexture, type ILightsTexture, type LightsTextureProperties
|
|
120
|
-
};
|
|
121
|
-
|
|
85
|
+
export { LightsTexture };
|
|
@@ -1,54 +1,35 @@
|
|
|
1
1
|
import * as wgpuMatrix from "wgpu-matrix";
|
|
2
|
-
import { type Point } from "./types";
|
|
3
|
-
|
|
4
|
-
type Parameters = {
|
|
5
|
-
readonly viewportSize: {
|
|
6
|
-
width: number;
|
|
7
|
-
height: number;
|
|
8
|
-
};
|
|
9
|
-
readonly center?: Point;
|
|
10
|
-
readonly zoom?: number;
|
|
11
|
-
};
|
|
12
2
|
|
|
13
3
|
class Viewport {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
public constructor(params: Parameters) {
|
|
4
|
+
invViewProjectionMatrix = wgpuMatrix.mat4.identity();
|
|
5
|
+
viewportSize = { width: 1, height: 1 };
|
|
6
|
+
topLeft = [0, 0];
|
|
7
|
+
zoom = 1;
|
|
8
|
+
constructor(params) {
|
|
21
9
|
this.setViewportSize(params.viewportSize.width, params.viewportSize.height);
|
|
22
|
-
|
|
23
10
|
const initialTopLeft = params.center ?? this.topLeft;
|
|
24
11
|
this.setTopLeft(...initialTopLeft);
|
|
25
|
-
|
|
26
12
|
const initialZoom = params.zoom ?? 1;
|
|
27
13
|
this.setZoom(initialZoom);
|
|
28
14
|
}
|
|
29
|
-
|
|
30
|
-
public get invertViewProjectionMatrix(): wgpuMatrix.Mat4Arg {
|
|
15
|
+
get invertViewProjectionMatrix() {
|
|
31
16
|
return this.invViewProjectionMatrix;
|
|
32
17
|
}
|
|
33
|
-
|
|
34
|
-
public setViewportSize(width: number, height: number): void {
|
|
18
|
+
setViewportSize(width, height) {
|
|
35
19
|
this.viewportSize.width = width;
|
|
36
20
|
this.viewportSize.height = height;
|
|
37
21
|
this.updateMatrices();
|
|
38
22
|
}
|
|
39
|
-
|
|
40
|
-
public setTopLeft(x: number, y: number): void {
|
|
23
|
+
setTopLeft(x, y) {
|
|
41
24
|
this.topLeft[0] = x;
|
|
42
25
|
this.topLeft[1] = y;
|
|
43
26
|
this.updateMatrices();
|
|
44
27
|
}
|
|
45
|
-
|
|
46
|
-
public setZoom(zoom: number): void {
|
|
28
|
+
setZoom(zoom) {
|
|
47
29
|
this.zoom = zoom;
|
|
48
30
|
this.updateMatrices();
|
|
49
31
|
}
|
|
50
|
-
|
|
51
|
-
private updateMatrices(): void {
|
|
32
|
+
updateMatrices() {
|
|
52
33
|
wgpuMatrix.mat4.identity(this.invViewProjectionMatrix);
|
|
53
34
|
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.scaling([1, -1, 0]), this.invViewProjectionMatrix, this.invViewProjectionMatrix);
|
|
54
35
|
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.translation([1, 1, 0]), this.invViewProjectionMatrix, this.invViewProjectionMatrix);
|
|
@@ -56,8 +37,4 @@ class Viewport {
|
|
|
56
37
|
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.translation([this.topLeft[0], this.topLeft[1], 0]), this.invViewProjectionMatrix, this.invViewProjectionMatrix);
|
|
57
38
|
}
|
|
58
39
|
}
|
|
59
|
-
|
|
60
|
-
export {
|
|
61
|
-
Viewport
|
|
62
|
-
};
|
|
63
|
-
|
|
40
|
+
export { Viewport };
|