@tinypoly/gpu-renderer 0.0.4 → 0.1.0
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/ARCHITECTURE.md +81 -10
- package/README.md +53 -5
- package/dist/atmosphere.d.ts +21 -0
- package/dist/atmosphere.d.ts.map +1 -0
- package/dist/atmosphere.js +72 -0
- package/dist/atmosphere.js.map +1 -0
- package/dist/bvh.d.ts +11 -6
- package/dist/bvh.d.ts.map +1 -1
- package/dist/bvh.js +64 -11
- package/dist/bvh.js.map +1 -1
- package/dist/denoise.d.ts +17 -2
- package/dist/denoise.d.ts.map +1 -1
- package/dist/denoise.js +95 -27
- package/dist/denoise.js.map +1 -1
- package/dist/dispatchScheduler.d.ts +11 -4
- package/dist/dispatchScheduler.d.ts.map +1 -1
- package/dist/dispatchScheduler.js +14 -7
- package/dist/dispatchScheduler.js.map +1 -1
- package/dist/frameLayout.d.ts.map +1 -1
- package/dist/frameLayout.js +18 -0
- package/dist/frameLayout.js.map +1 -1
- package/dist/geometry.d.ts.map +1 -1
- package/dist/geometry.js +6 -3
- package/dist/geometry.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lensPass.d.ts +60 -0
- package/dist/lensPass.d.ts.map +1 -0
- package/dist/lensPass.js +235 -0
- package/dist/lensPass.js.map +1 -0
- package/dist/lightTree.d.ts +43 -0
- package/dist/lightTree.d.ts.map +1 -0
- package/dist/lightTree.js +107 -0
- package/dist/lightTree.js.map +1 -0
- package/dist/lights.d.ts +19 -1
- package/dist/lights.d.ts.map +1 -1
- package/dist/lights.js +63 -1
- package/dist/lights.js.map +1 -1
- package/dist/materialLayout.d.ts +24 -0
- package/dist/materialLayout.d.ts.map +1 -1
- package/dist/materialLayout.js +36 -1
- package/dist/materialLayout.js.map +1 -1
- package/dist/pathTracePass.d.ts +6 -3
- package/dist/pathTracePass.d.ts.map +1 -1
- package/dist/pathTracePass.js +16 -10
- package/dist/pathTracePass.js.map +1 -1
- package/dist/renderer.d.ts +19 -7
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +198 -36
- package/dist/renderer.js.map +1 -1
- package/dist/sceneUpload.d.ts +19 -1
- package/dist/sceneUpload.d.ts.map +1 -1
- package/dist/sceneUpload.js +25 -3
- package/dist/sceneUpload.js.map +1 -1
- package/dist/settings.d.ts +136 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +100 -0
- package/dist/settings.js.map +1 -0
- package/dist/subsurface.d.ts +76 -0
- package/dist/subsurface.d.ts.map +1 -0
- package/dist/subsurface.js +70 -0
- package/dist/subsurface.js.map +1 -0
- package/dist/texturePack.d.ts +16 -4
- package/dist/texturePack.d.ts.map +1 -1
- package/dist/texturePack.js +61 -8
- package/dist/texturePack.js.map +1 -1
- package/dist/volumeContainment.d.ts +17 -0
- package/dist/volumeContainment.d.ts.map +1 -0
- package/dist/volumeContainment.js +61 -0
- package/dist/volumeContainment.js.map +1 -0
- package/dist/wgsl/bsdf.wgsl.d.ts +1 -1
- package/dist/wgsl/bsdf.wgsl.d.ts.map +1 -1
- package/dist/wgsl/bsdf.wgsl.js +35 -3
- package/dist/wgsl/bsdf.wgsl.js.map +1 -1
- package/dist/wgsl/bvh.wgsl.d.ts +8 -2
- package/dist/wgsl/bvh.wgsl.d.ts.map +1 -1
- package/dist/wgsl/bvh.wgsl.js +167 -96
- package/dist/wgsl/bvh.wgsl.js.map +1 -1
- package/dist/wgsl/common.wgsl.d.ts.map +1 -1
- package/dist/wgsl/common.wgsl.js +24 -7
- package/dist/wgsl/common.wgsl.js.map +1 -1
- package/dist/wgsl/lens.wgsl.d.ts +17 -0
- package/dist/wgsl/lens.wgsl.d.ts.map +1 -0
- package/dist/wgsl/lens.wgsl.js +315 -0
- package/dist/wgsl/lens.wgsl.js.map +1 -0
- package/dist/wgsl/lights.wgsl.d.ts +1 -1
- package/dist/wgsl/lights.wgsl.d.ts.map +1 -1
- package/dist/wgsl/lights.wgsl.js +206 -33
- package/dist/wgsl/lights.wgsl.js.map +1 -1
- package/dist/wgsl/pathTrace.wgsl.d.ts +1 -1
- package/dist/wgsl/pathTrace.wgsl.d.ts.map +1 -1
- package/dist/wgsl/pathTrace.wgsl.js +410 -25
- package/dist/wgsl/pathTrace.wgsl.js.map +1 -1
- package/dist/wgsl/random.wgsl.d.ts +1 -1
- package/dist/wgsl/random.wgsl.d.ts.map +1 -1
- package/dist/wgsl/random.wgsl.js +9 -17
- package/dist/wgsl/random.wgsl.js.map +1 -1
- package/dist/wgsl/sampling.wgsl.d.ts +1 -1
- package/dist/wgsl/sampling.wgsl.d.ts.map +1 -1
- package/dist/wgsl/sampling.wgsl.js +25 -0
- package/dist/wgsl/sampling.wgsl.js.map +1 -1
- package/dist/wgsl/surface.wgsl.d.ts +1 -1
- package/dist/wgsl/surface.wgsl.d.ts.map +1 -1
- package/dist/wgsl/surface.wgsl.js +47 -4
- package/dist/wgsl/surface.wgsl.js.map +1 -1
- package/dist/wgsl/texture.wgsl.d.ts +1 -1
- package/dist/wgsl/texture.wgsl.d.ts.map +1 -1
- package/dist/wgsl/texture.wgsl.js +10 -11
- package/dist/wgsl/texture.wgsl.js.map +1 -1
- package/package.json +1 -1
- package/src/atmosphere.ts +95 -0
- package/src/bvh.ts +81 -12
- package/src/denoise.ts +110 -27
- package/src/dispatchScheduler.ts +16 -7
- package/src/frameLayout.ts +18 -0
- package/src/geometry.ts +6 -2
- package/src/index.ts +13 -0
- package/src/lensPass.ts +299 -0
- package/src/lightTree.ts +172 -0
- package/src/lights.ts +90 -2
- package/src/materialLayout.ts +52 -1
- package/src/pathTracePass.ts +19 -10
- package/src/renderer.ts +258 -43
- package/src/sceneUpload.ts +41 -4
- package/src/settings.ts +234 -0
- package/src/subsurface.ts +153 -0
- package/src/texturePack.ts +80 -13
- package/src/volumeContainment.ts +81 -0
- package/src/wgsl/bsdf.wgsl.ts +35 -3
- package/src/wgsl/bvh.wgsl.ts +167 -96
- package/src/wgsl/common.wgsl.ts +24 -7
- package/src/wgsl/lens.wgsl.ts +314 -0
- package/src/wgsl/lights.wgsl.ts +206 -33
- package/src/wgsl/pathTrace.wgsl.ts +410 -25
- package/src/wgsl/random.wgsl.ts +9 -17
- package/src/wgsl/sampling.wgsl.ts +25 -0
- package/src/wgsl/surface.wgsl.ts +47 -4
- package/src/wgsl/texture.wgsl.ts +10 -11
package/src/materialLayout.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { layoutStruct, writeStruct, type StructField } from "./structLayout.js";
|
|
2
|
+
import { bevelOf, subsurfaceOf, volumeOf } from "./subsurface.js";
|
|
2
3
|
import { NO_TEXTURE } from "./texturePack.js";
|
|
3
4
|
import type { SerializedMaterial, UniformValue } from "./upstream.js";
|
|
4
5
|
|
|
@@ -59,6 +60,20 @@ export interface MaterialProperties {
|
|
|
59
60
|
combine: number;
|
|
60
61
|
side: number;
|
|
61
62
|
blending: number;
|
|
63
|
+
/**
|
|
64
|
+
* Share of the diffuse layer that scatters light inside the material, from `userData.cpuRenderer.subsurface`; zero
|
|
65
|
+
* for none. Physical and standard materials only.
|
|
66
|
+
*/
|
|
67
|
+
subsurface: number;
|
|
68
|
+
/** Mean free path of red, green and blue inside the material, in world units. */
|
|
69
|
+
subsurfaceRadius: number[];
|
|
70
|
+
subsurfaceAnisotropy: number;
|
|
71
|
+
/** The medium a volume's boundary encloses: its single scattering albedo, density per scene unit and anisotropy. */
|
|
72
|
+
volumeAlbedo: number[];
|
|
73
|
+
volumeDensity: number;
|
|
74
|
+
volumeAnisotropy: number;
|
|
75
|
+
/** The radius over which edges are rounded at shading time, in scene units; zero leaves them sharp. */
|
|
76
|
+
bevel: number;
|
|
62
77
|
/** An index into the texture table per slot, or `NO_TEXTURE`. */
|
|
63
78
|
maps: Record<MaterialMap, number>;
|
|
64
79
|
}
|
|
@@ -137,6 +152,18 @@ export const MATERIAL_ALPHA_HASH = 2048;
|
|
|
137
152
|
/** A physical material, whose specular colour and intensity reach the lobe and whose grazing reflectance follows them. */
|
|
138
153
|
export const MATERIAL_SPECULAR = 4096;
|
|
139
154
|
|
|
155
|
+
/**
|
|
156
|
+
* The mesh only bounds a medium, from `userData.cpuRenderer.volume`: its surface is invisible and the space inside
|
|
157
|
+
* scatters light.
|
|
158
|
+
*/
|
|
159
|
+
export const MATERIAL_VOLUME = 8192;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* An unlit material whose colour is known without running anything: opaque, normal blending, no light map, environment
|
|
163
|
+
* map, alpha map or shader. What it shows is what it emits, so direct sampling can aim at it like an emissive one.
|
|
164
|
+
*/
|
|
165
|
+
export const MATERIAL_UNLIT_LIGHT = 16384;
|
|
166
|
+
|
|
140
167
|
/** What a material's `program` reads as when it has no shader. */
|
|
141
168
|
export const NO_PROGRAM = 0xffffffff;
|
|
142
169
|
|
|
@@ -186,6 +213,11 @@ const FIELDS: StructField[] = [
|
|
|
186
213
|
{ name: "dielectric", type: "f32" },
|
|
187
214
|
{ name: "afterProgram", type: "u32", doc: "What a hook does after <opaque_fragment>, or NO_PROGRAM." },
|
|
188
215
|
{ name: "afterData", type: "u32" },
|
|
216
|
+
{ name: "subsurface", type: "vec4f", doc: "rgb is the mean free path of each colour inside, w the share of the diffuse layer." },
|
|
217
|
+
{ name: "subsurfaceAnisotropy", type: "f32" },
|
|
218
|
+
{ name: "volume", type: "vec4f", doc: "rgb is the medium's single scattering albedo, w its density per scene unit." },
|
|
219
|
+
{ name: "volumeAnisotropy", type: "f32" },
|
|
220
|
+
{ name: "bevel", type: "f32", doc: "The radius edges are rounded over at shading time; zero leaves them sharp." },
|
|
189
221
|
{ name: "normalRow0", type: "vec4f", doc: "The mesh's world normal matrix, for an object space normal map." },
|
|
190
222
|
{ name: "normalRow1", type: "vec4f" },
|
|
191
223
|
{ name: "normalRow2", type: "vec4f" },
|
|
@@ -263,6 +295,8 @@ export function materialProperties(
|
|
|
263
295
|
const sheen = physical ? Math.max(0, number(values.sheen, 0)) : 0;
|
|
264
296
|
const anisotropy = physical ? number(values.anisotropy, 0) : 0;
|
|
265
297
|
const thickness = vector(values.iridescenceThicknessRange, [100, 400], 2);
|
|
298
|
+
const medium = pbr ? subsurfaceOf(material) : null;
|
|
299
|
+
const volume = volumeOf(material);
|
|
266
300
|
|
|
267
301
|
const maps = Object.fromEntries(MATERIAL_MAPS.map(slot => {
|
|
268
302
|
const id = material?.maps?.[slot];
|
|
@@ -285,7 +319,12 @@ export function materialProperties(
|
|
|
285
319
|
| (number(values.normalMapType, 0) === 1 ? MATERIAL_OBJECT_NORMAL_MAP : 0)
|
|
286
320
|
| (shader?.patched ? MATERIAL_PATCHED : 0)
|
|
287
321
|
| (flag(values.alphaHash, false) ? MATERIAL_ALPHA_HASH : 0)
|
|
288
|
-
| (physical ? MATERIAL_SPECULAR : 0)
|
|
322
|
+
| (physical ? MATERIAL_SPECULAR : 0)
|
|
323
|
+
| (volume ? MATERIAL_VOLUME : 0)
|
|
324
|
+
| (type === "MeshBasicMaterial" && !shader && !transparent && !flag(values.alphaHash, false)
|
|
325
|
+
&& !flag(values.wireframe, false) && number(values.blending, 1) === 1 && number(values.opacity, 1) >= 1
|
|
326
|
+
&& number(values.alphaTest, 0) <= 0 && maps.alphaMap === NO_TEXTURE && maps.envMap === NO_TEXTURE
|
|
327
|
+
&& maps.lightMap === NO_TEXTURE && !volume ? MATERIAL_UNLIT_LIGHT : 0);
|
|
289
328
|
|
|
290
329
|
return {
|
|
291
330
|
kind,
|
|
@@ -330,6 +369,13 @@ export function materialProperties(
|
|
|
330
369
|
combine: number(values.combine, 0),
|
|
331
370
|
side: number(values.side, 0),
|
|
332
371
|
blending: number(values.blending, 1),
|
|
372
|
+
subsurface: medium?.weight ?? 0,
|
|
373
|
+
subsurfaceRadius: medium?.radius ?? [1, 1, 1],
|
|
374
|
+
subsurfaceAnisotropy: medium?.anisotropy ?? 0,
|
|
375
|
+
volumeAlbedo: volume?.albedo ?? [1, 1, 1],
|
|
376
|
+
volumeDensity: volume?.density ?? 0,
|
|
377
|
+
volumeAnisotropy: volume?.anisotropy ?? 0,
|
|
378
|
+
bevel: LIT.has(type) ? bevelOf(material) : 0,
|
|
333
379
|
maps,
|
|
334
380
|
};
|
|
335
381
|
}
|
|
@@ -400,6 +446,11 @@ export function writeMaterial(
|
|
|
400
446
|
dielectric: p.dielectric,
|
|
401
447
|
afterProgram: placement.afterProgram,
|
|
402
448
|
afterData: placement.afterData,
|
|
449
|
+
subsurface: [...p.subsurfaceRadius, p.subsurface],
|
|
450
|
+
subsurfaceAnisotropy: p.subsurfaceAnisotropy,
|
|
451
|
+
volume: [...p.volumeAlbedo, p.volumeDensity],
|
|
452
|
+
volumeAnisotropy: p.volumeAnisotropy,
|
|
453
|
+
bevel: p.bevel,
|
|
403
454
|
normalRow0: [n[0], n[3], n[6], 0],
|
|
404
455
|
normalRow1: [n[1], n[4], n[7], 0],
|
|
405
456
|
normalRow2: [n[2], n[5], n[8], 0],
|
package/src/pathTracePass.ts
CHANGED
|
@@ -23,8 +23,12 @@ export type FrameUniforms = Record<keyof typeof FRAME_LAYOUT.offsets & string, n
|
|
|
23
23
|
* declarations. The scene's translated shaders sit between the texture code they call and the surface code that calls
|
|
24
24
|
* them.
|
|
25
25
|
*/
|
|
26
|
-
export function pathTraceSource(
|
|
27
|
-
|
|
26
|
+
export function pathTraceSource(
|
|
27
|
+
programs: ShaderPrograms | null = null, subsurface = true, volumes = true, bevel = true): string {
|
|
28
|
+
// The random walk inside materials and the media inside volumes are compiled in only for a scene that has them: the
|
|
29
|
+
// kernel is bound by its size, and either would cost every other scene a few percent for code that never runs.
|
|
30
|
+
return `const SUBSURFACE_WALK: bool = ${subsurface};\nconst VOLUMES: bool = ${volumes};\nconst BEVEL: bool = ${bevel};\n`
|
|
31
|
+
+ COMMON_WGSL + RANDOM_WGSL + BVH_WGSL + SAMPLING_WGSL + TEXTURE_WGSL + SHADER_SUPPORT_WGSL
|
|
28
32
|
+ programsWgsl(programs) + ENVIRONMENT_WGSL + SURFACE_WGSL + BSDF_WGSL + LIGHTS_WGSL + PATH_TRACE_WGSL;
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -37,26 +41,31 @@ export class PathTracePass {
|
|
|
37
41
|
private readonly uniforms: GPUBuffer;
|
|
38
42
|
private readonly values = new ArrayBuffer(FRAME_BYTES);
|
|
39
43
|
private bindGroup: GPUBindGroup | null = null;
|
|
40
|
-
private programKey = "";
|
|
44
|
+
private programKey = "|false|false|false";
|
|
41
45
|
|
|
42
46
|
constructor(private readonly device: GPUDevice) {
|
|
43
|
-
this.pipeline = this.build(null);
|
|
47
|
+
this.pipeline = this.build(null, false, false, false);
|
|
44
48
|
this.uniforms = device.createBuffer({ size: FRAME_BYTES, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Recompiles the kernel when the scene's shaders changed, or whether it has a material that scatters light inside;
|
|
53
|
+
* the same set keeps the pipeline it has.
|
|
54
|
+
*/
|
|
55
|
+
setPrograms(programs: ShaderPrograms | null, subsurface = false, volumes = false, bevel = false) {
|
|
56
|
+
const key = `${programs?.key ?? ""}|${subsurface}|${volumes}|${bevel}`;
|
|
50
57
|
|
|
51
58
|
if (key === this.programKey) return;
|
|
52
59
|
|
|
53
60
|
this.programKey = key;
|
|
54
|
-
this.pipeline = this.build(programs);
|
|
61
|
+
this.pipeline = this.build(programs, subsurface, volumes, bevel);
|
|
55
62
|
this.bindGroup = null;
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
private build(programs: ShaderPrograms | null
|
|
59
|
-
|
|
65
|
+
private build(programs: ShaderPrograms | null, subsurface: boolean, volumes: boolean,
|
|
66
|
+
bevel: boolean): GPUComputePipeline {
|
|
67
|
+
const module = createShaderModule(this.device, "path trace",
|
|
68
|
+
pathTraceSource(programs, subsurface, volumes, bevel));
|
|
60
69
|
|
|
61
70
|
return this.device.createComputePipeline({ layout: "auto", compute: { module, entryPoint: "main" } });
|
|
62
71
|
}
|