@tinypoly/gpu-renderer 0.0.5 → 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 +59 -3
- package/README.md +52 -4
- 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/denoise.d.ts +11 -1
- package/dist/denoise.d.ts.map +1 -1
- package/dist/denoise.js +34 -6
- package/dist/denoise.js.map +1 -1
- package/dist/frameLayout.d.ts.map +1 -1
- package/dist/frameLayout.js +15 -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 +10 -0
- package/dist/lights.d.ts.map +1 -1
- package/dist/lights.js +54 -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 +118 -14
- package/dist/renderer.js.map +1 -1
- package/dist/sceneUpload.d.ts +5 -0
- package/dist/sceneUpload.d.ts.map +1 -1
- package/dist/sceneUpload.js +4 -0
- 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/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/common.wgsl.d.ts.map +1 -1
- package/dist/wgsl/common.wgsl.js +4 -0
- 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 +203 -31
- 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 +396 -25
- package/dist/wgsl/pathTrace.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 +21 -1
- package/dist/wgsl/surface.wgsl.js.map +1 -1
- package/package.json +1 -1
- package/src/atmosphere.ts +95 -0
- package/src/denoise.ts +44 -6
- package/src/frameLayout.ts +15 -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 +71 -1
- package/src/materialLayout.ts +52 -1
- package/src/pathTracePass.ts +19 -10
- package/src/renderer.ts +166 -22
- package/src/sceneUpload.ts +9 -0
- package/src/settings.ts +234 -0
- package/src/subsurface.ts +153 -0
- package/src/volumeContainment.ts +81 -0
- package/src/wgsl/bsdf.wgsl.ts +35 -3
- package/src/wgsl/common.wgsl.ts +4 -0
- package/src/wgsl/lens.wgsl.ts +314 -0
- package/src/wgsl/lights.wgsl.ts +203 -31
- package/src/wgsl/pathTrace.wgsl.ts +396 -25
- package/src/wgsl/sampling.wgsl.ts +25 -0
- package/src/wgsl/surface.wgsl.ts +21 -1
package/dist/pathTracePass.js
CHANGED
|
@@ -18,8 +18,11 @@ import { TEXTURE_WGSL } from "./wgsl/texture.wgsl.js";
|
|
|
18
18
|
* declarations. The scene's translated shaders sit between the texture code they call and the surface code that calls
|
|
19
19
|
* them.
|
|
20
20
|
*/
|
|
21
|
-
export function pathTraceSource(programs = null) {
|
|
22
|
-
|
|
21
|
+
export function pathTraceSource(programs = null, subsurface = true, volumes = true, bevel = true) {
|
|
22
|
+
// The random walk inside materials and the media inside volumes are compiled in only for a scene that has them: the
|
|
23
|
+
// kernel is bound by its size, and either would cost every other scene a few percent for code that never runs.
|
|
24
|
+
return `const SUBSURFACE_WALK: bool = ${subsurface};\nconst VOLUMES: bool = ${volumes};\nconst BEVEL: bool = ${bevel};\n`
|
|
25
|
+
+ COMMON_WGSL + RANDOM_WGSL + BVH_WGSL + SAMPLING_WGSL + TEXTURE_WGSL + SHADER_SUPPORT_WGSL
|
|
23
26
|
+ programsWgsl(programs) + ENVIRONMENT_WGSL + SURFACE_WGSL + BSDF_WGSL + LIGHTS_WGSL + PATH_TRACE_WGSL;
|
|
24
27
|
}
|
|
25
28
|
const FRAME_BYTES = FRAME_WORDS * 4;
|
|
@@ -30,23 +33,26 @@ export class PathTracePass {
|
|
|
30
33
|
uniforms;
|
|
31
34
|
values = new ArrayBuffer(FRAME_BYTES);
|
|
32
35
|
bindGroup = null;
|
|
33
|
-
programKey = "";
|
|
36
|
+
programKey = "|false|false|false";
|
|
34
37
|
constructor(device) {
|
|
35
38
|
this.device = device;
|
|
36
|
-
this.pipeline = this.build(null);
|
|
39
|
+
this.pipeline = this.build(null, false, false, false);
|
|
37
40
|
this.uniforms = device.createBuffer({ size: FRAME_BYTES, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
38
41
|
}
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Recompiles the kernel when the scene's shaders changed, or whether it has a material that scatters light inside;
|
|
44
|
+
* the same set keeps the pipeline it has.
|
|
45
|
+
*/
|
|
46
|
+
setPrograms(programs, subsurface = false, volumes = false, bevel = false) {
|
|
47
|
+
const key = `${programs?.key ?? ""}|${subsurface}|${volumes}|${bevel}`;
|
|
42
48
|
if (key === this.programKey)
|
|
43
49
|
return;
|
|
44
50
|
this.programKey = key;
|
|
45
|
-
this.pipeline = this.build(programs);
|
|
51
|
+
this.pipeline = this.build(programs, subsurface, volumes, bevel);
|
|
46
52
|
this.bindGroup = null;
|
|
47
53
|
}
|
|
48
|
-
build(programs) {
|
|
49
|
-
const module = createShaderModule(this.device, "path trace", pathTraceSource(programs));
|
|
54
|
+
build(programs, subsurface, volumes, bevel) {
|
|
55
|
+
const module = createShaderModule(this.device, "path trace", pathTraceSource(programs, subsurface, volumes, bevel));
|
|
50
56
|
return this.device.createComputePipeline({ layout: "auto", compute: { module, entryPoint: "main" } });
|
|
51
57
|
}
|
|
52
58
|
/** Rebinds after the scene or the accumulation buffer was replaced. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pathTracePass.js","sourceRoot":"","sources":["../src/pathTracePass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAuB,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAKtD;;;;GAIG;AACH,MAAM,UAAU,eAAe,
|
|
1
|
+
{"version":3,"file":"pathTracePass.js","sourceRoot":"","sources":["../src/pathTracePass.ts"],"names":[],"mappings":"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"}
|
package/dist/renderer.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type BvhWorkerFactory } from "./bvhBuilder.js";
|
|
2
|
+
import { type GpuRenderSettings, type GpuRenderSettingsInput } from "./settings.js";
|
|
2
3
|
import { type DenoiserSettings } from "./denoise.js";
|
|
3
|
-
import { EventEmitter, type Bucket, type RenderCamera, type RenderEnvironment, type RenderImage, type RenderPhase, type RenderPixels, type RenderScene, type
|
|
4
|
+
import { EventEmitter, type Bucket, type RenderCamera, type RenderEnvironment, type RenderImage, type RenderPhase, type RenderPixels, type RenderScene, type SerializedScene } from "./upstream.js";
|
|
4
5
|
export type { RenderCamera, RenderImage, RenderPhase, RenderPixels, RenderScene } from "./upstream.js";
|
|
5
6
|
/**
|
|
6
7
|
* The CPU renderer's events, with the same payloads, so a host listens to either renderer the same way. What differs
|
|
@@ -42,8 +43,11 @@ export interface GpuRendererOptions {
|
|
|
42
43
|
scene?: RenderScene | SerializedScene;
|
|
43
44
|
/** Defaults to a perspective camera at (5, 5, 5) looking at the origin. */
|
|
44
45
|
camera?: RenderCamera;
|
|
45
|
-
/**
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Merged over `DEFAULT_GPU_RENDER_SETTINGS`, group by group: the CPU renderer's settings, and the groups only this
|
|
48
|
+
* renderer reads (`bloom`, `lens`, `camera`, `subsurface`, the roulette under `globalIllumination`).
|
|
49
|
+
*/
|
|
50
|
+
settings?: GpuRenderSettingsInput;
|
|
47
51
|
/** Defaults to `DEFAULT_RENDER_ENVIRONMENT`. */
|
|
48
52
|
environment?: RenderEnvironment;
|
|
49
53
|
/** Image size in CSS pixels; the render size also applies `pixelRatio` and `settings.renderScale`. */
|
|
@@ -102,11 +106,13 @@ export declare class GpuRenderer extends EventEmitter<GpuRendererEvents> {
|
|
|
102
106
|
private planar;
|
|
103
107
|
private resolve;
|
|
104
108
|
private denoisePass;
|
|
109
|
+
private lensPass;
|
|
105
110
|
private denoiserSettings;
|
|
106
111
|
private finished;
|
|
107
112
|
private denoised;
|
|
108
113
|
private denoiseView;
|
|
109
114
|
private environmentSource;
|
|
115
|
+
private environmentAverage;
|
|
110
116
|
private environmentImage;
|
|
111
117
|
private canvas;
|
|
112
118
|
private context;
|
|
@@ -117,7 +123,7 @@ export declare class GpuRenderer extends EventEmitter<GpuRendererEvents> {
|
|
|
117
123
|
private bvh;
|
|
118
124
|
constructor(options: GpuRendererOptions);
|
|
119
125
|
/** The settings the next frame renders with. */
|
|
120
|
-
get settings(): Readonly<
|
|
126
|
+
get settings(): Readonly<GpuRenderSettings>;
|
|
121
127
|
/** How the denoiser filters. */
|
|
122
128
|
get denoiser(): Readonly<DenoiserSettings>;
|
|
123
129
|
/**
|
|
@@ -153,10 +159,11 @@ export declare class GpuRenderer extends EventEmitter<GpuRendererEvents> {
|
|
|
153
159
|
*/
|
|
154
160
|
setCamera(camera: RenderCamera): void;
|
|
155
161
|
/**
|
|
156
|
-
* Merges the given fields into the current settings, group by group. Turning the denoiser on or off
|
|
157
|
-
*
|
|
162
|
+
* Merges the given fields into the current settings, group by group. Turning the denoiser on or off, or changing
|
|
163
|
+
* what is done to the light after it is traced (exposure, tone mapping, vignette, bloom, chromatic aberration, white
|
|
164
|
+
* balance), shows the finished image again at once, as `setDenoiser` does, since none of that needs tracing.
|
|
158
165
|
*/
|
|
159
|
-
setSettings(settings:
|
|
166
|
+
setSettings(settings: GpuRenderSettingsInput): void;
|
|
160
167
|
setEnvironment(environment: RenderEnvironment): void;
|
|
161
168
|
/** Used by `attachCanvas`; pass `null` to detach. */
|
|
162
169
|
setOutputCanvas(canvas: HTMLCanvasElement | null): void;
|
|
@@ -201,6 +208,11 @@ export declare class GpuRenderer extends EventEmitter<GpuRendererEvents> {
|
|
|
201
208
|
private renderCaptures;
|
|
202
209
|
private configureCanvas;
|
|
203
210
|
private encodePresent;
|
|
211
|
+
/**
|
|
212
|
+
* The lens and the sensor over the radiance (or the denoiser's output), when the settings ask for any of them: the
|
|
213
|
+
* buffer of graded colour the display transform reads instead, or the input as it was.
|
|
214
|
+
*/
|
|
215
|
+
private encodeLens;
|
|
204
216
|
/** Denoises the accumulation as it stands, for the canvas and for the finished image. */
|
|
205
217
|
private encodeDenoise;
|
|
206
218
|
private frameUniforms;
|
package/dist/renderer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
|
package/dist/renderer.js
CHANGED
|
@@ -12,12 +12,17 @@ import { NO_TEXTURE, planTextures, textureEntry, writeTextures } from "./texture
|
|
|
12
12
|
import { PathTracePass } from "./pathTracePass.js";
|
|
13
13
|
import { ImageResolvePass } from "./imageResolve.js";
|
|
14
14
|
import { PresentPass } from "./presentPass.js";
|
|
15
|
+
import { LensPass, lensEffects } from "./lensPass.js";
|
|
16
|
+
import { DEFAULT_GPU_RENDER_SETTINGS, effectiveExposure, mergeGpuSettings, } from "./settings.js";
|
|
17
|
+
import { bevelOf, bevelRadius, subsurfaceMedium, subsurfaceOf, volumeMedium, volumeOf, } from "./subsurface.js";
|
|
18
|
+
import { containingVolume, NO_MATERIAL, volumeTriangles } from "./volumeContainment.js";
|
|
15
19
|
import { CONVERGED_ERROR, DEFAULT_DENOISER, DenoisePass, mergeDenoiser, } from "./denoise.js";
|
|
16
20
|
import { CaptureResolvePass, planarCaptures } from "./planarCapture.js";
|
|
17
21
|
import { prepareSceneAssets } from "./sceneAssets.js";
|
|
18
22
|
import { packVolumetricLights, VOLUMETRIC_WORDS } from "./volumetric.js";
|
|
19
23
|
import { environmentPower, uploadScene } from "./sceneUpload.js";
|
|
20
|
-
import {
|
|
24
|
+
import { atmosphereExtinction, averageRadiance, brightestSun, gradientAverage } from "./atmosphere.js";
|
|
25
|
+
import { DEFAULT_RENDER_ENVIRONMENT, EventEmitter, serializeCamera, serializeScene, srgbToLinear, } from "./upstream.js";
|
|
21
26
|
function abortError(message) {
|
|
22
27
|
return Object.assign(new Error(message), { name: "AbortError" });
|
|
23
28
|
}
|
|
@@ -43,6 +48,8 @@ const SHOW_EVERY_MS = 16;
|
|
|
43
48
|
* still stays short enough for the watchdog on its own.
|
|
44
49
|
*/
|
|
45
50
|
const BANDS_IN_FLIGHT = 2;
|
|
51
|
+
/** Throughput under which Russian roulette may end a path, with the chance of carrying on equal to the throughput. */
|
|
52
|
+
const ROULETTE_THRESHOLD = 0.2;
|
|
46
53
|
/** How often the canvas takes a freshly denoised image while a frame traces. */
|
|
47
54
|
const DENOISE_EVERY_MS = 200;
|
|
48
55
|
/** The most paths per pixel one dispatch takes, while no pixel can stop yet. */
|
|
@@ -127,6 +134,7 @@ export class GpuRenderer extends EventEmitter {
|
|
|
127
134
|
planar = false;
|
|
128
135
|
resolve = null;
|
|
129
136
|
denoisePass = null;
|
|
137
|
+
lensPass = null;
|
|
130
138
|
denoiserSettings = { ...DEFAULT_DENOISER };
|
|
131
139
|
// The size of the last frame that finished, which setDenoiser filters again; null while a frame traces.
|
|
132
140
|
finished = null;
|
|
@@ -136,6 +144,8 @@ export class GpuRenderer extends EventEmitter {
|
|
|
136
144
|
denoiseView = { pixelScale: 1, orthographic: false };
|
|
137
145
|
// Reading an environment image is a fetch, so it is started once and awaited by the frame that needs it.
|
|
138
146
|
environmentSource = "";
|
|
147
|
+
// The surroundings' radiance averaged over the sphere, which the air glows with; null for the gradient.
|
|
148
|
+
environmentAverage = null;
|
|
139
149
|
environmentImage = Promise.resolve(null);
|
|
140
150
|
canvas = null;
|
|
141
151
|
context = null;
|
|
@@ -150,7 +160,7 @@ export class GpuRenderer extends EventEmitter {
|
|
|
150
160
|
this.width = Math.max(1, Math.floor(options.width));
|
|
151
161
|
this.height = Math.max(1, Math.floor(options.height));
|
|
152
162
|
this.pixelRatio = checkedPixelRatio(options.pixelRatio ?? 1);
|
|
153
|
-
this.current =
|
|
163
|
+
this.current = mergeGpuSettings(DEFAULT_GPU_RENDER_SETTINGS, options.settings);
|
|
154
164
|
this.denoiserSettings = mergeDenoiser(DEFAULT_DENOISER, options.denoiser);
|
|
155
165
|
this.environment = DEFAULT_RENDER_ENVIRONMENT;
|
|
156
166
|
this.scheduler = new DispatchScheduler({ maxRows: this.renderHeight, maxSamples: BATCH_PATHS });
|
|
@@ -253,13 +263,14 @@ export class GpuRenderer extends EventEmitter {
|
|
|
253
263
|
this.camera = camera;
|
|
254
264
|
}
|
|
255
265
|
/**
|
|
256
|
-
* Merges the given fields into the current settings, group by group. Turning the denoiser on or off
|
|
257
|
-
*
|
|
266
|
+
* Merges the given fields into the current settings, group by group. Turning the denoiser on or off, or changing
|
|
267
|
+
* what is done to the light after it is traced (exposure, tone mapping, vignette, bloom, chromatic aberration, white
|
|
268
|
+
* balance), shows the finished image again at once, as `setDenoiser` does, since none of that needs tracing.
|
|
258
269
|
*/
|
|
259
270
|
setSettings(settings) {
|
|
260
|
-
const
|
|
261
|
-
this.current =
|
|
262
|
-
if (this.current
|
|
271
|
+
const before = developing(this.current);
|
|
272
|
+
this.current = mergeGpuSettings(this.current, settings);
|
|
273
|
+
if (developing(this.current) !== before)
|
|
263
274
|
this.refilter();
|
|
264
275
|
}
|
|
265
276
|
setEnvironment(environment) {
|
|
@@ -347,6 +358,8 @@ export class GpuRenderer extends EventEmitter {
|
|
|
347
358
|
this.buffers?.destroy();
|
|
348
359
|
this.accumulator?.destroy();
|
|
349
360
|
this.denoisePass?.destroy();
|
|
361
|
+
this.lensPass?.destroy();
|
|
362
|
+
this.lensPass = null;
|
|
350
363
|
this.imageResolve?.dispose();
|
|
351
364
|
this.imageResolve = null;
|
|
352
365
|
this.gpu?.device.destroy();
|
|
@@ -549,9 +562,14 @@ export class GpuRenderer extends EventEmitter {
|
|
|
549
562
|
/** Uploads what changed and makes sure the passes point at the current buffers. */
|
|
550
563
|
async prepare(gpu, revision, assets, camera, width, height, image) {
|
|
551
564
|
this.pathTrace ??= new PathTracePass(gpu.device);
|
|
552
|
-
|
|
565
|
+
const materials = assets.scene.meshes.flatMap(mesh => mesh.materials);
|
|
566
|
+
this.pathTrace.setPrograms(assets.programs, this.current.subsurface.enabled && materials.some(material => (material.type === "MeshStandardMaterial" || material.type === "MeshPhysicalMaterial")
|
|
567
|
+
&& subsurfaceOf(material) !== null),
|
|
568
|
+
// Even turned off, a volume's boundary has to stay invisible, which takes the same code.
|
|
569
|
+
materials.some(material => volumeOf(material) !== null), this.current.bevel.enabled && materials.some(material => bevelOf(material) > 0));
|
|
553
570
|
// A procedural sky stands in for the renderer's own environment, as it does in the CPU renderer.
|
|
554
571
|
const environment = assets.sky?.environment ?? image;
|
|
572
|
+
this.environmentAverage = environment ? averageRadiance(environment) : null;
|
|
555
573
|
const matrices = cameraMatrices(camera, width, height);
|
|
556
574
|
const view = `${JSON.stringify(camera)}|${width}|${height}`;
|
|
557
575
|
const moved = (!!this.packed?.cameraDependent || this.planar) && view !== this.packedView;
|
|
@@ -642,6 +660,7 @@ export class GpuRenderer extends EventEmitter {
|
|
|
642
660
|
skyData,
|
|
643
661
|
volumetricData,
|
|
644
662
|
volumetricCount: Math.min(volumetric.length / VOLUMETRIC_WORDS, 8),
|
|
663
|
+
volumes: volumeTriangles(geometry),
|
|
645
664
|
};
|
|
646
665
|
}
|
|
647
666
|
/**
|
|
@@ -671,6 +690,10 @@ export class GpuRenderer extends EventEmitter {
|
|
|
671
690
|
const uniforms = {
|
|
672
691
|
...this.frameUniforms(capture.camera, width, height, assets, target, capture.background),
|
|
673
692
|
lens: [0, 1, 0, 0],
|
|
693
|
+
lensDistortion: 0,
|
|
694
|
+
// A capture is a texture of the scene, seen again by the camera, which lays the air over it then.
|
|
695
|
+
atmosphereColor: [0, 0, 0, 0],
|
|
696
|
+
cameraVolume: NO_MATERIAL,
|
|
674
697
|
volumetricCount: 0,
|
|
675
698
|
clipPlane: capture.clip ?? [0, 0, 0, 0],
|
|
676
699
|
bandOrigin: [0, 0],
|
|
@@ -714,20 +737,31 @@ export class GpuRenderer extends EventEmitter {
|
|
|
714
737
|
this.present.setAccumulation(this.accumulator.buffer);
|
|
715
738
|
}
|
|
716
739
|
encodePresent(encoder, width, height) {
|
|
717
|
-
if (!this.context || !this.present)
|
|
740
|
+
if (!this.context || !this.present || !this.gpu)
|
|
718
741
|
return;
|
|
719
742
|
this.present.encode(encoder, this.context.getCurrentTexture().createView(), {
|
|
720
743
|
width,
|
|
721
744
|
height,
|
|
722
|
-
exposure: this.current
|
|
745
|
+
exposure: effectiveExposure(this.current),
|
|
723
746
|
toneMapping: this.current.toneMapping,
|
|
724
747
|
vignette: this.current.vignette,
|
|
725
748
|
grain: this.current.grain,
|
|
726
749
|
frameIndex: this.frameIndex,
|
|
727
750
|
transparent: this.current.background.mode === "transparent",
|
|
728
|
-
denoised: this.denoised ? this.denoisePass?.output : null,
|
|
751
|
+
denoised: this.encodeLens(this.gpu, encoder, width, height, this.denoised ? this.denoisePass?.output ?? null : null),
|
|
729
752
|
});
|
|
730
753
|
}
|
|
754
|
+
/**
|
|
755
|
+
* The lens and the sensor over the radiance (or the denoiser's output), when the settings ask for any of them: the
|
|
756
|
+
* buffer of graded colour the display transform reads instead, or the input as it was.
|
|
757
|
+
*/
|
|
758
|
+
encodeLens(gpu, encoder, width, height, denoised) {
|
|
759
|
+
const effects = lensEffects(this.current);
|
|
760
|
+
if (!effects)
|
|
761
|
+
return denoised;
|
|
762
|
+
this.lensPass ??= new LensPass(gpu.device);
|
|
763
|
+
return this.lensPass.encode(encoder, this.accumulator.buffer, denoised, width, height, effects);
|
|
764
|
+
}
|
|
731
765
|
/** Denoises the accumulation as it stands, for the canvas and for the finished image. */
|
|
732
766
|
encodeDenoise(gpu, encoder, width, height) {
|
|
733
767
|
this.denoisePass ??= new DenoisePass(gpu.device);
|
|
@@ -750,6 +784,13 @@ export class GpuRenderer extends EventEmitter {
|
|
|
750
784
|
? focalLength / (2 * Math.max(depthOfField.aperture, 1e-3))
|
|
751
785
|
: 0;
|
|
752
786
|
const backgroundMode = background.mode === "color" ? 1 : background.mode === "transparent" ? 2 : 0;
|
|
787
|
+
const { atmosphere } = this.current;
|
|
788
|
+
const strength = sky ? sky.intensity : this.environment.intensity ?? 1;
|
|
789
|
+
const airGlow = atmosphere.color
|
|
790
|
+
? linearColor(atmosphere.color, [0, 0, 0])
|
|
791
|
+
: (this.environmentAverage ?? gradientAverage(linearColor(gradient?.topColor, [1, 1, 1]), linearColor(gradient?.bottomColor, [0, 0, 0]), gradient?.exponent ?? 2)).map(channel => channel * strength);
|
|
792
|
+
const extinction = atmosphereExtinction(atmosphere);
|
|
793
|
+
const sun = brightestSun(assets.scene.lights);
|
|
753
794
|
return {
|
|
754
795
|
cameraToWorld: matrices.cameraWorld,
|
|
755
796
|
worldToCamera: matrices.view,
|
|
@@ -776,11 +817,28 @@ export class GpuRenderer extends EventEmitter {
|
|
|
776
817
|
resolution: [width, height],
|
|
777
818
|
cameraKind: matrices.orthographic ? 1 : 0,
|
|
778
819
|
bounces: Math.max(1, Math.round(this.current.globalIllumination.bounces)),
|
|
820
|
+
rouletteThreshold: this.current.globalIllumination.russianRoulette === false ? 0 : ROULETTE_THRESHOLD,
|
|
821
|
+
rouletteStart: Math.max(0, Math.round(this.current.globalIllumination.rouletteStart ?? 0)),
|
|
822
|
+
lensDistortion: Number.isFinite(this.current.lens.distortion) ? this.current.lens.distortion : 0,
|
|
823
|
+
subsurfaceEnabled: this.current.subsurface.enabled,
|
|
824
|
+
bevelEnabled: this.current.bevel.enabled,
|
|
825
|
+
volumesEnabled: this.current.volumes.enabled,
|
|
826
|
+
cameraVolume: this.current.volumes.enabled
|
|
827
|
+
? containingVolume(target?.volumes ?? null, matrices.cameraWorld.slice(12, 15))
|
|
828
|
+
: NO_MATERIAL,
|
|
829
|
+
atmosphereColor: [...airGlow, extinction.some(value => value > 0) ? 1 : 0],
|
|
830
|
+
atmosphereExtinction: [...extinction, Math.min(1, Math.max(0, Number(atmosphere.haze) || 0))],
|
|
831
|
+
atmosphereSun: [...sun?.direction ?? [0, 1, 0], 0],
|
|
832
|
+
atmosphereSunColor: [...sun?.irradiance ?? [0, 0, 0], 0],
|
|
779
833
|
triangleCount: buffers?.triangleCount ?? 0,
|
|
780
834
|
lightCount: buffers?.lightCount ?? 0,
|
|
781
835
|
areaLightCount: buffers?.areaLightCount ?? 0,
|
|
782
836
|
lightCdf: buffers?.lightCdf ?? 0,
|
|
783
837
|
lightTriangles: buffers?.lightTriangles ?? 0,
|
|
838
|
+
localLightCount: buffers?.localLightCount ?? 0,
|
|
839
|
+
localLightPick: buffers?.localLightPick ?? 0,
|
|
840
|
+
lightTree: this.current.globalIllumination.lightTree === false ? 0 : buffers?.lightTree ?? 0,
|
|
841
|
+
lightLeaves: buffers?.lightLeaves ?? 0,
|
|
784
842
|
clampIndirect: Math.max(0, this.current.globalIllumination.clamp),
|
|
785
843
|
// The setting is the angular diameter a light covers, in degrees, as it is for the CPU renderer's shadow blur.
|
|
786
844
|
shadowSpread: shadows.enabled ? Math.tan(Math.max(0, shadows.softness) * Math.PI / 360) : 0,
|
|
@@ -813,11 +871,16 @@ export class GpuRenderer extends EventEmitter {
|
|
|
813
871
|
*/
|
|
814
872
|
async readImage(gpu, width, height, denoised) {
|
|
815
873
|
const accumulator = this.accumulator;
|
|
816
|
-
const {
|
|
874
|
+
const { toneMapping, vignette } = this.current;
|
|
875
|
+
const exposure = effectiveExposure(this.current);
|
|
817
876
|
const transparent = this.current.background.mode === "transparent";
|
|
818
877
|
// Resolved on the device, so the page only copies the bytes of the image.
|
|
819
878
|
this.imageResolve ??= new ImageResolvePass(gpu.device);
|
|
820
|
-
|
|
879
|
+
// The lens's effects are encoded on their own, ahead of the resolve, which reads the colour they leave.
|
|
880
|
+
const encoder = gpu.device.createCommandEncoder({ label: "lens" });
|
|
881
|
+
const graded = this.encodeLens(gpu, encoder, width, height, denoised);
|
|
882
|
+
gpu.device.queue.submit([encoder.finish()]);
|
|
883
|
+
const data = await this.imageResolve.read(accumulator.buffer, graded, width, height, { exposure, toneMapping, vignette, transparent });
|
|
821
884
|
return { width, height, data };
|
|
822
885
|
}
|
|
823
886
|
}
|
|
@@ -835,6 +898,9 @@ const SERIALIZABLE = new Set([
|
|
|
835
898
|
*/
|
|
836
899
|
async function serializeLive(scene) {
|
|
837
900
|
const renamed = new Map();
|
|
901
|
+
// The snapshot keeps a material's name but not its media, so the name carries a mark to them.
|
|
902
|
+
const named = new Map();
|
|
903
|
+
const media = [];
|
|
838
904
|
scene.traverse(object => {
|
|
839
905
|
const value = object.material;
|
|
840
906
|
for (const material of Array.isArray(value) ? value : value ? [value] : []) {
|
|
@@ -843,16 +909,54 @@ async function serializeLive(scene) {
|
|
|
843
909
|
renamed.set(material, material.type);
|
|
844
910
|
material.type = shader.isRawShaderMaterial ? "RawShaderMaterial" : "ShaderMaterial";
|
|
845
911
|
}
|
|
912
|
+
const data = material.userData?.cpuRenderer;
|
|
913
|
+
if (!named.has(material)
|
|
914
|
+
&& (subsurfaceMedium(data?.subsurface) || volumeMedium(data?.volume) || bevelRadius(data?.bevel) > 0)) {
|
|
915
|
+
named.set(material, material.name);
|
|
916
|
+
material.name = `${material.name}${MEDIA_MARK}${media.length}`;
|
|
917
|
+
media.push({ subsurface: data?.subsurface, volume: data?.volume, bevel: data?.bevel });
|
|
918
|
+
}
|
|
846
919
|
}
|
|
847
920
|
});
|
|
921
|
+
let snapshot;
|
|
848
922
|
try {
|
|
849
923
|
// The path tracer samples only the base level of a texture: the mip chain would be built and thrown away.
|
|
850
|
-
|
|
924
|
+
snapshot = (await serializeScene(scene, { mipmaps: false })).scene;
|
|
851
925
|
}
|
|
852
926
|
finally {
|
|
853
927
|
for (const [material, type] of renamed)
|
|
854
928
|
material.type = type;
|
|
929
|
+
for (const [material, name] of named)
|
|
930
|
+
material.name = name;
|
|
931
|
+
}
|
|
932
|
+
// Materials are shared between the meshes that use them, so each one is unmarked once and seen marked no more.
|
|
933
|
+
for (const mesh of snapshot.meshes) {
|
|
934
|
+
for (const material of mesh.materials) {
|
|
935
|
+
const at = material.name.lastIndexOf(MEDIA_MARK);
|
|
936
|
+
if (at < 0)
|
|
937
|
+
continue;
|
|
938
|
+
const medium = media[Number(material.name.slice(at + MEDIA_MARK.length))];
|
|
939
|
+
material.name = material.name.slice(0, at) || material.type;
|
|
940
|
+
if (medium.subsurface !== undefined)
|
|
941
|
+
material.subsurface = medium.subsurface;
|
|
942
|
+
if (medium.volume !== undefined)
|
|
943
|
+
material.volume = medium.volume;
|
|
944
|
+
if (medium.bevel !== undefined)
|
|
945
|
+
material.bevel = medium.bevel;
|
|
946
|
+
}
|
|
855
947
|
}
|
|
948
|
+
return snapshot;
|
|
949
|
+
}
|
|
950
|
+
/** Ends a material's name while it is serialized, followed by the index of its media. */
|
|
951
|
+
const MEDIA_MARK = "\u0000media:";
|
|
952
|
+
/**
|
|
953
|
+
* Everything that changes the finished image without tracing it again, as one string: the denoiser switch and what
|
|
954
|
+
* happens to the light between the radiance and the screen.
|
|
955
|
+
*/
|
|
956
|
+
function developing(settings) {
|
|
957
|
+
const { exposure, toneMapping, vignette, bloom, glare, lens, camera, depthOfField, globalIllumination } = settings;
|
|
958
|
+
return JSON.stringify([globalIllumination.denoise, exposure, toneMapping, vignette, bloom, glare,
|
|
959
|
+
lens.chromaticAberration, camera, camera.physicalExposure ? depthOfField.aperture : 0]);
|
|
856
960
|
}
|
|
857
961
|
/**
|
|
858
962
|
* The summed coefficients of every LightProbe the renderer would draw, times its intensity, as Three's WebGLLights sums
|