@tinypoly/gpu-renderer 0.0.0-stage → 0.0.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/ARCHITECTURE.md +339 -0
- package/LICENSE +21 -0
- package/README.md +284 -2
- package/dist/accumulator.d.ts +27 -0
- package/dist/accumulator.d.ts.map +1 -0
- package/dist/accumulator.js +57 -0
- package/dist/accumulator.js.map +1 -0
- package/dist/bvh.d.ts +26 -0
- package/dist/bvh.d.ts.map +1 -0
- package/dist/bvh.js +296 -0
- package/dist/bvh.js.map +1 -0
- package/dist/bvhBuilder.d.ts +72 -0
- package/dist/bvhBuilder.d.ts.map +1 -0
- package/dist/bvhBuilder.js +126 -0
- package/dist/bvhBuilder.js.map +1 -0
- package/dist/bvhWorker.d.ts +2 -0
- package/dist/bvhWorker.d.ts.map +1 -0
- package/dist/bvhWorker.js +8 -0
- package/dist/bvhWorker.js.map +1 -0
- package/dist/camera.d.ts +29 -0
- package/dist/camera.d.ts.map +1 -0
- package/dist/camera.js +48 -0
- package/dist/camera.js.map +1 -0
- package/dist/canvas.d.ts +9 -0
- package/dist/canvas.d.ts.map +1 -0
- package/dist/canvas.js +11 -0
- package/dist/canvas.js.map +1 -0
- package/dist/denoise.d.ts +69 -0
- package/dist/denoise.d.ts.map +1 -0
- package/dist/denoise.js +455 -0
- package/dist/denoise.js.map +1 -0
- package/dist/device.d.ts +37 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +52 -0
- package/dist/device.js.map +1 -0
- package/dist/dispatchScheduler.d.ts +43 -0
- package/dist/dispatchScheduler.d.ts.map +1 -0
- package/dist/dispatchScheduler.js +49 -0
- package/dist/dispatchScheduler.js.map +1 -0
- package/dist/environment.d.ts +39 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +168 -0
- package/dist/environment.js.map +1 -0
- package/dist/frameLayout.d.ts +4 -0
- package/dist/frameLayout.d.ts.map +1 -0
- package/dist/frameLayout.js +58 -0
- package/dist/frameLayout.js.map +1 -0
- package/dist/geometry.d.ts +75 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +799 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/lights.d.ts +64 -0
- package/dist/lights.d.ts.map +1 -0
- package/dist/lights.js +264 -0
- package/dist/lights.js.map +1 -0
- package/dist/materialLayout.d.ts +143 -0
- package/dist/materialLayout.d.ts.map +1 -0
- package/dist/materialLayout.js +297 -0
- package/dist/materialLayout.js.map +1 -0
- package/dist/math.d.ts +10 -0
- package/dist/math.d.ts.map +1 -0
- package/dist/math.js +40 -0
- package/dist/math.js.map +1 -0
- package/dist/pathTracePass.d.ts +27 -0
- package/dist/pathTracePass.d.ts.map +1 -0
- package/dist/pathTracePass.js +83 -0
- package/dist/pathTracePass.js.map +1 -0
- package/dist/planarCapture.d.ts +38 -0
- package/dist/planarCapture.d.ts.map +1 -0
- package/dist/planarCapture.js +163 -0
- package/dist/planarCapture.js.map +1 -0
- package/dist/presentPass.d.ts +31 -0
- package/dist/presentPass.d.ts.map +1 -0
- package/dist/presentPass.js +78 -0
- package/dist/presentPass.js.map +1 -0
- package/dist/renderer.d.ts +209 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +847 -0
- package/dist/renderer.js.map +1 -0
- package/dist/sceneAssets.d.ts +24 -0
- package/dist/sceneAssets.d.ts.map +1 -0
- package/dist/sceneAssets.js +77 -0
- package/dist/sceneAssets.js.map +1 -0
- package/dist/sceneUpload.d.ts +61 -0
- package/dist/sceneUpload.d.ts.map +1 -0
- package/dist/sceneUpload.js +98 -0
- package/dist/sceneUpload.js.map +1 -0
- package/dist/shaderModule.d.ts +7 -0
- package/dist/shaderModule.d.ts.map +1 -0
- package/dist/shaderModule.js +19 -0
- package/dist/shaderModule.js.map +1 -0
- package/dist/shaderProgram.d.ts +124 -0
- package/dist/shaderProgram.d.ts.map +1 -0
- package/dist/shaderProgram.js +1030 -0
- package/dist/shaderProgram.js.map +1 -0
- package/dist/structLayout.d.ts +28 -0
- package/dist/structLayout.d.ts.map +1 -0
- package/dist/structLayout.js +58 -0
- package/dist/structLayout.js.map +1 -0
- package/dist/texturePack.d.ts +54 -0
- package/dist/texturePack.d.ts.map +1 -0
- package/dist/texturePack.js +86 -0
- package/dist/texturePack.js.map +1 -0
- package/dist/upstream.d.ts +7 -0
- package/dist/upstream.d.ts.map +1 -0
- package/dist/upstream.js +11 -0
- package/dist/upstream.js.map +1 -0
- package/dist/volumetric.d.ts +10 -0
- package/dist/volumetric.d.ts.map +1 -0
- package/dist/volumetric.js +34 -0
- package/dist/volumetric.js.map +1 -0
- package/dist/wgsl/bsdf.wgsl.d.ts +13 -0
- package/dist/wgsl/bsdf.wgsl.d.ts.map +1 -0
- package/dist/wgsl/bsdf.wgsl.js +619 -0
- package/dist/wgsl/bsdf.wgsl.js.map +1 -0
- package/dist/wgsl/bvh.wgsl.d.ts +3 -0
- package/dist/wgsl/bvh.wgsl.d.ts.map +1 -0
- package/dist/wgsl/bvh.wgsl.js +218 -0
- package/dist/wgsl/bvh.wgsl.js.map +1 -0
- package/dist/wgsl/common.wgsl.d.ts +3 -0
- package/dist/wgsl/common.wgsl.d.ts.map +1 -0
- package/dist/wgsl/common.wgsl.js +193 -0
- package/dist/wgsl/common.wgsl.js.map +1 -0
- package/dist/wgsl/environment.wgsl.d.ts +10 -0
- package/dist/wgsl/environment.wgsl.d.ts.map +1 -0
- package/dist/wgsl/environment.wgsl.js +145 -0
- package/dist/wgsl/environment.wgsl.js.map +1 -0
- package/dist/wgsl/lights.wgsl.d.ts +10 -0
- package/dist/wgsl/lights.wgsl.d.ts.map +1 -0
- package/dist/wgsl/lights.wgsl.js +434 -0
- package/dist/wgsl/lights.wgsl.js.map +1 -0
- package/dist/wgsl/pathTrace.wgsl.d.ts +14 -0
- package/dist/wgsl/pathTrace.wgsl.d.ts.map +1 -0
- package/dist/wgsl/pathTrace.wgsl.js +1020 -0
- package/dist/wgsl/pathTrace.wgsl.js.map +1 -0
- package/dist/wgsl/present.wgsl.d.ts +7 -0
- package/dist/wgsl/present.wgsl.d.ts.map +1 -0
- package/dist/wgsl/present.wgsl.js +154 -0
- package/dist/wgsl/present.wgsl.js.map +1 -0
- package/dist/wgsl/random.wgsl.d.ts +9 -0
- package/dist/wgsl/random.wgsl.d.ts.map +1 -0
- package/dist/wgsl/random.wgsl.js +91 -0
- package/dist/wgsl/random.wgsl.js.map +1 -0
- package/dist/wgsl/sampling.wgsl.d.ts +3 -0
- package/dist/wgsl/sampling.wgsl.d.ts.map +1 -0
- package/dist/wgsl/sampling.wgsl.js +31 -0
- package/dist/wgsl/sampling.wgsl.js.map +1 -0
- package/dist/wgsl/shaderSupport.wgsl.d.ts +6 -0
- package/dist/wgsl/shaderSupport.wgsl.d.ts.map +1 -0
- package/dist/wgsl/shaderSupport.wgsl.js +120 -0
- package/dist/wgsl/shaderSupport.wgsl.js.map +1 -0
- package/dist/wgsl/surface.wgsl.d.ts +10 -0
- package/dist/wgsl/surface.wgsl.d.ts.map +1 -0
- package/dist/wgsl/surface.wgsl.js +794 -0
- package/dist/wgsl/surface.wgsl.js.map +1 -0
- package/dist/wgsl/texture.wgsl.d.ts +11 -0
- package/dist/wgsl/texture.wgsl.d.ts.map +1 -0
- package/dist/wgsl/texture.wgsl.js +132 -0
- package/dist/wgsl/texture.wgsl.js.map +1 -0
- package/package.json +77 -3
- package/src/accumulator.ts +64 -0
- package/src/bvh.ts +336 -0
- package/src/bvhBuilder.ts +178 -0
- package/src/bvhWorker.ts +13 -0
- package/src/camera.ts +77 -0
- package/src/canvas.ts +13 -0
- package/src/denoise.ts +514 -0
- package/src/device.ts +81 -0
- package/src/dispatchScheduler.ts +71 -0
- package/src/environment.ts +233 -0
- package/src/frameLayout.ts +59 -0
- package/src/geometry.ts +1067 -0
- package/src/index.ts +64 -0
- package/src/lights.ts +365 -0
- package/src/materialLayout.ts +408 -0
- package/src/math.ts +48 -0
- package/src/pathTracePass.ts +97 -0
- package/src/planarCapture.ts +225 -0
- package/src/presentPass.ts +99 -0
- package/src/renderer.ts +1145 -0
- package/src/sceneAssets.ts +118 -0
- package/src/sceneUpload.ts +185 -0
- package/src/shaderModule.ts +19 -0
- package/src/shaderProgram.ts +1370 -0
- package/src/structLayout.ts +93 -0
- package/src/texturePack.ts +152 -0
- package/src/upstream.ts +56 -0
- package/src/volumetric.ts +42 -0
- package/src/wgsl/bsdf.wgsl.ts +618 -0
- package/src/wgsl/bvh.wgsl.ts +217 -0
- package/src/wgsl/common.wgsl.ts +193 -0
- package/src/wgsl/environment.wgsl.ts +144 -0
- package/src/wgsl/lights.wgsl.ts +433 -0
- package/src/wgsl/pathTrace.wgsl.ts +1019 -0
- package/src/wgsl/present.wgsl.ts +153 -0
- package/src/wgsl/random.wgsl.ts +90 -0
- package/src/wgsl/sampling.wgsl.ts +30 -0
- package/src/wgsl/shaderSupport.wgsl.ts +119 -0
- package/src/wgsl/surface.wgsl.ts +793 -0
- package/src/wgsl/texture.wgsl.ts +131 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { FRAME_LAYOUT, FRAME_WORDS } from "./frameLayout.js";
|
|
2
|
+
import { createShaderModule } from "./shaderModule.js";
|
|
3
|
+
import { programsWgsl } from "./shaderProgram.js";
|
|
4
|
+
import { writeStruct } from "./structLayout.js";
|
|
5
|
+
import { BSDF_WGSL } from "./wgsl/bsdf.wgsl.js";
|
|
6
|
+
import { BVH_WGSL } from "./wgsl/bvh.wgsl.js";
|
|
7
|
+
import { COMMON_WGSL } from "./wgsl/common.wgsl.js";
|
|
8
|
+
import { ENVIRONMENT_WGSL } from "./wgsl/environment.wgsl.js";
|
|
9
|
+
import { LIGHTS_WGSL } from "./wgsl/lights.wgsl.js";
|
|
10
|
+
import { PATH_TRACE_WGSL } from "./wgsl/pathTrace.wgsl.js";
|
|
11
|
+
import { RANDOM_WGSL } from "./wgsl/random.wgsl.js";
|
|
12
|
+
import { SAMPLING_WGSL } from "./wgsl/sampling.wgsl.js";
|
|
13
|
+
import { SHADER_SUPPORT_WGSL } from "./wgsl/shaderSupport.wgsl.js";
|
|
14
|
+
import { SURFACE_WGSL } from "./wgsl/surface.wgsl.js";
|
|
15
|
+
import { TEXTURE_WGSL } from "./wgsl/texture.wgsl.js";
|
|
16
|
+
/**
|
|
17
|
+
* The whole kernel, in the order WGSL needs: every stage may only call what comes before it, as there are no forward
|
|
18
|
+
* declarations. The scene's translated shaders sit between the texture code they call and the surface code that calls
|
|
19
|
+
* them.
|
|
20
|
+
*/
|
|
21
|
+
export function pathTraceSource(programs = null) {
|
|
22
|
+
return COMMON_WGSL + RANDOM_WGSL + BVH_WGSL + SAMPLING_WGSL + TEXTURE_WGSL + SHADER_SUPPORT_WGSL
|
|
23
|
+
+ programsWgsl(programs) + ENVIRONMENT_WGSL + SURFACE_WGSL + BSDF_WGSL + LIGHTS_WGSL + PATH_TRACE_WGSL;
|
|
24
|
+
}
|
|
25
|
+
const FRAME_BYTES = FRAME_WORDS * 4;
|
|
26
|
+
const WORKGROUP = 8;
|
|
27
|
+
export class PathTracePass {
|
|
28
|
+
device;
|
|
29
|
+
pipeline;
|
|
30
|
+
uniforms;
|
|
31
|
+
values = new ArrayBuffer(FRAME_BYTES);
|
|
32
|
+
bindGroup = null;
|
|
33
|
+
programKey = "";
|
|
34
|
+
constructor(device) {
|
|
35
|
+
this.device = device;
|
|
36
|
+
this.pipeline = this.build(null);
|
|
37
|
+
this.uniforms = device.createBuffer({ size: FRAME_BYTES, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
38
|
+
}
|
|
39
|
+
/** Recompiles the kernel when the scene's shaders changed; the same set of programs keeps the pipeline it has. */
|
|
40
|
+
setPrograms(programs) {
|
|
41
|
+
const key = programs?.key ?? "";
|
|
42
|
+
if (key === this.programKey)
|
|
43
|
+
return;
|
|
44
|
+
this.programKey = key;
|
|
45
|
+
this.pipeline = this.build(programs);
|
|
46
|
+
this.bindGroup = null;
|
|
47
|
+
}
|
|
48
|
+
build(programs) {
|
|
49
|
+
const module = createShaderModule(this.device, "path trace", pathTraceSource(programs));
|
|
50
|
+
return this.device.createComputePipeline({ layout: "auto", compute: { module, entryPoint: "main" } });
|
|
51
|
+
}
|
|
52
|
+
/** Rebinds after the scene or the accumulation buffer was replaced. */
|
|
53
|
+
setBindings(scene, accumulation) {
|
|
54
|
+
this.bindGroup = this.device.createBindGroup({
|
|
55
|
+
layout: this.pipeline.getBindGroupLayout(0),
|
|
56
|
+
entries: [
|
|
57
|
+
{ binding: 0, resource: { buffer: this.uniforms } },
|
|
58
|
+
{ binding: 1, resource: { buffer: scene.positions } },
|
|
59
|
+
{ binding: 2, resource: { buffer: scene.attributes } },
|
|
60
|
+
{ binding: 3, resource: { buffer: scene.indices } },
|
|
61
|
+
{ binding: 4, resource: { buffer: scene.materials } },
|
|
62
|
+
{ binding: 5, resource: { buffer: scene.nodes } },
|
|
63
|
+
{ binding: 6, resource: { buffer: scene.lights } },
|
|
64
|
+
{ binding: 7, resource: { buffer: accumulation } },
|
|
65
|
+
{ binding: 8, resource: { buffer: scene.textures } },
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
encode(encoder, frame) {
|
|
70
|
+
if (!this.bindGroup)
|
|
71
|
+
throw new Error("GPU renderer: the path tracing pass has no scene bound.");
|
|
72
|
+
new Uint32Array(this.values).fill(0);
|
|
73
|
+
writeStruct(FRAME_LAYOUT, this.values, 0, frame);
|
|
74
|
+
this.device.queue.writeBuffer(this.uniforms, 0, this.values);
|
|
75
|
+
const pass = encoder.beginComputePass({ label: "path trace" });
|
|
76
|
+
const size = frame.bandSize;
|
|
77
|
+
pass.setPipeline(this.pipeline);
|
|
78
|
+
pass.setBindGroup(0, this.bindGroup);
|
|
79
|
+
pass.dispatchWorkgroups(Math.ceil(size[0] / WORKGROUP), Math.ceil(size[1] / WORKGROUP));
|
|
80
|
+
pass.end();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=pathTracePass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathTracePass.js","sourceRoot":"","sources":["../src/pathTracePass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CameraState, RenderBackgroundMode, SerializedScene } from "./upstream.js";
|
|
2
|
+
/**
|
|
3
|
+
* The CPU renderer's planar captures (`userData.cpuRenderer.planarCapture`): a flat surface whose shader samples what is
|
|
4
|
+
* reflected in it and seen through it, as `tReflectionMap`, `tEnvironmentReflectionMap`, `tRefractionMap` and
|
|
5
|
+
* `tRefractionDepth`, through `reflectionMatrix` and `refractionMatrix`. The cameras, the clip planes and the matrices are
|
|
6
|
+
* `pipeline.js`'s own; the images are rendered by this renderer, path traced from those cameras.
|
|
7
|
+
*/
|
|
8
|
+
export interface PlanarCapture {
|
|
9
|
+
/** The texture the image goes to, and the depth texture for the refraction capture. */
|
|
10
|
+
texture: string;
|
|
11
|
+
depth?: string;
|
|
12
|
+
camera: CameraState;
|
|
13
|
+
/** Whether the capture sees the scene, without its planar surfaces, or only the environment. */
|
|
14
|
+
scene: "scene" | "environment";
|
|
15
|
+
background: RenderBackgroundMode;
|
|
16
|
+
/** Drops what lies behind the plane, as the capture's clip plane does: `dot(xyz, p) + w < 0` is cut. */
|
|
17
|
+
clip?: number[];
|
|
18
|
+
}
|
|
19
|
+
export interface PlanarCaptures {
|
|
20
|
+
/** The scene with the capture textures in its table and each material's capture uniforms bound. */
|
|
21
|
+
scene: SerializedScene;
|
|
22
|
+
/** The scene the captures see: everything but the planar surfaces, which never appear in one. */
|
|
23
|
+
captureScene: SerializedScene;
|
|
24
|
+
captures: PlanarCapture[];
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
}
|
|
28
|
+
/** The captures a scene needs from this camera, or null when it has no planar surface. */
|
|
29
|
+
export declare function planarCaptures(source: SerializedScene, camera: CameraState, width: number, height: number): PlanarCaptures | null;
|
|
30
|
+
export declare class CaptureResolvePass {
|
|
31
|
+
private readonly device;
|
|
32
|
+
private readonly pipeline;
|
|
33
|
+
private readonly uniforms;
|
|
34
|
+
constructor(device: GPUDevice);
|
|
35
|
+
/** `color` and `depth` are word offsets of the textures' texels; a depth of 0xffffffff writes none. */
|
|
36
|
+
encode(encoder: GPUCommandEncoder, accumulation: GPUBuffer, textures: GPUBuffer, width: number, height: number, color: number, depth: number): void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=planarCapture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planarCapture.d.ts","sourceRoot":"","sources":["../src/planarCapture.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAsB,eAAe,EAAqB,MAAM,eAAe,CAAC;AAE/H;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,gGAAgG;IAChG,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC;IAC/B,UAAU,EAAE,oBAAoB,CAAC;IACjC,wGAAwG;IACxG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,mGAAmG;IACnG,KAAK,EAAE,eAAe,CAAC;IACvB,iGAAiG;IACjG,YAAY,EAAE,eAAe,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAsBD,0FAA0F;AAC1F,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CA4FpG;AA6CD,qBAAa,kBAAkB;IAIjB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;gBAER,MAAM,EAAE,SAAS;IAO9C,uGAAuG;IACvG,MAAM,CAAC,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAC7E,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAmB9D"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Matrix3, Matrix4, Plane, Vector3 } from "three";
|
|
2
|
+
import { cameraProjection } from "./camera.js";
|
|
3
|
+
import { createShaderModule } from "./shaderModule.js";
|
|
4
|
+
/** A capture is rendered at most this wide; it is a texture a shader blurs and distorts, not the image itself. */
|
|
5
|
+
const MAX_CAPTURE = 512;
|
|
6
|
+
function placeholder(id, width, height) {
|
|
7
|
+
return {
|
|
8
|
+
id,
|
|
9
|
+
width,
|
|
10
|
+
height,
|
|
11
|
+
data: new Float32Array(width * height * 4),
|
|
12
|
+
colorSpace: "srgb-linear",
|
|
13
|
+
wrapS: 1001,
|
|
14
|
+
wrapT: 1001,
|
|
15
|
+
matrix: [1, 0, 0, 0, 1, 0, 0, 0, 1],
|
|
16
|
+
// The rows are written top first, as the CPU renderer writes them.
|
|
17
|
+
flipY: true,
|
|
18
|
+
channel: 0,
|
|
19
|
+
nearest: false,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** The captures a scene needs from this camera, or null when it has no planar surface. */
|
|
23
|
+
export function planarCaptures(source, camera, width, height) {
|
|
24
|
+
const planar = source.meshes.filter(mesh => !mesh.primitive && mesh.materials.some(material => material?.planarCapture && material.shader));
|
|
25
|
+
if (!planar.length)
|
|
26
|
+
return null;
|
|
27
|
+
const scale = Math.min(1, MAX_CAPTURE / Math.max(width, height));
|
|
28
|
+
const captureWidth = Math.max(1, Math.round(width * scale));
|
|
29
|
+
const captureHeight = Math.max(1, Math.round(height * scale));
|
|
30
|
+
const textures = [...source.textures];
|
|
31
|
+
const captures = [];
|
|
32
|
+
const copies = new Map();
|
|
33
|
+
const cameraWorld = new Matrix4().fromArray(camera.matrixWorld);
|
|
34
|
+
const projection = cameraProjection(camera, width / height);
|
|
35
|
+
const bias = new Matrix4().set(0.5, 0, 0, 0.5, 0, 0.5, 0, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 1);
|
|
36
|
+
for (const mesh of planar) {
|
|
37
|
+
const model = new Matrix4().fromArray(mesh.matrixWorld);
|
|
38
|
+
const normal = new Vector3(0, 1, 0).applyMatrix3(new Matrix3().getNormalMatrix(model)).normalize();
|
|
39
|
+
const point = new Vector3().setFromMatrixPosition(model);
|
|
40
|
+
const plane = new Plane().setFromNormalAndCoplanarPoint(normal, point);
|
|
41
|
+
const { x, y, z } = normal, d = plane.constant;
|
|
42
|
+
const mirror = new Matrix4().set(1 - 2 * x * x, -2 * x * y, -2 * x * z, -2 * d * x, -2 * y * x, 1 - 2 * y * y, -2 * y * z, -2 * d * y, -2 * z * x, -2 * z * y, 1 - 2 * z * z, -2 * d * z, 0, 0, 0, 1);
|
|
43
|
+
const reflected = { ...camera, matrixWorld: mirror.clone().multiply(cameraWorld).toArray() };
|
|
44
|
+
const side = plane.distanceToPoint(new Vector3().setFromMatrixPosition(cameraWorld)) >= 0 ? 1 : -1;
|
|
45
|
+
const textureMatrix = (world) => bias.clone().multiply(projection)
|
|
46
|
+
.multiply(new Matrix4().fromArray(world).invert()).multiply(model).toArray();
|
|
47
|
+
for (const material of mesh.materials) {
|
|
48
|
+
if (!material?.planarCapture || !material.shader)
|
|
49
|
+
continue;
|
|
50
|
+
const id = material.planarCapture.id;
|
|
51
|
+
const copy = {
|
|
52
|
+
...material,
|
|
53
|
+
shader: { ...material.shader, uniforms: { ...material.shader.uniforms } },
|
|
54
|
+
};
|
|
55
|
+
const uniforms = copy.shader.uniforms;
|
|
56
|
+
const names = {
|
|
57
|
+
reflection: `${id}:tReflectionMap`,
|
|
58
|
+
environment: `${id}:tEnvironmentReflectionMap`,
|
|
59
|
+
refraction: `${id}:tRefractionMap`,
|
|
60
|
+
depth: `${id}:tRefractionDepth`,
|
|
61
|
+
};
|
|
62
|
+
Object.assign(uniforms, {
|
|
63
|
+
reflectionMatrix: textureMatrix(reflected.matrixWorld),
|
|
64
|
+
refractionMatrix: textureMatrix(camera.matrixWorld),
|
|
65
|
+
cameraNear: camera.near,
|
|
66
|
+
cameraFar: camera.far,
|
|
67
|
+
tReflectionMap: { texture: names.reflection },
|
|
68
|
+
tEnvironmentReflectionMap: { texture: names.environment },
|
|
69
|
+
tRefractionMap: { texture: names.refraction },
|
|
70
|
+
tRefractionDepth: { texture: names.depth },
|
|
71
|
+
});
|
|
72
|
+
copies.set(material, copy);
|
|
73
|
+
for (const name of Object.values(names))
|
|
74
|
+
textures.push(placeholder(name, captureWidth, captureHeight));
|
|
75
|
+
captures.push({ texture: names.reflection, camera: reflected, scene: "scene", background: "transparent",
|
|
76
|
+
clip: [x * side, y * side, z * side, d * side + 0.01] }, { texture: names.environment, camera: reflected, scene: "environment", background: "environment" }, { texture: names.refraction, depth: names.depth, camera, scene: "scene", background: "environment",
|
|
77
|
+
clip: [-x * side, -y * side, -z * side, -d * side + 0.01] });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const scene = {
|
|
81
|
+
...source,
|
|
82
|
+
textures,
|
|
83
|
+
meshes: source.meshes.map(mesh => ({ ...mesh, materials: mesh.materials.map(m => (m && copies.get(m)) ?? m) })),
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
scene,
|
|
87
|
+
captureScene: { ...source, meshes: source.meshes.filter(mesh => !planar.includes(mesh)) },
|
|
88
|
+
captures,
|
|
89
|
+
width: captureWidth,
|
|
90
|
+
height: captureHeight,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Writes a finished capture from its accumulation buffer into the texels of its texture, and the depth into another. */
|
|
94
|
+
const RESOLVE_WGSL = /* wgsl */ `
|
|
95
|
+
struct Resolve {
|
|
96
|
+
size: vec2<u32>,
|
|
97
|
+
color: u32,
|
|
98
|
+
depth: u32,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
@group(0) @binding(0) var<uniform> resolve: Resolve;
|
|
102
|
+
@group(0) @binding(1) var<storage, read> accumulation: array<vec4<f32>>;
|
|
103
|
+
@group(0) @binding(2) var<storage, read_write> textures: array<u32>;
|
|
104
|
+
|
|
105
|
+
@compute @workgroup_size(64, 1, 1)
|
|
106
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
107
|
+
let count = resolve.size.x * resolve.size.y;
|
|
108
|
+
let i = id.x;
|
|
109
|
+
|
|
110
|
+
if (i >= count) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let sum = accumulation[i];
|
|
115
|
+
let extra = accumulation[count + i];
|
|
116
|
+
let n = max(sum.w, 1.0);
|
|
117
|
+
// Linear light, premultiplied by the coverage, as the CPU renderer's capture holds it.
|
|
118
|
+
let color = vec4<f32>(sum.rgb / n, extra.x / n);
|
|
119
|
+
|
|
120
|
+
for (var c = 0u; c < 4u; c = c + 1u) {
|
|
121
|
+
textures[resolve.color + i * 4u + c] = bitcast<u32>(color[c]);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (resolve.depth != 0xffffffffu) {
|
|
125
|
+
let depth = extra.y / n;
|
|
126
|
+
|
|
127
|
+
for (var c = 0u; c < 3u; c = c + 1u) {
|
|
128
|
+
textures[resolve.depth + i * 4u + c] = bitcast<u32>(depth);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
textures[resolve.depth + i * 4u + 3u] = bitcast<u32>(1.0);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
export class CaptureResolvePass {
|
|
136
|
+
device;
|
|
137
|
+
pipeline;
|
|
138
|
+
uniforms;
|
|
139
|
+
constructor(device) {
|
|
140
|
+
this.device = device;
|
|
141
|
+
const module = createShaderModule(device, "capture resolve", RESOLVE_WGSL);
|
|
142
|
+
this.pipeline = device.createComputePipeline({ layout: "auto", compute: { module, entryPoint: "main" } });
|
|
143
|
+
this.uniforms = device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
144
|
+
}
|
|
145
|
+
/** `color` and `depth` are word offsets of the textures' texels; a depth of 0xffffffff writes none. */
|
|
146
|
+
encode(encoder, accumulation, textures, width, height, color, depth) {
|
|
147
|
+
this.device.queue.writeBuffer(this.uniforms, 0, new Uint32Array([width, height, color, depth]));
|
|
148
|
+
const group = this.device.createBindGroup({
|
|
149
|
+
layout: this.pipeline.getBindGroupLayout(0),
|
|
150
|
+
entries: [
|
|
151
|
+
{ binding: 0, resource: { buffer: this.uniforms } },
|
|
152
|
+
{ binding: 1, resource: { buffer: accumulation } },
|
|
153
|
+
{ binding: 2, resource: { buffer: textures } },
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
const pass = encoder.beginComputePass({ label: "capture resolve" });
|
|
157
|
+
pass.setPipeline(this.pipeline);
|
|
158
|
+
pass.setBindGroup(0, group);
|
|
159
|
+
pass.dispatchWorkgroups(Math.ceil(width * height / 64));
|
|
160
|
+
pass.end();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=planarCapture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planarCapture.js","sourceRoot":"","sources":["../src/planarCapture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RenderToneMapping } from "./upstream.js";
|
|
2
|
+
export interface PresentUniforms {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
exposure: number;
|
|
6
|
+
toneMapping: RenderToneMapping;
|
|
7
|
+
vignette: number;
|
|
8
|
+
grain: number;
|
|
9
|
+
frameIndex: number;
|
|
10
|
+
transparent: boolean;
|
|
11
|
+
/** The denoiser's output, which the colour is read from instead of the accumulation when given. */
|
|
12
|
+
denoised?: GPUBuffer | null;
|
|
13
|
+
}
|
|
14
|
+
/** Resolves the accumulation buffer onto the canvas: divide by the sample count, expose, tone map, encode. */
|
|
15
|
+
export declare class PresentPass {
|
|
16
|
+
private readonly device;
|
|
17
|
+
readonly format: GPUTextureFormat;
|
|
18
|
+
private readonly pipeline;
|
|
19
|
+
private readonly uniforms;
|
|
20
|
+
private readonly values;
|
|
21
|
+
private readonly floats;
|
|
22
|
+
private readonly integers;
|
|
23
|
+
private bindGroup;
|
|
24
|
+
private accumulation;
|
|
25
|
+
private source;
|
|
26
|
+
constructor(device: GPUDevice, format: GPUTextureFormat);
|
|
27
|
+
setAccumulation(accumulation: GPUBuffer): void;
|
|
28
|
+
private bind;
|
|
29
|
+
encode(encoder: GPUCommandEncoder, view: GPUTextureView, present: PresentUniforms): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=presentPass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentPass.d.ts","sourceRoot":"","sources":["../src/presentPass.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGvD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAOD,8GAA8G;AAC9G,qBAAa,WAAW;IAUV,OAAO,CAAC,QAAQ,CAAC,MAAM;IAAa,QAAQ,CAAC,MAAM,EAAE,gBAAgB;IATjF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IACzD,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,MAAM,CAA0B;gBAEX,MAAM,EAAE,SAAS,EAAW,MAAM,EAAE,gBAAgB;IAejF,eAAe,CAAC,YAAY,EAAE,SAAS;IAKvC,OAAO,CAAC,IAAI;IAmBZ,MAAM,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe;CA0BlF"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createShaderModule } from "./shaderModule.js";
|
|
2
|
+
import { PRESENT_WGSL } from "./wgsl/present.wgsl.js";
|
|
3
|
+
/** The order the shader's `toneMapping` switch expects. */
|
|
4
|
+
const TONE_MAPPING = ["aces", "agx", "neutral", "linear"];
|
|
5
|
+
const PRESENT_BYTES = 48;
|
|
6
|
+
/** Resolves the accumulation buffer onto the canvas: divide by the sample count, expose, tone map, encode. */
|
|
7
|
+
export class PresentPass {
|
|
8
|
+
device;
|
|
9
|
+
format;
|
|
10
|
+
pipeline;
|
|
11
|
+
uniforms;
|
|
12
|
+
values = new ArrayBuffer(PRESENT_BYTES);
|
|
13
|
+
floats = new Float32Array(this.values);
|
|
14
|
+
integers = new Uint32Array(this.values);
|
|
15
|
+
bindGroup = null;
|
|
16
|
+
accumulation = null;
|
|
17
|
+
source = null;
|
|
18
|
+
constructor(device, format) {
|
|
19
|
+
this.device = device;
|
|
20
|
+
this.format = format;
|
|
21
|
+
const module = createShaderModule(device, "present", PRESENT_WGSL);
|
|
22
|
+
this.pipeline = device.createRenderPipeline({
|
|
23
|
+
layout: "auto",
|
|
24
|
+
vertex: { module, entryPoint: "vertexMain" },
|
|
25
|
+
fragment: { module, entryPoint: "fragmentMain", targets: [{ format }] },
|
|
26
|
+
primitive: { topology: "triangle-list" },
|
|
27
|
+
});
|
|
28
|
+
this.uniforms = device.createBuffer({
|
|
29
|
+
size: PRESENT_BYTES,
|
|
30
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
setAccumulation(accumulation) {
|
|
34
|
+
this.accumulation = accumulation;
|
|
35
|
+
this.bind(null);
|
|
36
|
+
}
|
|
37
|
+
bind(denoised) {
|
|
38
|
+
if (!this.accumulation)
|
|
39
|
+
return;
|
|
40
|
+
// Without a denoised image the accumulation stands in for it; the uniform says which one to read.
|
|
41
|
+
const source = denoised ?? this.accumulation;
|
|
42
|
+
if (this.bindGroup && source === this.source)
|
|
43
|
+
return;
|
|
44
|
+
this.source = source;
|
|
45
|
+
this.bindGroup = this.device.createBindGroup({
|
|
46
|
+
layout: this.pipeline.getBindGroupLayout(0),
|
|
47
|
+
entries: [
|
|
48
|
+
{ binding: 0, resource: { buffer: this.uniforms } },
|
|
49
|
+
{ binding: 1, resource: { buffer: this.accumulation } },
|
|
50
|
+
{ binding: 2, resource: { buffer: source } },
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
encode(encoder, view, present) {
|
|
55
|
+
this.bind(present.denoised ?? null);
|
|
56
|
+
if (!this.bindGroup)
|
|
57
|
+
throw new Error("GPU renderer: the presentation pass has no accumulation buffer bound.");
|
|
58
|
+
this.integers[0] = present.width;
|
|
59
|
+
this.integers[1] = present.height;
|
|
60
|
+
this.floats[2] = present.exposure;
|
|
61
|
+
this.integers[3] = Math.max(0, TONE_MAPPING.indexOf(present.toneMapping));
|
|
62
|
+
this.floats[4] = present.vignette;
|
|
63
|
+
this.floats[5] = present.grain;
|
|
64
|
+
this.integers[6] = present.frameIndex;
|
|
65
|
+
this.integers[7] = present.transparent ? 1 : 0;
|
|
66
|
+
this.integers[8] = present.denoised ? 1 : 0;
|
|
67
|
+
this.device.queue.writeBuffer(this.uniforms, 0, this.values);
|
|
68
|
+
const pass = encoder.beginRenderPass({
|
|
69
|
+
label: "present",
|
|
70
|
+
colorAttachments: [{ view, loadOp: "clear", storeOp: "store", clearValue: { r: 0, g: 0, b: 0, a: 1 } }],
|
|
71
|
+
});
|
|
72
|
+
pass.setPipeline(this.pipeline);
|
|
73
|
+
pass.setBindGroup(0, this.bindGroup);
|
|
74
|
+
pass.draw(3);
|
|
75
|
+
pass.end();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=presentPass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentPass.js","sourceRoot":"","sources":["../src/presentPass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { type BvhWorkerFactory } from "./bvhBuilder.js";
|
|
2
|
+
import { type DenoiserSettings } from "./denoise.js";
|
|
3
|
+
import { EventEmitter, type Bucket, type RenderCamera, type RenderEnvironment, type RenderImage, type RenderPhase, type RenderPixels, type RenderScene, type RenderSettings, type RenderSettingsInput, type SerializedScene } from "./upstream.js";
|
|
4
|
+
export type { RenderCamera, RenderImage, RenderPhase, RenderPixels, RenderScene } from "./upstream.js";
|
|
5
|
+
/**
|
|
6
|
+
* The CPU renderer's events, with the same payloads, so a host listens to either renderer the same way. What differs
|
|
7
|
+
* is when they fire: nothing is finished until the last sample lands, so the pixels arrive once.
|
|
8
|
+
*/
|
|
9
|
+
export interface GpuRendererEvents {
|
|
10
|
+
/** The scene is on the device and tracing starts; `image` has the render size and is empty. */
|
|
11
|
+
start: {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
/** The finished image, once, as a single region at (0, 0). `image` already holds it. */
|
|
16
|
+
pixels: RenderPixels;
|
|
17
|
+
/** Rows traced out of `total`, over every sample. `"prepare"` while the scene uploads, `"shade"` while it traces. */
|
|
18
|
+
progress: {
|
|
19
|
+
completed: number;
|
|
20
|
+
total: number;
|
|
21
|
+
phase: RenderPhase;
|
|
22
|
+
};
|
|
23
|
+
/** The band of rows being traced, as a bucket of worker 0, or `null` when the device is idle. */
|
|
24
|
+
bucket: {
|
|
25
|
+
worker: number;
|
|
26
|
+
bucket: Bucket | null;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
/** One more sample per pixel finished over the whole image. Only this renderer has it. */
|
|
31
|
+
sample: {
|
|
32
|
+
samples: number;
|
|
33
|
+
target: number;
|
|
34
|
+
};
|
|
35
|
+
/** `image` is finished. */
|
|
36
|
+
complete: void;
|
|
37
|
+
/** The frame failed; `render()` rejects with the same error. */
|
|
38
|
+
error: Error;
|
|
39
|
+
}
|
|
40
|
+
/** The CPU renderer's options without its worker pool, which has no counterpart on a device. */
|
|
41
|
+
export interface GpuRendererOptions {
|
|
42
|
+
scene?: RenderScene | SerializedScene;
|
|
43
|
+
/** Defaults to a perspective camera at (5, 5, 5) looking at the origin. */
|
|
44
|
+
camera?: RenderCamera;
|
|
45
|
+
/** Merged over `DEFAULT_RENDER_SETTINGS`, group by group. */
|
|
46
|
+
settings?: RenderSettingsInput;
|
|
47
|
+
/** Defaults to `DEFAULT_RENDER_ENVIRONMENT`. */
|
|
48
|
+
environment?: RenderEnvironment;
|
|
49
|
+
/** Image size in CSS pixels; the render size also applies `pixelRatio` and `settings.renderScale`. */
|
|
50
|
+
width: number;
|
|
51
|
+
height: number;
|
|
52
|
+
/** Defaults to 1. */
|
|
53
|
+
pixelRatio?: number;
|
|
54
|
+
/** How the denoiser filters, when `settings.globalIllumination.denoise` turns it on. Merged over `DEFAULT_DENOISER`. */
|
|
55
|
+
denoiser?: Partial<DenoiserSettings>;
|
|
56
|
+
/**
|
|
57
|
+
* Builds the BVH of a large scene in a Web Worker, so the page keeps responding while it is split. The tree is the
|
|
58
|
+
* same either way. Defaults to true where Web Workers exist, or when `createBvhWorker` is given; false builds on the
|
|
59
|
+
* main thread. If the worker cannot start, the renderer warns once and builds on the main thread.
|
|
60
|
+
*/
|
|
61
|
+
bvhWorker?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Starts the BVH worker. Replace it when the bundler cannot follow `new URL("./bvhWorker.js", import.meta.url)`, or
|
|
64
|
+
* outside the browser, with anything shaped like a Web Worker that runs `dist/bvhWorker.js`.
|
|
65
|
+
*/
|
|
66
|
+
createBvhWorker?: BvhWorkerFactory;
|
|
67
|
+
}
|
|
68
|
+
/** `render()` rejects with this when a newer frame, `cancel()` or `dispose()` replaced the frame it started. */
|
|
69
|
+
export declare const isAbortError: (error: unknown) => boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Path traces a Three.js scene on the GPU, behind the same API as `CpuRenderer`. The setters record the inputs;
|
|
72
|
+
* `render()` opens a frame with whatever is current and accumulates samples until it reaches `settings.samples`.
|
|
73
|
+
*/
|
|
74
|
+
export declare class GpuRenderer extends EventEmitter<GpuRendererEvents> {
|
|
75
|
+
private current;
|
|
76
|
+
private environment;
|
|
77
|
+
private scene;
|
|
78
|
+
private probe;
|
|
79
|
+
private camera;
|
|
80
|
+
private width;
|
|
81
|
+
private height;
|
|
82
|
+
private pixelRatio;
|
|
83
|
+
private output;
|
|
84
|
+
private frame;
|
|
85
|
+
private isPaused;
|
|
86
|
+
private resumed;
|
|
87
|
+
private unpaused;
|
|
88
|
+
private ready;
|
|
89
|
+
private gpu;
|
|
90
|
+
private accumulator;
|
|
91
|
+
private pathTrace;
|
|
92
|
+
private present;
|
|
93
|
+
private buffers;
|
|
94
|
+
private packed;
|
|
95
|
+
private sceneDirty;
|
|
96
|
+
private assets;
|
|
97
|
+
private packedView;
|
|
98
|
+
private target;
|
|
99
|
+
private planar;
|
|
100
|
+
private resolve;
|
|
101
|
+
private denoisePass;
|
|
102
|
+
private denoiserSettings;
|
|
103
|
+
private finished;
|
|
104
|
+
private denoised;
|
|
105
|
+
private denoiseView;
|
|
106
|
+
private environmentSource;
|
|
107
|
+
private environmentImage;
|
|
108
|
+
private canvas;
|
|
109
|
+
private context;
|
|
110
|
+
private scheduler;
|
|
111
|
+
private revision;
|
|
112
|
+
private frameIndex;
|
|
113
|
+
private disposed;
|
|
114
|
+
private bvh;
|
|
115
|
+
constructor(options: GpuRendererOptions);
|
|
116
|
+
/** The settings the next frame renders with. */
|
|
117
|
+
get settings(): Readonly<RenderSettings>;
|
|
118
|
+
/** How the denoiser filters. */
|
|
119
|
+
get denoiser(): Readonly<DenoiserSettings>;
|
|
120
|
+
/**
|
|
121
|
+
* Merges the given fields into the denoiser's settings. Filtering costs nothing like tracing, so a finished image is
|
|
122
|
+
* filtered again at once, without tracing anything: `image` and the canvas take the result and `pixels` fires. A frame
|
|
123
|
+
* in flight uses them from its next pass on.
|
|
124
|
+
*/
|
|
125
|
+
setDenoiser(input: Partial<DenoiserSettings>): void;
|
|
126
|
+
/** Filters the finished image again with the current denoiser settings, or shows it unfiltered when it is off. */
|
|
127
|
+
private refilter;
|
|
128
|
+
/** A frame is in flight: `render()` was called and has not settled. */
|
|
129
|
+
get rendering(): boolean;
|
|
130
|
+
get paused(): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* The image of the last finished frame, or an empty one of the render size while a frame traces; `null` before the
|
|
133
|
+
* first frame starts. Each frame allocates a new buffer, so a reference taken at `complete` stays as it is.
|
|
134
|
+
*/
|
|
135
|
+
get image(): RenderImage | null;
|
|
136
|
+
get renderWidth(): number;
|
|
137
|
+
get renderHeight(): number;
|
|
138
|
+
/** Image size in CSS pixels for the next frame; `pixelRatio` stays as it is when omitted. */
|
|
139
|
+
setSize(width: number, height: number, pixelRatio?: number): void;
|
|
140
|
+
setPixelRatio(pixelRatio: number): void;
|
|
141
|
+
/**
|
|
142
|
+
* Takes a Three scene, serialized in the background, or the result of `serializeScene`. The live scene is not read
|
|
143
|
+
* again until this is called once more.
|
|
144
|
+
*/
|
|
145
|
+
setScene(scene: RenderScene | SerializedScene): void;
|
|
146
|
+
/**
|
|
147
|
+
* A Three camera is read at every `render()`, so moving it or changing its aspect only needs a new frame.
|
|
148
|
+
* A `CameraState` snapshot is used as it is.
|
|
149
|
+
*/
|
|
150
|
+
setCamera(camera: RenderCamera): void;
|
|
151
|
+
/**
|
|
152
|
+
* Merges the given fields into the current settings, group by group. Turning the denoiser on or off also filters the
|
|
153
|
+
* finished image again at once, as `setDenoiser` does, since that needs no tracing.
|
|
154
|
+
*/
|
|
155
|
+
setSettings(settings: RenderSettingsInput): void;
|
|
156
|
+
setEnvironment(environment: RenderEnvironment): void;
|
|
157
|
+
/** Used by `attachCanvas`; pass `null` to detach. */
|
|
158
|
+
setOutputCanvas(canvas: HTMLCanvasElement | null): void;
|
|
159
|
+
/**
|
|
160
|
+
* Starts a frame with the current scene, camera, settings, environment and size, discarding any frame in
|
|
161
|
+
* progress, and accumulates `settings.samples` samples per pixel. Resolves with the finished image. Rejects with an
|
|
162
|
+
* `AbortError` when a later `render()`, `cancel()` or `dispose()` replaces the frame, and with the error when the
|
|
163
|
+
* frame fails.
|
|
164
|
+
*/
|
|
165
|
+
render(): Promise<RenderImage>;
|
|
166
|
+
/** Stops between two dispatches; `resume()` continues the same frame. */
|
|
167
|
+
pause(): void;
|
|
168
|
+
resume(): void;
|
|
169
|
+
/**
|
|
170
|
+
* Stops the frame in flight and keeps the device for the next one. `render()` rejects with an `AbortError` and
|
|
171
|
+
* `image` keeps what it held. A paused frame is cancelled too, and the next one starts unpaused. Does nothing
|
|
172
|
+
* without a frame in flight.
|
|
173
|
+
*/
|
|
174
|
+
cancel(): void;
|
|
175
|
+
/** Releases the device. A frame in flight rejects with an `AbortError`. */
|
|
176
|
+
dispose(): void;
|
|
177
|
+
/** Takes the frame in flight, if any, so it can be settled after the events go out. */
|
|
178
|
+
private settle;
|
|
179
|
+
/** Settles the frame in flight, if any, with an `AbortError`. */
|
|
180
|
+
private abort;
|
|
181
|
+
private fail;
|
|
182
|
+
private emitIdle;
|
|
183
|
+
private device;
|
|
184
|
+
private accumulate;
|
|
185
|
+
/** The rows a pass still traced something in, read back from the accumulator's row flags. */
|
|
186
|
+
private activeRows;
|
|
187
|
+
private check;
|
|
188
|
+
/** Uploads what changed and makes sure the passes point at the current buffers. */
|
|
189
|
+
private prepare;
|
|
190
|
+
/** Packs and uploads one scene: its textures, geometry, hierarchy, lights and every extra word they point at. */
|
|
191
|
+
private packScene;
|
|
192
|
+
/**
|
|
193
|
+
* Renders a scene's planar captures with this renderer, from the mirrored and the real camera, and writes each into
|
|
194
|
+
* the texels of its placeholder in the main scene's texture buffer. Everything is queued ahead of the frame itself,
|
|
195
|
+
* which the queue then runs in order.
|
|
196
|
+
*/
|
|
197
|
+
private renderCaptures;
|
|
198
|
+
private configureCanvas;
|
|
199
|
+
private encodePresent;
|
|
200
|
+
/** Denoises the accumulation as it stands, for the canvas and for the finished image. */
|
|
201
|
+
private encodeDenoise;
|
|
202
|
+
private frameUniforms;
|
|
203
|
+
/**
|
|
204
|
+
* Copies the accumulation buffer back and resolves it on the CPU, with the same exposure, tone mapping and sRGB
|
|
205
|
+
* encoding the presentation pass applies. Grain is a presentation effect and is not part of the returned image.
|
|
206
|
+
*/
|
|
207
|
+
private readImage;
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=renderer.d.ts.map
|