@multiplekex/shallot 0.2.3 → 0.2.5
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/package.json +1 -1
- package/src/extras/arrows/index.ts +3 -3
- package/src/extras/caustic.ts +37 -0
- package/src/extras/gradient/index.ts +63 -69
- package/src/extras/index.ts +3 -0
- package/src/extras/lines/index.ts +3 -3
- package/src/extras/skylab/index.ts +314 -0
- package/src/extras/text/font.ts +69 -14
- package/src/extras/text/index.ts +15 -7
- package/src/extras/text/sdf.ts +13 -2
- package/src/extras/water.ts +64 -0
- package/src/standard/defaults.ts +2 -0
- package/src/standard/index.ts +2 -0
- package/src/standard/raster/index.ts +517 -0
- package/src/standard/{render → raytracing}/bvh/blas.ts +3 -3
- package/src/standard/{render → raytracing}/bvh/tlas.ts +3 -0
- package/src/standard/{render → raytracing}/depth.ts +9 -9
- package/src/standard/raytracing/index.ts +380 -0
- package/src/standard/{render → raytracing}/instance.ts +3 -0
- package/src/standard/raytracing/shaders.ts +815 -0
- package/src/standard/{render → raytracing}/triangle.ts +1 -1
- package/src/standard/render/camera.ts +88 -80
- package/src/standard/render/index.ts +68 -208
- package/src/standard/render/indirect.ts +9 -10
- package/src/standard/render/mesh/index.ts +35 -166
- package/src/standard/render/overlay.ts +4 -4
- package/src/standard/render/pass.ts +1 -1
- package/src/standard/render/postprocess.ts +75 -50
- package/src/standard/render/scene.ts +28 -16
- package/src/standard/render/surface/compile.ts +6 -8
- package/src/standard/render/surface/noise.ts +15 -2
- package/src/standard/render/surface/shaders.ts +257 -0
- package/src/standard/render/surface/structs.ts +13 -6
- package/src/standard/render/forward/index.ts +0 -259
- package/src/standard/render/forward/raster.ts +0 -228
- package/src/standard/render/shaders.ts +0 -484
- package/src/standard/render/surface/wgsl.ts +0 -573
- /package/src/standard/{render → raytracing}/bvh/radix.ts +0 -0
- /package/src/standard/{render → raytracing}/bvh/structs.ts +0 -0
- /package/src/standard/{render → raytracing}/bvh/traverse.ts +0 -0
- /package/src/standard/{render → raytracing}/intersection.ts +0 -0
- /package/src/standard/{render → raytracing}/ray.ts +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MAX_ENTITIES } from "../../../core";
|
|
2
|
-
import { setTraits, type
|
|
2
|
+
import { setTraits, createFieldProxy, type FieldProxy } from "../../../core/component";
|
|
3
3
|
import { createEntityIdBuffer } from "../../compute";
|
|
4
4
|
import { writeIndirect } from "../indirect";
|
|
5
5
|
import { createBox } from "./box";
|
|
@@ -7,7 +7,7 @@ import { createSphere } from "./sphere";
|
|
|
7
7
|
import { createPlane } from "./plane";
|
|
8
8
|
|
|
9
9
|
export const MAX_SURFACES = 16;
|
|
10
|
-
export const MAX_BATCH_SLOTS =
|
|
10
|
+
export const MAX_BATCH_SLOTS = 256;
|
|
11
11
|
const INVALID_SHAPE = 0xffffffff;
|
|
12
12
|
|
|
13
13
|
const batchEntityIds = new Uint32Array(MAX_ENTITIES);
|
|
@@ -81,11 +81,7 @@ export const Volume = {
|
|
|
81
81
|
HalfSpace: 1,
|
|
82
82
|
} as const;
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
function colorProxy(): ColorProxy {
|
|
87
|
-
const data = MeshColors.data;
|
|
88
|
-
|
|
84
|
+
function hexColorProxy(data: Float32Array): FieldProxy {
|
|
89
85
|
function getValue(eid: number): number {
|
|
90
86
|
const offset = eid * 4;
|
|
91
87
|
const r = Math.round(data[offset] * 255);
|
|
@@ -101,67 +97,7 @@ function colorProxy(): ColorProxy {
|
|
|
101
97
|
data[offset + 2] = (value & 0xff) / 255;
|
|
102
98
|
}
|
|
103
99
|
|
|
104
|
-
return new Proxy([] as unknown as
|
|
105
|
-
get(_, prop) {
|
|
106
|
-
if (prop === "get") return getValue;
|
|
107
|
-
if (prop === "set") return setValue;
|
|
108
|
-
const eid = Number(prop);
|
|
109
|
-
if (Number.isNaN(eid)) return undefined;
|
|
110
|
-
return getValue(eid);
|
|
111
|
-
},
|
|
112
|
-
set(_, prop, value) {
|
|
113
|
-
const eid = Number(prop);
|
|
114
|
-
if (Number.isNaN(eid)) return false;
|
|
115
|
-
setValue(eid, value);
|
|
116
|
-
return true;
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
interface ColorChannelProxy extends Array<number>, FieldAccessor {}
|
|
122
|
-
|
|
123
|
-
function colorChannelProxy(channelIndex: number): ColorChannelProxy {
|
|
124
|
-
const data = MeshColors.data;
|
|
125
|
-
|
|
126
|
-
function getValue(eid: number): number {
|
|
127
|
-
return data[eid * 4 + channelIndex];
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function setValue(eid: number, value: number): void {
|
|
131
|
-
data[eid * 4 + channelIndex] = value;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return new Proxy([] as unknown as ColorChannelProxy, {
|
|
135
|
-
get(_, prop) {
|
|
136
|
-
if (prop === "get") return getValue;
|
|
137
|
-
if (prop === "set") return setValue;
|
|
138
|
-
const eid = Number(prop);
|
|
139
|
-
if (Number.isNaN(eid)) return undefined;
|
|
140
|
-
return getValue(eid);
|
|
141
|
-
},
|
|
142
|
-
set(_, prop, value) {
|
|
143
|
-
const eid = Number(prop);
|
|
144
|
-
if (Number.isNaN(eid)) return false;
|
|
145
|
-
setValue(eid, value);
|
|
146
|
-
return true;
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
interface SizeProxy extends Array<number>, FieldAccessor {}
|
|
152
|
-
|
|
153
|
-
function sizeProxy(component: number): SizeProxy {
|
|
154
|
-
const data = MeshSizes.data;
|
|
155
|
-
|
|
156
|
-
function getValue(eid: number): number {
|
|
157
|
-
return data[eid * 4 + component];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function setValue(eid: number, value: number): void {
|
|
161
|
-
data[eid * 4 + component] = value;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return new Proxy([] as unknown as SizeProxy, {
|
|
100
|
+
return new Proxy([] as unknown as FieldProxy, {
|
|
165
101
|
get(_, prop) {
|
|
166
102
|
if (prop === "get") return getValue;
|
|
167
103
|
if (prop === "set") return setValue;
|
|
@@ -178,86 +114,19 @@ function sizeProxy(component: number): SizeProxy {
|
|
|
178
114
|
});
|
|
179
115
|
}
|
|
180
116
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
function pbrProxy(component: number, defaultValue: number): PBRProxy {
|
|
117
|
+
function roughnessProxy(): FieldProxy {
|
|
184
118
|
const data = MeshPBR.data;
|
|
185
119
|
|
|
186
120
|
function getValue(eid: number): number {
|
|
187
|
-
const val = data[eid * 4
|
|
188
|
-
return val === 0
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function setValue(eid: number, value: number): void {
|
|
192
|
-
data[eid * 4 + component] = value;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return new Proxy([] as unknown as PBRProxy, {
|
|
196
|
-
get(_, prop) {
|
|
197
|
-
if (prop === "get") return getValue;
|
|
198
|
-
if (prop === "set") return setValue;
|
|
199
|
-
const eid = Number(prop);
|
|
200
|
-
if (Number.isNaN(eid)) return undefined;
|
|
201
|
-
return getValue(eid);
|
|
202
|
-
},
|
|
203
|
-
set(_, prop, value) {
|
|
204
|
-
const eid = Number(prop);
|
|
205
|
-
if (Number.isNaN(eid)) return false;
|
|
206
|
-
setValue(eid, value);
|
|
207
|
-
return true;
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
interface EmissionProxy extends Array<number>, FieldAccessor {}
|
|
213
|
-
|
|
214
|
-
function emissionProxy(): EmissionProxy {
|
|
215
|
-
const data = MeshEmission.data;
|
|
216
|
-
|
|
217
|
-
function getValue(eid: number): number {
|
|
218
|
-
const offset = eid * 4;
|
|
219
|
-
const r = Math.round(data[offset] * 255);
|
|
220
|
-
const g = Math.round(data[offset + 1] * 255);
|
|
221
|
-
const b = Math.round(data[offset + 2] * 255);
|
|
222
|
-
return (r << 16) | (g << 8) | b;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function setValue(eid: number, value: number): void {
|
|
226
|
-
const offset = eid * 4;
|
|
227
|
-
data[offset] = ((value >> 16) & 0xff) / 255;
|
|
228
|
-
data[offset + 1] = ((value >> 8) & 0xff) / 255;
|
|
229
|
-
data[offset + 2] = (value & 0xff) / 255;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return new Proxy([] as unknown as EmissionProxy, {
|
|
233
|
-
get(_, prop) {
|
|
234
|
-
if (prop === "get") return getValue;
|
|
235
|
-
if (prop === "set") return setValue;
|
|
236
|
-
const eid = Number(prop);
|
|
237
|
-
if (Number.isNaN(eid)) return undefined;
|
|
238
|
-
return getValue(eid);
|
|
239
|
-
},
|
|
240
|
-
set(_, prop, value) {
|
|
241
|
-
const eid = Number(prop);
|
|
242
|
-
if (Number.isNaN(eid)) return false;
|
|
243
|
-
setValue(eid, value);
|
|
244
|
-
return true;
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function emissionIntensityProxy(): PBRProxy {
|
|
250
|
-
const data = MeshEmission.data;
|
|
251
|
-
|
|
252
|
-
function getValue(eid: number): number {
|
|
253
|
-
return data[eid * 4 + 3];
|
|
121
|
+
const val = data[eid * 4];
|
|
122
|
+
return val === 0 ? 0.9 : val;
|
|
254
123
|
}
|
|
255
124
|
|
|
256
125
|
function setValue(eid: number, value: number): void {
|
|
257
|
-
data[eid * 4
|
|
126
|
+
data[eid * 4] = value;
|
|
258
127
|
}
|
|
259
128
|
|
|
260
|
-
return new Proxy([] as unknown as
|
|
129
|
+
return new Proxy([] as unknown as FieldProxy, {
|
|
261
130
|
get(_, prop) {
|
|
262
131
|
if (prop === "get") return getValue;
|
|
263
132
|
if (prop === "set") return setValue;
|
|
@@ -276,35 +145,35 @@ function emissionIntensityProxy(): PBRProxy {
|
|
|
276
145
|
|
|
277
146
|
export const Mesh: {
|
|
278
147
|
shape: Uint32Array;
|
|
279
|
-
color:
|
|
280
|
-
colorR:
|
|
281
|
-
colorG:
|
|
282
|
-
colorB:
|
|
283
|
-
opacity:
|
|
284
|
-
sizeX:
|
|
285
|
-
sizeY:
|
|
286
|
-
sizeZ:
|
|
287
|
-
roughness:
|
|
288
|
-
metallic:
|
|
289
|
-
ior:
|
|
290
|
-
emission:
|
|
291
|
-
emissionIntensity:
|
|
148
|
+
color: FieldProxy;
|
|
149
|
+
colorR: FieldProxy;
|
|
150
|
+
colorG: FieldProxy;
|
|
151
|
+
colorB: FieldProxy;
|
|
152
|
+
opacity: FieldProxy;
|
|
153
|
+
sizeX: FieldProxy;
|
|
154
|
+
sizeY: FieldProxy;
|
|
155
|
+
sizeZ: FieldProxy;
|
|
156
|
+
roughness: FieldProxy;
|
|
157
|
+
metallic: FieldProxy;
|
|
158
|
+
ior: FieldProxy;
|
|
159
|
+
emission: FieldProxy;
|
|
160
|
+
emissionIntensity: FieldProxy;
|
|
292
161
|
volume: Uint8Array;
|
|
293
162
|
} = {
|
|
294
163
|
shape: MeshShapes.data,
|
|
295
|
-
color:
|
|
296
|
-
colorR:
|
|
297
|
-
colorG:
|
|
298
|
-
colorB:
|
|
299
|
-
opacity:
|
|
300
|
-
sizeX:
|
|
301
|
-
sizeY:
|
|
302
|
-
sizeZ:
|
|
303
|
-
roughness:
|
|
304
|
-
metallic:
|
|
305
|
-
ior:
|
|
306
|
-
emission:
|
|
307
|
-
emissionIntensity:
|
|
164
|
+
color: hexColorProxy(MeshColors.data),
|
|
165
|
+
colorR: createFieldProxy(MeshColors.data, 4, 0),
|
|
166
|
+
colorG: createFieldProxy(MeshColors.data, 4, 1),
|
|
167
|
+
colorB: createFieldProxy(MeshColors.data, 4, 2),
|
|
168
|
+
opacity: createFieldProxy(MeshColors.data, 4, 3),
|
|
169
|
+
sizeX: createFieldProxy(MeshSizes.data, 4, 0),
|
|
170
|
+
sizeY: createFieldProxy(MeshSizes.data, 4, 1),
|
|
171
|
+
sizeZ: createFieldProxy(MeshSizes.data, 4, 2),
|
|
172
|
+
roughness: roughnessProxy(),
|
|
173
|
+
metallic: createFieldProxy(MeshPBR.data, 4, 1),
|
|
174
|
+
ior: createFieldProxy(MeshPBR.data, 4, 2),
|
|
175
|
+
emission: hexColorProxy(MeshEmission.data),
|
|
176
|
+
emissionIntensity: createFieldProxy(MeshEmission.data, 4, 3),
|
|
308
177
|
volume: MeshVolumes.data,
|
|
309
178
|
};
|
|
310
179
|
|
|
@@ -12,7 +12,7 @@ export interface OverlayNodeConfig {
|
|
|
12
12
|
export function createOverlayNode(config: OverlayNodeConfig): ComputeNode {
|
|
13
13
|
return {
|
|
14
14
|
id: "overlay",
|
|
15
|
-
inputs: [{ id: "
|
|
15
|
+
inputs: [{ id: "z", access: "read" }],
|
|
16
16
|
outputs: [
|
|
17
17
|
{ id: "color", access: "write" },
|
|
18
18
|
{ id: "mask", access: "write" },
|
|
@@ -21,7 +21,7 @@ export function createOverlayNode(config: OverlayNodeConfig): ComputeNode {
|
|
|
21
21
|
execute(ctx: ExecutionContext) {
|
|
22
22
|
const { device, encoder, format, context } = ctx;
|
|
23
23
|
const targetView = ctx.getTextureView("color") ?? ctx.canvasView;
|
|
24
|
-
const
|
|
24
|
+
const zView = ctx.getTextureView("z")!;
|
|
25
25
|
const maskView = ctx.getTextureView("mask")!;
|
|
26
26
|
const eidView = ctx.getTextureView("eid")!;
|
|
27
27
|
|
|
@@ -32,7 +32,7 @@ export function createOverlayNode(config: OverlayNodeConfig): ComputeNode {
|
|
|
32
32
|
width: context.canvas.width,
|
|
33
33
|
height: context.canvas.height,
|
|
34
34
|
sceneView: targetView,
|
|
35
|
-
|
|
35
|
+
zView,
|
|
36
36
|
entityIdView: eidView,
|
|
37
37
|
maskView,
|
|
38
38
|
canvasView: ctx.canvasView,
|
|
@@ -60,7 +60,7 @@ export function createOverlayNode(config: OverlayNodeConfig): ComputeNode {
|
|
|
60
60
|
},
|
|
61
61
|
],
|
|
62
62
|
depthStencilAttachment: {
|
|
63
|
-
view:
|
|
63
|
+
view: zView,
|
|
64
64
|
depthLoadOp: "load" as const,
|
|
65
65
|
depthStoreOp: "store" as const,
|
|
66
66
|
},
|
|
@@ -17,7 +17,7 @@ export interface DrawContext {
|
|
|
17
17
|
readonly height: number;
|
|
18
18
|
|
|
19
19
|
readonly sceneView: GPUTextureView;
|
|
20
|
-
readonly
|
|
20
|
+
readonly zView: GPUTextureView;
|
|
21
21
|
readonly entityIdView: GPUTextureView;
|
|
22
22
|
readonly maskView: GPUTextureView;
|
|
23
23
|
readonly canvasView: GPUTextureView;
|
|
@@ -120,7 +120,6 @@ fn applyVignette(color: vec3f, uv: vec2f) -> vec3f {
|
|
|
120
120
|
|
|
121
121
|
fn sampleBloom(uv: vec2f) -> vec3f {
|
|
122
122
|
let texelSize = vec2f(uniforms.texelSizeX, uniforms.texelSizeY);
|
|
123
|
-
// Normalize to reference height (1080p) for resolution-independent bloom
|
|
124
123
|
let height = 1.0 / uniforms.texelSizeY;
|
|
125
124
|
let resolutionScale = height / 1080.0;
|
|
126
125
|
let spread = uniforms.bloomRadius * 4.0 * resolutionScale;
|
|
@@ -130,7 +129,6 @@ fn sampleBloom(uv: vec2f) -> vec3f {
|
|
|
130
129
|
var bloom = vec3f(0.0);
|
|
131
130
|
var totalWeight = 0.0;
|
|
132
131
|
|
|
133
|
-
// 9x9 kernel with gaussian weights
|
|
134
132
|
for (var y = -4; y <= 4; y++) {
|
|
135
133
|
for (var x = -4; x <= 4; x++) {
|
|
136
134
|
let offset = vec2f(f32(x), f32(y)) * texelSize * spread;
|
|
@@ -165,7 +163,6 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
|
|
|
165
163
|
color = select(fxaaColor, color, maskValue >= 0.5);
|
|
166
164
|
}
|
|
167
165
|
|
|
168
|
-
// Bloom applied before tonemapping
|
|
169
166
|
if (uniforms.flags & FLAG_BLOOM) != 0u {
|
|
170
167
|
let bloom = sampleBloom(input.uv);
|
|
171
168
|
color += bloom * uniforms.bloomIntensity;
|
|
@@ -251,6 +248,16 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
251
248
|
let linearSampler: GPUSampler | null = null;
|
|
252
249
|
let nearestSampler: GPUSampler | null = null;
|
|
253
250
|
|
|
251
|
+
let uniformData: ArrayBuffer;
|
|
252
|
+
let uniformFloats: Float32Array;
|
|
253
|
+
let uniformUints: Uint32Array;
|
|
254
|
+
|
|
255
|
+
let mainBindGroup: GPUBindGroup | null = null;
|
|
256
|
+
let blitBindGroup: GPUBindGroup | null = null;
|
|
257
|
+
let cachedInputView: GPUTextureView | null = null;
|
|
258
|
+
let cachedSampler: GPUSampler | null = null;
|
|
259
|
+
let cachedMaskView: GPUTextureView | null = null;
|
|
260
|
+
|
|
254
261
|
return {
|
|
255
262
|
id: "postprocess",
|
|
256
263
|
inputs: [
|
|
@@ -306,6 +313,10 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
306
313
|
magFilter: "nearest",
|
|
307
314
|
minFilter: "nearest",
|
|
308
315
|
});
|
|
316
|
+
|
|
317
|
+
uniformData = new ArrayBuffer(48);
|
|
318
|
+
uniformFloats = new Float32Array(uniformData);
|
|
319
|
+
uniformUints = new Uint32Array(uniformData);
|
|
309
320
|
},
|
|
310
321
|
|
|
311
322
|
execute(ctx: ExecutionContext) {
|
|
@@ -314,7 +325,7 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
314
325
|
const height = context.canvas.height;
|
|
315
326
|
const colorView = ctx.getTextureView("color")!;
|
|
316
327
|
const maskView = ctx.getTextureView("mask")!;
|
|
317
|
-
const
|
|
328
|
+
const zView = ctx.getTextureView("z")!;
|
|
318
329
|
const eidView = ctx.getTextureView("eid")!;
|
|
319
330
|
const pingAView = ctx.getTextureView("pingA")!;
|
|
320
331
|
const pingBView = ctx.getTextureView("pingB")!;
|
|
@@ -337,7 +348,7 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
337
348
|
width,
|
|
338
349
|
height,
|
|
339
350
|
sceneView: colorView,
|
|
340
|
-
|
|
351
|
+
zView,
|
|
341
352
|
entityIdView: eidView,
|
|
342
353
|
maskView,
|
|
343
354
|
canvasView,
|
|
@@ -368,7 +379,7 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
368
379
|
width,
|
|
369
380
|
height,
|
|
370
381
|
sceneView: colorView,
|
|
371
|
-
|
|
382
|
+
zView,
|
|
372
383
|
entityIdView: eidView,
|
|
373
384
|
maskView,
|
|
374
385
|
canvasView,
|
|
@@ -390,32 +401,38 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
390
401
|
if (config.uniforms.bloomIntensity > 0) flags |= FLAG_BLOOM;
|
|
391
402
|
if (config.uniforms.quantize > 0) flags |= FLAG_QUANTIZE;
|
|
392
403
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
404
|
+
uniformFloats[0] = config.uniforms.exposure;
|
|
405
|
+
uniformFloats[1] = config.uniforms.vignetteStrength;
|
|
406
|
+
uniformFloats[2] = config.uniforms.vignetteInner;
|
|
407
|
+
uniformFloats[3] = config.uniforms.vignetteOuter;
|
|
408
|
+
uniformFloats[4] = 1.0 / width;
|
|
409
|
+
uniformFloats[5] = 1.0 / height;
|
|
410
|
+
uniformUints[6] = flags;
|
|
411
|
+
uniformFloats[7] = config.uniforms.bloomIntensity;
|
|
412
|
+
uniformFloats[8] = config.uniforms.bloomThreshold;
|
|
413
|
+
uniformFloats[9] = config.uniforms.bloomRadius;
|
|
414
|
+
uniformFloats[10] = config.uniforms.quantize;
|
|
415
|
+
|
|
416
|
+
device.queue.writeBuffer(uniformBuffer!, 0, uniformData);
|
|
417
|
+
|
|
418
|
+
if (
|
|
419
|
+
currentInput !== cachedInputView ||
|
|
420
|
+
sampler !== cachedSampler ||
|
|
421
|
+
maskView !== cachedMaskView
|
|
422
|
+
) {
|
|
423
|
+
mainBindGroup = device.createBindGroup({
|
|
424
|
+
layout: pipeline!.getBindGroupLayout(0),
|
|
425
|
+
entries: [
|
|
426
|
+
{ binding: 0, resource: currentInput },
|
|
427
|
+
{ binding: 1, resource: sampler },
|
|
428
|
+
{ binding: 2, resource: { buffer: uniformBuffer! } },
|
|
429
|
+
{ binding: 3, resource: maskView },
|
|
430
|
+
],
|
|
431
|
+
});
|
|
432
|
+
cachedInputView = currentInput;
|
|
433
|
+
cachedSampler = sampler;
|
|
434
|
+
cachedMaskView = maskView;
|
|
435
|
+
}
|
|
419
436
|
|
|
420
437
|
const pass = encoder.beginRenderPass({
|
|
421
438
|
colorAttachments: [
|
|
@@ -429,17 +446,21 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
429
446
|
});
|
|
430
447
|
|
|
431
448
|
pass.setPipeline(pipeline!);
|
|
432
|
-
pass.setBindGroup(0,
|
|
449
|
+
pass.setBindGroup(0, mainBindGroup!);
|
|
433
450
|
pass.draw(3);
|
|
434
451
|
pass.end();
|
|
435
452
|
} else {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
453
|
+
if (currentInput !== cachedInputView || sampler !== cachedSampler) {
|
|
454
|
+
blitBindGroup = device.createBindGroup({
|
|
455
|
+
layout: blitPipeline!.getBindGroupLayout(0),
|
|
456
|
+
entries: [
|
|
457
|
+
{ binding: 0, resource: currentInput },
|
|
458
|
+
{ binding: 1, resource: sampler },
|
|
459
|
+
],
|
|
460
|
+
});
|
|
461
|
+
cachedInputView = currentInput;
|
|
462
|
+
cachedSampler = sampler;
|
|
463
|
+
}
|
|
443
464
|
|
|
444
465
|
const pass = encoder.beginRenderPass({
|
|
445
466
|
colorAttachments: [
|
|
@@ -453,18 +474,22 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
453
474
|
});
|
|
454
475
|
|
|
455
476
|
pass.setPipeline(blitPipeline!);
|
|
456
|
-
pass.setBindGroup(0,
|
|
477
|
+
pass.setBindGroup(0, blitBindGroup!);
|
|
457
478
|
pass.draw(3);
|
|
458
479
|
pass.end();
|
|
459
480
|
}
|
|
460
481
|
} else {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
482
|
+
if (currentInput !== cachedInputView || sampler !== cachedSampler) {
|
|
483
|
+
blitBindGroup = device.createBindGroup({
|
|
484
|
+
layout: blitPipeline!.getBindGroupLayout(0),
|
|
485
|
+
entries: [
|
|
486
|
+
{ binding: 0, resource: currentInput },
|
|
487
|
+
{ binding: 1, resource: sampler },
|
|
488
|
+
],
|
|
489
|
+
});
|
|
490
|
+
cachedInputView = currentInput;
|
|
491
|
+
cachedSampler = sampler;
|
|
492
|
+
}
|
|
468
493
|
|
|
469
494
|
const pass = encoder.beginRenderPass({
|
|
470
495
|
colorAttachments: [
|
|
@@ -478,7 +503,7 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
478
503
|
});
|
|
479
504
|
|
|
480
505
|
pass.setPipeline(blitPipeline!);
|
|
481
|
-
pass.setBindGroup(0,
|
|
506
|
+
pass.setBindGroup(0, blitBindGroup!);
|
|
482
507
|
pass.draw(3);
|
|
483
508
|
pass.end();
|
|
484
509
|
}
|
|
@@ -492,7 +517,7 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
492
517
|
width,
|
|
493
518
|
height,
|
|
494
519
|
sceneView: colorView,
|
|
495
|
-
|
|
520
|
+
zView,
|
|
496
521
|
entityIdView: eidView,
|
|
497
522
|
maskView,
|
|
498
523
|
canvasView,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export const SCENE_UNIFORM_SIZE =
|
|
2
|
-
export const
|
|
3
|
-
export const
|
|
1
|
+
export const SCENE_UNIFORM_SIZE = 352;
|
|
2
|
+
export const SKY_UNIFORM_SIZE = 176;
|
|
3
|
+
export const Z_FORMAT: GPUTextureFormat = "depth24plus";
|
|
4
|
+
export const DEPTH_FORMAT: GPUTextureFormat = "r32float";
|
|
4
5
|
export const MASK_FORMAT: GPUTextureFormat = "r8unorm";
|
|
5
6
|
export const EID_FORMAT: GPUTextureFormat = "r32uint";
|
|
6
7
|
export const COLOR_FORMAT: GPUTextureFormat = "rgba8unorm";
|
|
@@ -13,6 +14,14 @@ export function createSceneBuffer(device: GPUDevice): GPUBuffer {
|
|
|
13
14
|
});
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
export function createSkyBuffer(device: GPUDevice): GPUBuffer {
|
|
18
|
+
return device.createBuffer({
|
|
19
|
+
label: "sky",
|
|
20
|
+
size: SKY_UNIFORM_SIZE,
|
|
21
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
export function ensureTextures(
|
|
17
26
|
device: GPUDevice,
|
|
18
27
|
format: GPUTextureFormat,
|
|
@@ -25,9 +34,9 @@ export function ensureTextures(
|
|
|
25
34
|
if (existing && existing.width === width && existing.height === height) return;
|
|
26
35
|
|
|
27
36
|
existing?.destroy();
|
|
28
|
-
textures.get("linear-depth")?.destroy();
|
|
29
|
-
textures.get("eid")?.destroy();
|
|
30
37
|
textures.get("depth")?.destroy();
|
|
38
|
+
textures.get("eid")?.destroy();
|
|
39
|
+
textures.get("z")?.destroy();
|
|
31
40
|
textures.get("mask")?.destroy();
|
|
32
41
|
textures.get("pingA")?.destroy();
|
|
33
42
|
textures.get("pingB")?.destroy();
|
|
@@ -42,11 +51,14 @@ export function ensureTextures(
|
|
|
42
51
|
GPUTextureUsage.TEXTURE_BINDING,
|
|
43
52
|
});
|
|
44
53
|
|
|
45
|
-
const
|
|
46
|
-
label: "
|
|
54
|
+
const depth = device.createTexture({
|
|
55
|
+
label: "depth",
|
|
47
56
|
size: { width, height },
|
|
48
|
-
format:
|
|
49
|
-
usage:
|
|
57
|
+
format: DEPTH_FORMAT,
|
|
58
|
+
usage:
|
|
59
|
+
GPUTextureUsage.STORAGE_BINDING |
|
|
60
|
+
GPUTextureUsage.RENDER_ATTACHMENT |
|
|
61
|
+
GPUTextureUsage.TEXTURE_BINDING,
|
|
50
62
|
});
|
|
51
63
|
|
|
52
64
|
const eid = device.createTexture({
|
|
@@ -59,10 +71,10 @@ export function ensureTextures(
|
|
|
59
71
|
GPUTextureUsage.TEXTURE_BINDING,
|
|
60
72
|
});
|
|
61
73
|
|
|
62
|
-
const
|
|
63
|
-
label: "
|
|
74
|
+
const z = device.createTexture({
|
|
75
|
+
label: "z",
|
|
64
76
|
size: { width, height },
|
|
65
|
-
format:
|
|
77
|
+
format: Z_FORMAT,
|
|
66
78
|
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
67
79
|
});
|
|
68
80
|
|
|
@@ -89,12 +101,12 @@ export function ensureTextures(
|
|
|
89
101
|
|
|
90
102
|
textures.set("color", color);
|
|
91
103
|
textureViews.set("color", color.createView());
|
|
92
|
-
textures.set("linear-depth", linearDepth);
|
|
93
|
-
textureViews.set("linear-depth", linearDepth.createView());
|
|
94
|
-
textures.set("eid", eid);
|
|
95
|
-
textureViews.set("eid", eid.createView());
|
|
96
104
|
textures.set("depth", depth);
|
|
97
105
|
textureViews.set("depth", depth.createView());
|
|
106
|
+
textures.set("eid", eid);
|
|
107
|
+
textureViews.set("eid", eid.createView());
|
|
108
|
+
textures.set("z", z);
|
|
109
|
+
textureViews.set("z", z.createView());
|
|
98
110
|
textures.set("mask", mask);
|
|
99
111
|
textureViews.set("mask", mask.createView());
|
|
100
112
|
textures.set("pingA", pingA);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WGSL_STRUCTS } from "./structs";
|
|
2
2
|
import type { SurfaceData } from "./index";
|
|
3
|
-
import { compileVertexBody, WGSL_LIGHTING_CALC } from "./
|
|
3
|
+
import { compileVertexBody, WGSL_LIGHTING_CALC } from "./shaders";
|
|
4
4
|
|
|
5
5
|
export function compileSurface(data: SurfaceData): string {
|
|
6
6
|
const vertexTransform = compileVertexBody(data.vertex);
|
|
@@ -26,11 +26,10 @@ fn vs(input: VertexInput) -> VertexOutput {
|
|
|
26
26
|
let baseWorldPos = (world * vec4<f32>(scaledPos, 1.0)).xyz;
|
|
27
27
|
let worldNormal = normalize((world * vec4<f32>(input.normal, 0.0)).xyz);
|
|
28
28
|
let finalWorldPos = userVertexTransform(baseWorldPos, worldNormal, eid);
|
|
29
|
-
_ = shapes[eid]; // Keep binding alive
|
|
30
29
|
|
|
31
30
|
var output: VertexOutput;
|
|
32
31
|
output.position = scene.viewProj * vec4<f32>(finalWorldPos, 1.0);
|
|
33
|
-
output.color =
|
|
32
|
+
output.color = data[eid].baseColor;
|
|
34
33
|
output.worldNormal = worldNormal;
|
|
35
34
|
output.entityId = eid;
|
|
36
35
|
output.worldPos = finalWorldPos;
|
|
@@ -40,14 +39,13 @@ fn vs(input: VertexInput) -> VertexOutput {
|
|
|
40
39
|
@fragment
|
|
41
40
|
fn fs(input: VertexOutput) -> FragmentOutput {
|
|
42
41
|
let eid = input.entityId;
|
|
43
|
-
let
|
|
44
|
-
let emissionData = emission[eid];
|
|
42
|
+
let d = data[eid];
|
|
45
43
|
|
|
46
44
|
var surface: SurfaceData;
|
|
47
45
|
surface.baseColor = input.color.rgb;
|
|
48
|
-
surface.roughness =
|
|
49
|
-
surface.metallic =
|
|
50
|
-
surface.emission =
|
|
46
|
+
surface.roughness = d.pbr.x;
|
|
47
|
+
surface.metallic = d.pbr.y;
|
|
48
|
+
surface.emission = d.emission.rgb * d.emission.a;
|
|
51
49
|
surface.normal = normalize(input.worldNormal);
|
|
52
50
|
surface.worldPos = input.worldPos;
|
|
53
51
|
|