@meimu/mutracer 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +222 -0
- package/LICENSES/FidelityFX-FSR.txt +19 -0
- package/LICENSES/pbrt-v4-Apache-2.0.txt +202 -0
- package/THIRD_PARTY_NOTICES.md +18 -4
- package/dist/assets/bvh.worker.js +1 -1
- package/dist/mutracer.umd.js +6260 -5580
- package/docs/api.md +45 -18
- package/docs/materials.md +4 -2
- package/docs/performance.md +7 -0
- package/docs/post-processing.md +62 -9
- package/docs/progressive-rendering.md +3 -0
- package/docs/sampling.md +4 -0
- package/docs/technical/acceleration.md +52 -0
- package/docs/technical/aovs.md +79 -0
- package/docs/technical/caustics.md +109 -0
- package/docs/technical/continuous-spectrum.md +29 -0
- package/docs/technical/display-upscale.md +82 -0
- package/docs/technical/openpbr.md +99 -0
- package/docs/technical/pbrt-import.md +168 -0
- package/docs/technical/tiling.md +74 -0
- package/docs/technical/webgl.md +53 -0
- package/docs/viewer.md +11 -1
- package/lib/Display.d.ts +19 -5
- package/lib/Display.js +10 -7
- package/lib/Display.js.map +1 -1
- package/lib/Engine.d.ts +2 -1
- package/lib/Engine.js +30 -2
- package/lib/Engine.js.map +1 -1
- package/lib/Render.d.ts +20 -11
- package/lib/Render.js +32 -7
- package/lib/Render.js.map +1 -1
- package/lib/main.d.ts +3 -1
- package/lib/main.js +1 -0
- package/lib/main.js.map +1 -1
- package/lib/oidn.d.ts +1 -1
- package/lib/renderer/AovPrimitiveCache.js +39 -8
- package/lib/renderer/AovPrimitiveCache.js.map +1 -1
- package/lib/renderer/DisplayPostProcess.d.ts +8 -3
- package/lib/renderer/DisplayPostProcess.js +51 -18
- package/lib/renderer/DisplayPostProcess.js.map +1 -1
- package/lib/renderer/MaterialData.js +7 -2
- package/lib/renderer/MaterialData.js.map +1 -1
- package/lib/renderer/RenderingPipeline.d.ts +7 -1
- package/lib/renderer/RenderingPipeline.js.map +1 -1
- package/lib/renderer/TileRender.d.ts +2 -2
- package/lib/renderer/TileRender.js +128 -7
- package/lib/renderer/TileRender.js.map +1 -1
- package/lib/renderer/WGPUAov.d.ts +6 -1
- package/lib/renderer/WGPUAov.js +108 -14
- package/lib/renderer/WGPUAov.js.map +1 -1
- package/lib/renderer/WGPUCanvasSurface.js +12 -1
- package/lib/renderer/WGPUCanvasSurface.js.map +1 -1
- package/lib/renderer/WGPUEnvMapDistribution.js +19 -19
- package/lib/renderer/WGPUFullQuadPass.js +3 -3
- package/lib/renderer/WGPURayTraceOutput.js +12 -12
- package/lib/renderer/WGPURayTracePass.d.ts +17 -4
- package/lib/renderer/WGPURayTracePass.js +194 -71
- package/lib/renderer/WGPURayTracePass.js.map +1 -1
- package/lib/renderer/WGPURenderingPipeline.js +46 -40
- package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLAov.js +3 -3
- package/lib/renderer/WebGLAov.js.map +1 -1
- package/lib/renderer/WebGLFullQuadPass.d.ts +1 -1
- package/lib/renderer/WebGLFullQuadPass.js +8 -2
- package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
- package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
- package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
- package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
- package/lib/renderer/WebGLRayTracePass.d.ts +14 -10
- package/lib/renderer/WebGLRayTracePass.js +115 -111
- package/lib/renderer/WebGLRayTracePass.js.map +1 -1
- package/lib/renderer/WebGLRenderingPipeline.js +10 -3
- package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLSkyBaker.js +57 -57
- package/lib/renderer/aov.d.ts +13 -1
- package/lib/renderer/aov.js +21 -2
- package/lib/renderer/aov.js.map +1 -1
- package/lib/renderer/aovDisplay.js +2 -2
- package/lib/renderer/aovDisplay.js.map +1 -1
- package/lib/renderer/binnedSahBvh.d.ts +2 -1
- package/lib/renderer/binnedSahBvh.js +24 -17
- package/lib/renderer/binnedSahBvh.js.map +1 -1
- package/lib/renderer/bvhAccel.d.ts +3 -1
- package/lib/renderer/bvhAccel.js +36 -6
- package/lib/renderer/bvhAccel.js.map +1 -1
- package/lib/renderer/cameraUniform.d.ts +1 -1
- package/lib/renderer/cameraUniform.js +6 -2
- package/lib/renderer/cameraUniform.js.map +1 -1
- package/lib/renderer/compactVertices.d.ts +14 -0
- package/lib/renderer/compactVertices.js +124 -0
- package/lib/renderer/compactVertices.js.map +1 -0
- package/lib/renderer/easu.d.ts +11 -0
- package/lib/renderer/easu.js +156 -0
- package/lib/renderer/easu.js.map +1 -0
- package/lib/renderer/geometryUpdateState.d.ts +1 -0
- package/lib/renderer/geometryUpdateState.js.map +1 -1
- package/lib/renderer/geometryUpdates.js +3 -2
- package/lib/renderer/geometryUpdates.js.map +1 -1
- package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
- package/lib/renderer/glsl/aovReflectance.glsl.js +35 -35
- package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
- package/lib/renderer/glsl/aovTrace.frag.js +44 -36
- package/lib/renderer/glsl/aovTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.js +16 -0
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/cameraRay.glsl.d.ts +1 -1
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -16
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +8 -8
- package/lib/renderer/glsl/chunks/envMap.glsl.js +67 -67
- package/lib/renderer/glsl/chunks/intersect.glsl.js +390 -375
- package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +120 -120
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +562 -562
- package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
- package/lib/renderer/glsl/chunks/random.glsl.js +4 -4
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +37 -35
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js +70 -74
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -1
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +107 -88
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +11 -11
- package/lib/renderer/glsl/chunks/sampling.glsl.js +77 -77
- package/lib/renderer/glsl/chunks/sobol.glsl.js +70 -70
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.d.ts +6 -0
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js +47 -0
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
- package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
- package/lib/renderer/glsl/depthQuery.frag.js +12 -6
- package/lib/renderer/glsl/depthQuery.frag.js.map +1 -1
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
- package/lib/renderer/glsl/rayTrace.frag.js +233 -170
- package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/shadowCatcher.frag.js +10 -9
- package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
- package/lib/renderer/glsl/webglPipeline.frag.js +58 -58
- package/lib/renderer/gpuMemory.js +1 -1
- package/lib/renderer/gpuMemory.js.map +1 -1
- package/lib/renderer/openPbrEnergyLut.d.ts +2 -1
- package/lib/renderer/openPbrEnergyLut.js +18 -1
- package/lib/renderer/openPbrEnergyLut.js.map +1 -1
- package/lib/renderer/pathLimits.d.ts +5 -4
- package/lib/renderer/pathLimits.js +6 -5
- package/lib/renderer/pathLimits.js.map +1 -1
- package/lib/renderer/prepareMeshBVH.d.ts +2 -0
- package/lib/renderer/prepareMeshBVH.js +5 -3
- package/lib/renderer/prepareMeshBVH.js.map +1 -1
- package/lib/renderer/progressiveScheduler.js +1 -1
- package/lib/renderer/progressiveScheduler.js.map +1 -1
- package/lib/renderer/renderPipeline.d.ts +4 -0
- package/lib/renderer/renderPipeline.js +1 -0
- package/lib/renderer/renderPipeline.js.map +1 -1
- package/lib/renderer/researchTransport.d.ts +1 -1
- package/lib/renderer/researchTransport.js.map +1 -1
- package/lib/renderer/sceneAssembly.d.ts +1 -1
- package/lib/renderer/sceneAssembly.js +4 -3
- package/lib/renderer/sceneAssembly.js.map +1 -1
- package/lib/renderer/sceneChangeDetector.d.ts +1 -1
- package/lib/renderer/sceneChangeDetector.js +3 -1
- package/lib/renderer/sceneChangeDetector.js.map +1 -1
- package/lib/renderer/sceneLayoutSchema.d.ts +1 -0
- package/lib/renderer/sceneLayoutSchema.js +2 -2
- package/lib/renderer/sceneLayoutSchema.js.map +1 -1
- package/lib/renderer/scenePreparation.d.ts +3 -2
- package/lib/renderer/scenePreparation.js +18 -2
- package/lib/renderer/scenePreparation.js.map +1 -1
- package/lib/renderer/scratchSampling.js +6 -6
- package/lib/renderer/spectrum.js +2 -2
- package/lib/renderer/staticBvhPreparation.d.ts +9 -0
- package/lib/renderer/staticBvhPreparation.js +8 -2
- package/lib/renderer/staticBvhPreparation.js.map +1 -1
- package/lib/renderer/surfaceHit.d.ts +10 -0
- package/lib/renderer/surfaceHit.js +22 -0
- package/lib/renderer/surfaceHit.js.map +1 -0
- package/lib/renderer/tangentRequirements.d.ts +2 -0
- package/lib/renderer/tangentRequirements.js +7 -0
- package/lib/renderer/tangentRequirements.js.map +1 -0
- package/lib/renderer/textureAtlas.d.ts +4 -0
- package/lib/renderer/textureAtlas.js +48 -2
- package/lib/renderer/textureAtlas.js.map +1 -1
- package/lib/renderer/webgl.js +4 -0
- package/lib/renderer/webgl.js.map +1 -1
- package/lib/renderer/webglVertexAttributes.d.ts +17 -0
- package/lib/renderer/webglVertexAttributes.js +44 -0
- package/lib/renderer/webglVertexAttributes.js.map +1 -0
- package/lib/renderer/wgpuBindlessSource.js +2 -2
- package/lib/renderer/wgpuMaterialConstants.js +4 -3
- package/lib/renderer/wgpuMaterialConstants.js.map +1 -1
- package/lib/renderer/wgpuSceneUniform.js +2 -2
- package/lib/renderer/wgpuSceneUniform.js.map +1 -1
- package/lib/renderer/wgpuShaderSource.d.ts +15 -0
- package/lib/renderer/wgpuShaderSource.js +1 -1
- package/lib/renderer/wgpuShaderSource.js.map +1 -1
- package/lib/renderer/wgsl/aovCompact.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/aovCompact.wgsl.js +26 -0
- package/lib/renderer/wgsl/aovCompact.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
- package/lib/renderer/wgsl/aovReflectance.wgsl.js +39 -39
- package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
- package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/aovResolve.wgsl.js +21 -2
- package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js +2 -2
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/aovTrace.wgsl.js +31 -31
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js +56 -0
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
- package/lib/renderer/wgsl/causticLight.compute.d.ts +1 -1
- package/lib/renderer/wgsl/causticLight.compute.js +121 -119
- package/lib/renderer/wgsl/causticLight.compute.js.map +1 -1
- package/lib/renderer/wgsl/chunks/background.wgsl.js +46 -46
- package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +4 -4
- package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/caustics.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js +30 -30
- package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +6 -2
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js +550 -542
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +18 -16
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +2 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +70 -69
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +593 -593
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +118 -118
- package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +4 -1
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +32 -26
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +114 -114
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +159 -137
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +8 -8
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js +74 -74
- package/lib/renderer/wgsl/chunks/sobol.wgsl.js +74 -74
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.d.ts +6 -0
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js +66 -0
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js +61 -0
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.js +99 -97
- package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
- package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/depthQuery.wgsl.js +11 -2
- package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/easu.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/easu.wgsl.js +80 -0
- package/lib/renderer/wgsl/easu.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.d.ts +21 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.js +230 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/jnlm.compute.js +74 -74
- package/lib/renderer/wgsl/jnlm.compute.js.map +1 -1
- package/lib/renderer/wgsl/offlineAdaptive.compute.js +26 -26
- package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
- package/lib/renderer/wgsl/photonMap.compute.js +89 -89
- package/lib/renderer/wgsl/proceduralSky.compute.js +61 -61
- package/lib/renderer/wgsl/rayTrace.compute.d.ts +14 -0
- package/lib/renderer/wgsl/rayTrace.compute.js +395 -333
- package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
- package/lib/scene/Scene.js.map +1 -1
- package/lib/settings/render.d.ts +11 -0
- package/lib/settings/render.js +1 -0
- package/lib/settings/render.js.map +1 -1
- package/lib/util/fromTHREE.js +21 -14
- package/lib/util/fromTHREE.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +5 -2
- package/lib/oidnBundledWeights.cdn.d.ts +0 -2
- package/lib/oidnBundledWeights.cdn.js +0 -5
- package/lib/oidnBundledWeights.cdn.js.map +0 -1
- package/lib/renderer/bvh.worker.d.ts +0 -1
- package/lib/renderer/bvh.worker.js +0 -16
- package/lib/renderer/bvh.worker.js.map +0 -1
- package/lib/renderer/bvhWorkerBuild.d.ts +0 -13
- package/lib/renderer/bvhWorkerBuild.js +0 -17
- package/lib/renderer/bvhWorkerBuild.js.map +0 -1
- package/lib/renderer/lightCore.d.ts +0 -12
- package/lib/renderer/lightCore.js +0 -13
- package/lib/renderer/lightCore.js.map +0 -1
- package/lib/renderer/materialCore.d.ts +0 -8
- package/lib/renderer/materialCore.js +0 -9
- package/lib/renderer/materialCore.js.map +0 -1
- package/lib/scene/PixelTexture.d.ts +0 -6
- package/lib/scene/PixelTexture.js +0 -10
- package/lib/scene/PixelTexture.js.map +0 -1
- package/lib/util/studioLighting.d.ts +0 -18
- package/lib/util/studioLighting.js +0 -36
- package/lib/util/studioLighting.js.map +0 -1
package/docs/api.md
CHANGED
|
@@ -127,6 +127,7 @@ other sequences retain their completed samples.
|
|
|
127
127
|
| Option | Default | Meaning |
|
|
128
128
|
| --- | --- | --- |
|
|
129
129
|
| `maxSamples` | `2048` | Complete sample budget |
|
|
130
|
+
| `aovResolution` | `'render'` | `'display'` traces AOVs at canvas size on WebGPU, capped at 4 samples regardless of `aovSamples`; requires a scale-based render. WebGL falls back with one warning |
|
|
130
131
|
| `aovs` / `aovSamples` | `[]` / `16` | Optional [surface outputs](#surface-outputs) / independent positive integer sample cap |
|
|
131
132
|
| `bounces` / `clamping` | `3` / `0` | Scattering depth / per-sample radiance clamp; 0 disables clamping |
|
|
132
133
|
| `samplingPattern` | `'sobol'` | Sobol, ZSobol or random; see [sampling](./sampling.md) |
|
|
@@ -144,8 +145,9 @@ other sequences retain their completed samples.
|
|
|
144
145
|
| `fallback` | `null` | Single-level Render on the same engine |
|
|
145
146
|
| `denoiser` | `null` | Per-render configuration; read back through the frozen `denoiser` getter and change with `setDenoiser()`; see [denoising](./denoising.md) |
|
|
146
147
|
|
|
147
|
-
`bounces` is rounded and clamped to [1,
|
|
148
|
-
Paths allow at most `min(bounces * 3,
|
|
148
|
+
`bounces` is rounded and clamped to [1, 50] on WebGPU or [1, 20] on WebGL;
|
|
149
|
+
NaN becomes 1. Paths allow at most `min(bounces * 3, 50)` events on WebGPU
|
|
150
|
+
or `min(bounces * 3, 20)` on WebGL, including transmission,
|
|
149
151
|
alpha skips and escape checks. Opaque paths also terminate at their scattering
|
|
150
152
|
limit. The event budget can truncate deep transparent paths before the requested
|
|
151
153
|
scattering depth. On Intel Mac WebGL, the event limit is `min(bounces, 3)`, doubled
|
|
@@ -350,9 +352,20 @@ const depth = await render.readPixels('depth'); // Float32Array, RGBA
|
|
|
350
352
|
const ids = await render.readPixels('id'); // Uint32Array, RGBA
|
|
351
353
|
```
|
|
352
354
|
|
|
353
|
-
You can change `render.aovs` or `render.
|
|
355
|
+
You can change `render.aovs`, `render.aovSamples` or `render.aovResolution` after sampling. Continue
|
|
354
356
|
calling `refine()` to regenerate AOVs for the current view; beauty samples and
|
|
355
|
-
completed denoising are preserved. AOV accumulation restarts when
|
|
357
|
+
completed denoising are preserved. AOV accumulation restarts when any of them changes.
|
|
358
|
+
|
|
359
|
+
To keep beauty at reduced resolution while reading or displaying full-resolution
|
|
360
|
+
surface outputs, set `aovResolution: 'display'` on a scale-based render. The
|
|
361
|
+
default is `'render'`. AOV readbacks and visualization use their own dimensions;
|
|
362
|
+
beauty and denoiser guides keep the render dimensions. Both modes stop at
|
|
363
|
+
`min(samples, aovSamples)`; display mode also caps at 4, follows canvas resizes,
|
|
364
|
+
and rejects fixed-size renders. During tracing, display mode starts after the first
|
|
365
|
+
beauty sample and adds one AOV sample per frame; the frame that reaches
|
|
366
|
+
`maxSamples` completes the rest. WebGL falls back to render dimensions and warns
|
|
367
|
+
once per render. Each kind has the same meaning in both modes.
|
|
368
|
+
Custom denoiser AOV inputs require `'render'` resolution.
|
|
356
369
|
|
|
357
370
|
| Kind | RGBA contents |
|
|
358
371
|
| --- | --- |
|
|
@@ -361,13 +374,14 @@ completed denoising are preserved. AOV accumulation restarts when either changes
|
|
|
361
374
|
| `roughness` | Specular roughness, metalness, unsupported-reflectance fraction, coverage |
|
|
362
375
|
| `diffuseAlbedo` | Directional-hemispherical diffuse reflectance RGB, valid coverage |
|
|
363
376
|
| `specularAlbedo` | Directional-hemispherical specular reflectance RGB, valid coverage |
|
|
377
|
+
| `diffuseColor` | Diffuse texture color: base weight × base color × (1 − metalness), tinted by coat color; valid coverage |
|
|
378
|
+
| `specularColor` | Specular texture color: metal base color plus dielectric specular color × F0, tinted by coat color; valid coverage |
|
|
364
379
|
| `id` | Object, local instance (0 for ordinary meshes), material, source triangle index; background is `0xFFFFFFFF` in all channels |
|
|
365
380
|
| `motion` | Previous position minus current position in pixels, x right and y down; z = 0, alpha = 3 for valid history or 0 otherwise |
|
|
366
381
|
|
|
367
|
-
Depth, position, roughness and
|
|
368
|
-
rays, including depth of field
|
|
369
|
-
|
|
370
|
-
uses only supported hits for both normalization and valid coverage. A blank pixel
|
|
382
|
+
Depth, position, roughness, reflectance and color average independent jittered primary
|
|
383
|
+
rays, including depth of field. RGB values use hit-count normalization; alpha is hit coverage over all AOV samples. Reflectance
|
|
384
|
+
and color use only supported hits for both normalization and valid coverage. A blank pixel
|
|
371
385
|
is zero. These passes preserve beauty samples but do not sample the same paths.
|
|
372
386
|
Alpha holes use the first surface with alpha ≥ 0.5, skipping shadow catchers,
|
|
373
387
|
with at most 32 layers.
|
|
@@ -392,14 +406,23 @@ Reflectance outputs are separate from the existing OIDN `albedo` guide.
|
|
|
392
406
|
Coat, fuzz, anisotropy, subsurface/volume scattering, bevel, thin film,
|
|
393
407
|
dispersion, partial alpha and nonstandard materials are unsupported by this
|
|
394
408
|
reflectance estimate. Such hits contribute to `roughness.b` and have zero
|
|
395
|
-
reflectance validity. Reflectance
|
|
396
|
-
|
|
409
|
+
reflectance validity. Reflectance tracing can be expensive; request it only when needed.
|
|
410
|
+
|
|
411
|
+
`diffuseColor` and `specularColor` read resolved material inputs without
|
|
412
|
+
integrating the BSDF, so they are cheap. They support coat, fuzz and anisotropic
|
|
413
|
+
surfaces; transmission, partial alpha, media and nonstandard materials have zero
|
|
414
|
+
color validity. A render can request `diffuseAlbedo` or `diffuseColor`, not both;
|
|
415
|
+
the same applies to `specularAlbedo` and `specularColor`.
|
|
397
416
|
|
|
398
417
|
Reading a kind absent from `render.aovs` rejects. A custom denoiser can request
|
|
399
418
|
its own [AOV inputs](./denoising.md#custom-denoisers). With neither request there
|
|
400
|
-
are no AOV allocations or passes. Enabling any kind costs about 128 GPU bytes
|
|
401
|
-
per pixel on WebGPU or 192 on WebGL, plus scene identity/history data
|
|
402
|
-
|
|
419
|
+
are no AOV allocations or passes. Enabling any kind normally costs about 128 GPU bytes
|
|
420
|
+
per AOV pixel on WebGPU or 192 on WebGL, plus scene identity/history data.
|
|
421
|
+
WebGPU display mode requesting only `depth`, `diffuseColor` and/or `specularColor` costs
|
|
422
|
+
24 bytes per pixel plus small scene metadata; borrowing all three GPU textures
|
|
423
|
+
adds another 24 bytes per pixel (about 288 MB total at 6 MP). Its color
|
|
424
|
+
accumulation has half precision. Other AOV selections use the full allocation;
|
|
425
|
+
each custom denoiser AOV snapshot adds 16 bytes per pixel. A render may retain one
|
|
403
426
|
reusable snapshot per kind between denoising calls. Readback adds a CPU copy.
|
|
404
427
|
WebGPU dimensions remain subject to device buffer limits. A full-frame AOV
|
|
405
428
|
sample runs independently of tile/adaptive sampling and may exceed the render's
|
|
@@ -421,7 +444,7 @@ const png = await engine.display.toBlob(render);
|
|
|
421
444
|
| `depth` | Black at the near depth, white at the far depth, clamped outside the range |
|
|
422
445
|
| `position` | World xyz mapped to RGB; origin is 0.5 and ±position scale maps to 0/1 |
|
|
423
446
|
| `roughness` | RGB = roughness, metalness, unsupported-reflectance fraction |
|
|
424
|
-
| `diffuseAlbedo`, `specularAlbedo` | Linear
|
|
447
|
+
| `diffuseAlbedo`, `specularAlbedo`, `diffuseColor`, `specularColor` | Linear RGB clamped to [0, 1], then sRGB encoded |
|
|
425
448
|
| `id` | Stable pseudocolor for the selected uint32 ID component; colors can collide |
|
|
426
449
|
| `motion` | Direction as hue (+x is red, +y is yellow-green), displacement/scale as brightness |
|
|
427
450
|
|
|
@@ -598,10 +621,14 @@ see [denoising](./denoising.md#custom-oidn-networks). The main entry exports
|
|
|
598
621
|
## GPU output and display passes
|
|
599
622
|
|
|
600
623
|
`render.getOutputTexture(kind)` borrows native HDR or the latest display image;
|
|
601
|
-
`
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
624
|
+
`render.getAovTexture('diffuseColor' | 'specularColor' | 'depth')` borrows raw
|
|
625
|
+
linear AOV textures at their own resolution after sampling; WebGL returns undefined.
|
|
626
|
+
`display.addPostProcess(pass, options?)` returns unregister and runs on every present/export.
|
|
627
|
+
Both are WebGPU-only. `options.outputSize` defaults to preserving input dimensions;
|
|
628
|
+
the final display texture and export can differ from the render size. Fixed renders
|
|
629
|
+
are cropped to their requested rectangle before export passes. HDR textures can
|
|
630
|
+
include extra pixels around a fixed render's requested image. See
|
|
631
|
+
[formats, lifecycle, EASU upscale and overlay examples](./post-processing.md).
|
|
605
632
|
|
|
606
633
|
Anisotropy direction options: `anisotropyMap` (default `undefined`) reads linear RG as a tangent direction and B as a multiplier for base specular strength. `specularAnisotropyRotation` (default `0`) rotates that direction counter-clockwise in radians; `coatAnisotropyRotation` (default `0`) rotates the coat relative to the geometry tangent. See [materials](./materials.md#anisotropy-directions) for frame and fallback conventions.
|
|
607
634
|
|
package/docs/materials.md
CHANGED
|
@@ -51,12 +51,14 @@ the textures they reference still share atlas space.
|
|
|
51
51
|
|
|
52
52
|
Units: `transmissionDepth` and `subsurfaceRadius` are in scene units;
|
|
53
53
|
`thinFilmThickness` is in micrometres (`0.45` = 450 nm).
|
|
54
|
+
Subsurface materials with short scattering radii may appear darker than in earlier releases.
|
|
54
55
|
|
|
55
56
|
`baseWeight` scales diffuse reflection and the metallic normal-incidence color
|
|
56
57
|
(`baseWeight * baseColor`). Dielectric specular, transmission and subsurface
|
|
57
58
|
retain their own strengths. For metals, `specularColor` tints the F82 Fresnel
|
|
58
59
|
curve near grazing angles and `specularWeight` scales the entire reflection,
|
|
59
60
|
including thin-film reflection. At their default values, F82 reduces to Schlick.
|
|
61
|
+
Low-roughness metals may appear slightly darker under broad lighting than in earlier releases.
|
|
60
62
|
|
|
61
63
|
Native `specularRoughnessAnisotropy` and `coatRoughnessAnisotropy` use the OpenPBR GGX mapping:
|
|
62
64
|
`alphaT = roughness² * sqrt(2 / (1 + (1 - anisotropy)²))` and
|
|
@@ -129,7 +131,7 @@ an alternate serialization format.
|
|
|
129
131
|
| --- | --- | --- |
|
|
130
132
|
| `map` | RGB (sRGB), A | Multiplies `baseColor`; alpha use set by `mapAlphaUsage` |
|
|
131
133
|
| `alphaMap` | G | Opacity, as in Three.js |
|
|
132
|
-
| `normalMap`, `normalScale` | RGB | Tangent space;
|
|
134
|
+
| `normalMap`, `normalScale` | RGB | Tangent space; uses triangle UV derivatives |
|
|
133
135
|
| `metallicRoughnessMap` | G = roughness, B = metalness | glTF convention |
|
|
134
136
|
| `roughnessMap` | G | |
|
|
135
137
|
| `metalnessMap` | B | |
|
|
@@ -288,6 +290,6 @@ Set `specularAnisotropyRotation` or provide `anisotropyMap` to orient the base s
|
|
|
288
290
|
|
|
289
291
|
`coatAnisotropyRotation` defaults to zero and uses the geometry tangent independently of the base map. Base and coat use their respective directions and [normals](#coat-normals). Zero anisotropy strength ignores the direction.
|
|
290
292
|
|
|
291
|
-
Provided tangent XYZ and optional W handedness are preserved. For XYZ tangents the sign comes from triangle UV derivatives. Missing or degenerate tangents use UV derivatives and then a stable orthonormal fallback
|
|
293
|
+
Provided tangent XYZ and optional W handedness are preserved. Missing tangents are generated from primary UVs only when a material using the geometry needs anisotropy or an active coat normal map; adding such a material prepares them automatically. For XYZ tangents the sign comes from triangle UV derivatives. Missing UVs or degenerate tangents use UV derivatives where available and then a stable orthonormal fallback. The direction texture's selected UV set is used for derivative fallback, including UV1. A provided XYZW tangent remains authoritative. Directions are reorthogonalized against the final shading normal, including normal maps and back faces, and instance transforms preserve mirrored handedness. UV scale, offset and flipY affect texel lookup; they do not rotate the encoded direction.
|
|
292
294
|
|
|
293
295
|
The direction and strength inputs use native OpenPBR semantics by default. For imported glTF/Three.js strength, select `specularAnisotropyModel: 'gltf'`; the same roughness and strength properties then retain source values. Source scalar inputs are clamped to [0, 1] before texture factors; non-finite source roughness/strength fall back to 0.3/0. Native scalar handling is unchanged. Zero source strength preserves the original roughness path. The conversion matches the GGX alpha axes before existing minimum-alpha clamping; Fresnel, masking, multiple scattering and OpenPBR coating remain the library's model. See [the conversion rules](./threejs.md#anisotropy-source-conversion).
|
package/docs/performance.md
CHANGED
|
@@ -38,6 +38,13 @@ A tuning checklist. Each item links to the page with the details.
|
|
|
38
38
|
- Textures share an atlas bounded by `textureAtlasBudgetBytes`; larger textures
|
|
39
39
|
are downscaled. Check `engine.getDiagnostics()?.textureAtlas`.
|
|
40
40
|
|
|
41
|
+
WebGPU quantizes vertex normal and tangent directions; scenes with displacement
|
|
42
|
+
retain full normal precision. Vertex RGB values in
|
|
43
|
+
`[0, 1]` have at most `1/510` absolute error per channel; scenes containing
|
|
44
|
+
negative or HDR vertex colors retain float32 RGB instead. Positions and UV
|
|
45
|
+
coordinates retain float32 precision. Large scenes still depend on the device's
|
|
46
|
+
buffer limits and the browser's available CPU memory.
|
|
47
|
+
|
|
41
48
|
## Animation and editing
|
|
42
49
|
|
|
43
50
|
See [scene updates](./updates.md) for the cost of each kind of edit.
|
package/docs/post-processing.md
CHANGED
|
@@ -18,8 +18,9 @@ remove(); // Safe to call again.
|
|
|
18
18
|
|
|
19
19
|
Passes run in registration order on every `present()` and `toBlob()`, after
|
|
20
20
|
composition and denoising. They receive the selected complete render, including
|
|
21
|
-
fallbacks, at its actual dimensions. Export uses the same chain without
|
|
22
|
-
|
|
21
|
+
fallbacks, at its actual dimensions. Export uses the same chain without changing
|
|
22
|
+
the display canvas; fixed-size renders are cropped to their requested size before
|
|
23
|
+
entering the chain. `readPixels()` never runs these passes.
|
|
23
24
|
|
|
24
25
|
For a complete overlay implementation, see
|
|
25
26
|
[`createCrosshairPass`](../examples/shared/crosshairPass.ts). It loads the input
|
|
@@ -35,12 +36,55 @@ A changing overlay can read application state in its callback. `RenderLoop`
|
|
|
35
36
|
stops presenting after convergence, so explicitly call `display.present(final)`
|
|
36
37
|
when that state changes. This refreshes the overlay without tracing more samples.
|
|
37
38
|
|
|
39
|
+
For edge-adaptive enlargement without sharpening:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import {createEasuPass} from '@meimu/mutracer';
|
|
43
|
+
const pass = createEasuPass();
|
|
44
|
+
const removeUpscale = engine.display.addPostProcess(pass, {
|
|
45
|
+
outputSize: (_, display) => display
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Register the upscale before overlays that should stay at canvas resolution. An
|
|
50
|
+
input that already has the output size is copied unchanged and a larger one is
|
|
51
|
+
area-averaged, so one registration can serve a full-resolution or supersampled
|
|
52
|
+
final render and a reduced-resolution preview.
|
|
53
|
+
|
|
54
|
+
To recover texture detail, enable `diffuseColor`, `specularColor` and `depth`
|
|
55
|
+
on a scale-based render with `aovResolution: 'display'`, and create the pass with
|
|
56
|
+
`createEasuPass({albedoDetail: true})`. Keep beauty at the desired reduced
|
|
57
|
+
`resolutionScale`. Unregister the pass, then call `pass.dispose()` when finished
|
|
58
|
+
to release its scratch images.
|
|
59
|
+
|
|
60
|
+
EASU works on display-encoded RGB after tone mapping, including extended-range
|
|
61
|
+
output, and preserves alpha. EASU alone cannot recover missing texture detail.
|
|
62
|
+
Albedo compensation recovers supported surface texture detail but cannot recover
|
|
63
|
+
reflection, refraction or geometric detail. It maps the displayed image back
|
|
64
|
+
through the display transform, estimates locally how much radiance follows albedo,
|
|
65
|
+
and changes only that part, so specular highlights mostly keep their brightness.
|
|
66
|
+
Clipped highlights cannot be recovered. Transmission, cutouts, background, low
|
|
67
|
+
coverage and depth boundaries receive EASU alone. With detail, a present costs about
|
|
68
|
+
2.6 ms at 6 MP on an Apple M4 Max, compared with about 0.5 ms for EASU alone.
|
|
69
|
+
|
|
38
70
|
## Options and image semantics
|
|
39
71
|
|
|
40
72
|
`getOutputTexture(kind)` requires `'hdr'` or `'display'`; both return undefined
|
|
41
73
|
on WebGL, before a complete sample or after disposal. There are no passes by
|
|
42
74
|
default. `addPostProcess(pass)` returns an idempotent unregister function.
|
|
43
|
-
`PostProcess` and `
|
|
75
|
+
`PostProcess`, `PostProcessContext` and `PostProcessOptions` are exported types.
|
|
76
|
+
|
|
77
|
+
Use `addPostProcess(pass, {outputSize: (input, display) => display})` to output
|
|
78
|
+
at canvas resolution. The default preserves the input dimensions. Each callback
|
|
79
|
+
receives the previous pass's dimensions and the current canvas dimensions, also
|
|
80
|
+
for `toBlob()`. A chain can change size more than once. Return positive integer
|
|
81
|
+
width and height within `device.limits.maxTextureDimension2D`; invalid dimensions
|
|
82
|
+
discard the whole chain and emit an engine error, as callback exceptions do.
|
|
83
|
+
|
|
84
|
+
`ctx.width` and `ctx.height` remain the actual render dimensions. Read
|
|
85
|
+
`ctx.input.width/height` and `ctx.output.width/height` for the pass dimensions.
|
|
86
|
+
`toBlob()` exports the final chain dimensions; `getOutputTexture('display')`
|
|
87
|
+
borrows that actual-sized image, which may differ from the render size.
|
|
44
88
|
|
|
45
89
|
| Image | Meaning |
|
|
46
90
|
| --- | --- |
|
|
@@ -59,6 +103,21 @@ by primary-hit coverage for partially hit pixels, restoring the per-sample
|
|
|
59
103
|
average. Thus that CPU readback can differ from the borrowed native HDR texture.
|
|
60
104
|
See [custom denoiser image semantics](./denoising.md#custom-denoisers).
|
|
61
105
|
|
|
106
|
+
`createEasuPass()` defaults to EASU alone. `albedoDetail` defaults to `false`.
|
|
107
|
+
When the displayed render lacks those AOVs or display resolution, the pass warns
|
|
108
|
+
once and upscales without detail; frames whose AOVs are not ready yet or differ
|
|
109
|
+
from the output size also use EASU alone. The optional AOVs add tracing and
|
|
110
|
+
memory cost; see [surface outputs](./api.md#surface-outputs).
|
|
111
|
+
|
|
112
|
+
`render.getAovTexture(kind)` borrows enabled `diffuseColor`, `specularColor` or
|
|
113
|
+
`depth` outputs after an AOV sample completes, only on WebGPU. Colors use
|
|
114
|
+
`rgba8unorm-srgb`, which loads as linear values in [0, 1], with valid coverage in
|
|
115
|
+
alpha; depth uses `rg32float`, with
|
|
116
|
+
camera-forward depth in red and hit coverage in green. These raw textures follow
|
|
117
|
+
the same borrowing lifetime as `getOutputTexture()` and have the AOV dimensions.
|
|
118
|
+
Each is resolved from the accumulation when its samples change, and the first
|
|
119
|
+
call for a kind also creates its pipeline.
|
|
120
|
+
|
|
62
121
|
## Caveats
|
|
63
122
|
|
|
64
123
|
Textures are borrowed and read-only. Do not retain, write or destroy returned
|
|
@@ -79,9 +138,3 @@ discards the chain's recorded commands, displays the original composed image
|
|
|
79
138
|
and emits the engine `error` event. GPU validation errors remain WebGPU errors;
|
|
80
139
|
the callback must record valid commands.
|
|
81
140
|
|
|
82
|
-
## Implementation notes
|
|
83
|
-
|
|
84
|
-
The composed image is kept separately, so a thrown callback cannot leave a
|
|
85
|
-
partly processed result.
|
|
86
|
-
Display passes do not enter denoiser inputs, change samples or invalidate cached
|
|
87
|
-
filter results. HDR-stage callbacks are outside this API.
|
|
@@ -146,6 +146,9 @@ camera edits discard an unfinished sample and restart against the new inputs.
|
|
|
146
146
|
`maxTiles` caps the sample's tile grid (rounded up to a rectangular grid), so a
|
|
147
147
|
smaller value makes larger tiles. It does not cap work per frame or per call;
|
|
148
148
|
use `timeBudgetMs` and the between-frame deadline to control queued work.
|
|
149
|
+
With GPU timing available, WebGPU can keep tiles above `timeBudgetMs` when the
|
|
150
|
+
budget cannot be reached or further subdivision brings little speedup. This limits
|
|
151
|
+
extra offline rendering cost while allowing longer pauses between updates.
|
|
149
152
|
|
|
150
153
|
## Reading and exporting
|
|
151
154
|
|
package/docs/sampling.md
CHANGED
|
@@ -23,6 +23,10 @@ render.samplingPattern = 'zsobol';
|
|
|
23
23
|
`sampleSequenceOffset`. Use disjoint offset ranges for animation frames.
|
|
24
24
|
- **Backends**: WebGPU and WebGL 2 can differ in floating-point rounding even
|
|
25
25
|
with identical sequence points.
|
|
26
|
+
- **Dispersion**: on WebGPU, `dispersionWavelengths: 3` with
|
|
27
|
+
`directLightCandidates > 1` can need more samples in individual RGB channels
|
|
28
|
+
under strongly colored lighting and materials. Lower overall noise does not
|
|
29
|
+
guarantee lower noise in every channel.
|
|
26
30
|
- **Fireflies**: very narrow specular lobes under directional lights can
|
|
27
31
|
produce rare, large contributions with any pattern. Sampling does not clamp
|
|
28
32
|
them; use `render.clamping` if needed.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Acceleration structures
|
|
2
|
+
|
|
3
|
+
The renderer traces a two-level hierarchy: one bottom-level BVH (BLAS) per geometry
|
|
4
|
+
and a top-level BVH (TLAS) over mesh instances. Builders, layouts and preparation
|
|
5
|
+
are documented in the [BVH guide](../bvh.md); this note records the choices behind
|
|
6
|
+
the defaults and the alternatives that were measured. The code is
|
|
7
|
+
`src/renderer/bvhAccel.ts` and `binnedSahBvh.ts`.
|
|
8
|
+
|
|
9
|
+
## TLAS
|
|
10
|
+
|
|
11
|
+
- **Builder.** The TLAS always uses the built-in binned SAH builder, a JavaScript
|
|
12
|
+
port of TinyBVH's `BVH::Build`, built and refitted on the calling thread.
|
|
13
|
+
- **Bins.** The web TLAS uses 64 SAH bins (`WEB_TLAS_BINS`); native keeps 8. More
|
|
14
|
+
bins separate overlapping static instances in scenes with many instances.
|
|
15
|
+
Higher instance costs, exact SAH and forced fallbacks were compared and not
|
|
16
|
+
adopted. The rebuilt tree can pick a different object at coincident faces, which
|
|
17
|
+
changes `id` AOVs there; other AOVs matched, and HDR differed only by rounding.
|
|
18
|
+
- **Instance bounds.** Each instance's world bounds, padded by displacement, are
|
|
19
|
+
stored after the TLAS. Leaf traversal tests them before transforming the ray
|
|
20
|
+
into the BLAS's space, so a ray that misses an instance skips the transform and
|
|
21
|
+
the BLAS root test. Both web backends and the caustic kernel use them.
|
|
22
|
+
|
|
23
|
+
## BLAS
|
|
24
|
+
|
|
25
|
+
- **Defaults.** The BVH2 layout with spatial splits off stays the default after a
|
|
26
|
+
matrix of builder, layout and split settings. CWBVH was slower on the measured
|
|
27
|
+
scenes despite its smaller nodes. Spatial splits help some scenes at three to
|
|
28
|
+
five times the build time, so they stay opt-in.
|
|
29
|
+
- **Traversal tweaks.** Changes to box tests and stack handling showed no reliable
|
|
30
|
+
gain and were not adopted.
|
|
31
|
+
|
|
32
|
+
## Static merge prototype
|
|
33
|
+
|
|
34
|
+
A prototype merged static instances into one world-space BLAS, with world-space
|
|
35
|
+
triangle bounds and vertex tests in local space. It was faster on a heavy
|
|
36
|
+
many-instance scene, but:
|
|
37
|
+
|
|
38
|
+
- coincident geometry needs the old tree as a fallback to keep object identity,
|
|
39
|
+
which costs memory and cold build time;
|
|
40
|
+
- HDR and legacy guides differ by rare rounding, and subsurface scattering, alpha
|
|
41
|
+
random streams, instance colors and picking were not verified;
|
|
42
|
+
- incremental updates and the choice of which instances count as static are
|
|
43
|
+
undesigned.
|
|
44
|
+
|
|
45
|
+
It is not in production. Pursuing it needs both web layouts, an update strategy and
|
|
46
|
+
those verifications, then a native port and comparison.
|
|
47
|
+
|
|
48
|
+
## Changing this code
|
|
49
|
+
|
|
50
|
+
- TLAS and BLAS changes affect `id` AOVs and picking at ties; compare those as well
|
|
51
|
+
as HDR.
|
|
52
|
+
- Keep native's TLAS parameters unless native is aligned in a separate change.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Surface color AOVs
|
|
2
|
+
|
|
3
|
+
MuTracer has two pairs of surface color outputs. `diffuseAlbedo` and
|
|
4
|
+
`specularAlbedo` report how much light a surface reflects. `diffuseColor` and
|
|
5
|
+
`specularColor` report the material colors that produce it. Usage and the exact
|
|
6
|
+
definitions are in [surface outputs](../api.md#surface-outputs); this note explains
|
|
7
|
+
why both pairs exist, how they are named and how they are stored.
|
|
8
|
+
|
|
9
|
+
## Reflectance and color
|
|
10
|
+
|
|
11
|
+
The albedo kinds are directional-hemispherical reflectance: the fraction of
|
|
12
|
+
uniform incident light that the prepared OpenPBR BSDF reflects toward the view
|
|
13
|
+
direction. They integrate the BSDF by quadrature (`aovReflectance*.wgsl.ts` and
|
|
14
|
+
`.glsl.ts`), so they cost more than the other outputs and support only materials
|
|
15
|
+
the quadrature models. Coat, fuzz, anisotropy and similar hits are marked
|
|
16
|
+
unsupported.
|
|
17
|
+
|
|
18
|
+
The color kinds read resolved material inputs without integration:
|
|
19
|
+
|
|
20
|
+
- diffuse: base weight × base color × (1 − metalness)
|
|
21
|
+
- specular: metalness × base weight × base color + (1 − metalness) ×
|
|
22
|
+
specular weight × specular color × F0, with F0 from the specular IOR
|
|
23
|
+
|
|
24
|
+
Both are multiplied by the coat color, weighted by the coat weight. Transmission,
|
|
25
|
+
partial alpha, media and nonstandard materials have zero validity.
|
|
26
|
+
|
|
27
|
+
EASU detail recovery needs the color kinds, not reflectance. It compares
|
|
28
|
+
display-resolution colors with their average over each render pixel and scales
|
|
29
|
+
the part of the upscaled radiance that follows color by that ratio. Layer factors
|
|
30
|
+
that are uniform across a surface, such as coat or fuzz, cancel in the ratio, so
|
|
31
|
+
the cheap estimate covers more surfaces than the quadrature does. Reflectance
|
|
32
|
+
remains the right input for compositing and other uses that need reflected energy.
|
|
33
|
+
|
|
34
|
+
## Names
|
|
35
|
+
|
|
36
|
+
Renderers use "albedo" for both quantities:
|
|
37
|
+
|
|
38
|
+
| Renderer | Integrated reflectance | Material color |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| [MoonRay](https://docs.openmoonray.org/user-reference/how-to-guides/render-outputs/material-aovs/) | `albedo`: response to unoccluded white light from all directions | `color` |
|
|
41
|
+
| [Mitsuba 3](https://mitsuba.readthedocs.io/en/stable/src/generated/plugins_integrators.html) | `albedo`: diffuse reflectance, approximate for some materials | none |
|
|
42
|
+
| [Arnold](https://help.autodesk.com/cloudhelp/ENU/AR-Core/files/ac-output-aovs/arnold_user_guide_ac_output_aovs_ac_aovs_html.html) | none | `diffuse_albedo`, `specular_albedo`: colors without lighting |
|
|
43
|
+
| [Cycles](https://docs.blender.org/manual/en/latest/render/layers/passes.html) | none | `Diffuse Color`, `Glossy Color`: BSDF color weights |
|
|
44
|
+
| V-Ray, Redshift | none | `Diffuse Filter` |
|
|
45
|
+
|
|
46
|
+
MuTracer's names match MoonRay: albedo for integrated reflectance, color for
|
|
47
|
+
material inputs. Albedo for reflectance also matches Mitsuba and the
|
|
48
|
+
"directional albedo" of energy compensation work. Arnold uses albedo for colors,
|
|
49
|
+
so documentation always states the definition next to the name. No surveyed
|
|
50
|
+
renderer names an AOV "reflectance"; the viewer uses it only in labels.
|
|
51
|
+
|
|
52
|
+
These outputs are separate from the OIDN `albedo` guide, which follows its own
|
|
53
|
+
path rules for denoising.
|
|
54
|
+
|
|
55
|
+
## Storage
|
|
56
|
+
|
|
57
|
+
The WebGPU accumulation has four `vec4f` lanes per pixel (`AOV_LAYOUT`):
|
|
58
|
+
depth with roughness, position with hit count, diffuse and specular. A lobe's
|
|
59
|
+
albedo and color share its lane, selected per kind by mask bits 3–4 and 7–8, so a
|
|
60
|
+
render may request only one of them per lobe. Resolve, display and snapshot shaders
|
|
61
|
+
see a color kind as the albedo kind of its lane (`aovLaneKind`), so they need no
|
|
62
|
+
color-specific code. Separate lanes would add 32 bytes per pixel to every AOV
|
|
63
|
+
render. If both are ever needed together, adding lanes lifts the restriction
|
|
64
|
+
without changing the API.
|
|
65
|
+
|
|
66
|
+
Display-resolution renders requesting only `depth`, `diffuseColor` and
|
|
67
|
+
`specularColor` use a compact 24-byte layout: float depth and hit count, plus two
|
|
68
|
+
colors in half precision. It skips the center pass, so it has no ID or motion.
|
|
69
|
+
Half-precision sums lose precision as the sample count grows, which is acceptable
|
|
70
|
+
only because display resolution stops at 4 samples (`DISPLAY_AOV_SAMPLE_CAP`).
|
|
71
|
+
For detail recovery, 4 jittered samples matched 16 within measurement noise.
|
|
72
|
+
Render resolution keeps the full layout for any request.
|
|
73
|
+
|
|
74
|
+
## Native
|
|
75
|
+
|
|
76
|
+
Native shares `aovTraceDisplay.wgsl.ts` but still requests display-resolution
|
|
77
|
+
colors through the albedo bits with the `AOV_DISPLAY` override. The web build never
|
|
78
|
+
sets that override. Native should adopt the color kinds when it is next aligned
|
|
79
|
+
with web AOVs.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Caustic estimators
|
|
2
|
+
|
|
3
|
+
Path tracing finds caustics only when a BSDF sample happens to hit the light
|
|
4
|
+
through a smooth surface, because shadow rays treat glass as an occluder. MuTracer
|
|
5
|
+
adds two WebGPU estimators for those paths: light tracing and progressive photon
|
|
6
|
+
mapping. Usage, costs and limits are in the [caustics guide](../caustics.md); this
|
|
7
|
+
note explains how the paths are divided and how the estimators work.
|
|
8
|
+
|
|
9
|
+
## Path partition
|
|
10
|
+
|
|
11
|
+
A surface is *smooth* when `isCausticSpecular` holds: no diffuse, subsurface, fuzz
|
|
12
|
+
or coat weight, and specular roughness at most `CAUSTIC_ROUGHNESS_MAX` (0.1). The
|
|
13
|
+
test depends only on the material, never on the lobe a sample chose, so every
|
|
14
|
+
estimator classifies a vertex the same way (`src/renderer/caustics.ts`).
|
|
15
|
+
|
|
16
|
+
Counting from the light, the *receiver* is the first non-smooth surface vertex, k is
|
|
17
|
+
the number of smooth vertices between the light and the receiver, and the *camera
|
|
18
|
+
prefix* is the path from the camera to the receiver. Surfaces skipped through alpha
|
|
19
|
+
are not vertices.
|
|
20
|
+
|
|
21
|
+
| Paths | Estimator |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| k = 0 | Path tracing, unchanged |
|
|
24
|
+
| k ≥ 1, empty camera prefix (the camera sees the receiver directly), light tracing on | Light tracing |
|
|
25
|
+
| Other k ≥ 1, photon mapping on | Photon mapping |
|
|
26
|
+
| Anything else | Path tracing's BSDF hits |
|
|
27
|
+
|
|
28
|
+
Path tracing tracks the smooth chain length and whether the receiver is the first
|
|
29
|
+
visible surface. When it hits a light on a path that an enabled estimator owns, the
|
|
30
|
+
contribution is zero. Each path is therefore counted by exactly one estimator.
|
|
31
|
+
When an estimator is off or unsupported (WebGL 2), its rows fall back to path
|
|
32
|
+
tracing, so every configuration has the same expected image and differs only in
|
|
33
|
+
noise. Scenes whose smooth casters use stochastic blend coverage turn both
|
|
34
|
+
estimators off, because their photon transport does not yet match path-tracing
|
|
35
|
+
energy.
|
|
36
|
+
|
|
37
|
+
## Casters and emission
|
|
38
|
+
|
|
39
|
+
The renderer collects caster meshes and instances automatically from smooth
|
|
40
|
+
materials, with one conservative world-space sphere per instance. Photons are
|
|
41
|
+
emitted only toward caster spheres: a path whose first surface from the light is
|
|
42
|
+
not smooth belongs to path tracing, so restricting emission loses no estimator's
|
|
43
|
+
paths. Emission samples the full light surface, then accepts directions toward
|
|
44
|
+
the caster mixture; the direction PDF accounts for overlapping cones
|
|
45
|
+
(`casterDirectionPdf`). Lights are chosen by a separate power PMF, not the NEE
|
|
46
|
+
selection table (`causticEmission.ts`). Directional and environment light emit
|
|
47
|
+
from a mixture of projected caster disks.
|
|
48
|
+
|
|
49
|
+
## Light tracing
|
|
50
|
+
|
|
51
|
+
Light tracing is BDPT's t = 1 strategy. Photons follow smooth vertices with adjoint
|
|
52
|
+
BSDF corrections. At the receiver, the pass samples a lens point, connects to the
|
|
53
|
+
camera, tests visibility and splats into the pixel with float32 compare-and-swap
|
|
54
|
+
atomics. It runs once per sample batch, after the last tile, in its own pass and
|
|
55
|
+
bind group, because the main integrator already uses the baseline eight storage
|
|
56
|
+
buffers. The result accumulates separately; resolve adds it to the path-traced
|
|
57
|
+
radiance, so readback, denoising and display see the combined image. Adaptive
|
|
58
|
+
sampling measures variance only on the path-traced part.
|
|
59
|
+
|
|
60
|
+
## Photon mapping
|
|
61
|
+
|
|
62
|
+
Photon mapping uses probabilistic progressive photon mapping (Knaus and Zwicker
|
|
63
|
+
2011). Each sample batch emits a new photon map on the first tile, which later tiles
|
|
64
|
+
reuse. The gather radius shrinks as r_i = r_1 · i^((α − 1)/2) with α = 2/3
|
|
65
|
+
(`photonRadius`). The first radius is `initialRadius`, or 3% of the caster sphere
|
|
66
|
+
radius. At the first non-smooth camera vertex the radius is further limited to
|
|
67
|
+
about two projected pixels (`photonVisibleRadius`); mirror prefixes use an
|
|
68
|
+
approximate footprint, and deeper vertices use the global radius. The pixel cap
|
|
69
|
+
reduces blotches after denoising, at the cost of grainier raw output.
|
|
70
|
+
|
|
71
|
+
Photons are stored at the first non-smooth surface after at least one smooth
|
|
72
|
+
vertex, whatever camera prefix will later find them; queries at directly visible
|
|
73
|
+
receivers skip them when light tracing owns those paths. Camera paths query at every non-smooth vertex within `bounces`, with a
|
|
74
|
+
normal-consistent surface kernel.
|
|
75
|
+
|
|
76
|
+
Each photon takes 20 bytes: float32 position and RGBE8 flux, and two octahedral
|
|
77
|
+
directions (incident direction and normal). Two hash-grid layers with different
|
|
78
|
+
cell sizes, one for first visible receivers and one for deeper queries, each sort
|
|
79
|
+
only a 4-byte index, for 28 bytes per photon. Grids are rebuilt every batch with a
|
|
80
|
+
count, a two-level parallel prefix sum and a scatter; bucket counts are powers of
|
|
81
|
+
two up to 262144. Batches are reduced to fit device limits and a 128 MiB budget.
|
|
82
|
+
|
|
83
|
+
Quantized flux and directions limit precision. More batches shrink the radius
|
|
84
|
+
but do not remove that error, so photon mapping is consistent only up to storage
|
|
85
|
+
precision.
|
|
86
|
+
|
|
87
|
+
## Rejected and paused work
|
|
88
|
+
|
|
89
|
+
- **MNEE and SMS** (manifold next-event estimation and specular manifold sampling)
|
|
90
|
+
are paused and excluded from builds. Behind a wavy refractive surface, each
|
|
91
|
+
receiver can have dozens of manifold roots; Newton's method finds one, and SMS
|
|
92
|
+
with its 64-trial cap covered only part of their weight, so neither converged
|
|
93
|
+
to an unbiased result. The code remains in
|
|
94
|
+
`src/research/mnee/`, registered explicitly by tests and research scripts. A
|
|
95
|
+
restart should address multiple roots, for example with manifold path guiding
|
|
96
|
+
(Fan et al. 2023).
|
|
97
|
+
- **Separate photon denoising**, filtering photon contributions apart from path
|
|
98
|
+
tracing, increased error in comparisons and is not used.
|
|
99
|
+
- **Photon-count radius scaling**, per-caster radii and larger shrinking screen
|
|
100
|
+
radii remain internal diagnostics (`causticDiagnostics.ts`). None improved
|
|
101
|
+
equal-error time on every test scene.
|
|
102
|
+
|
|
103
|
+
## Changing this code
|
|
104
|
+
|
|
105
|
+
- The partition runs in WGSL. WebGL traces plain paths and needs no zeroing; its
|
|
106
|
+
GLSL chain state exists only for the paused MNEE research path.
|
|
107
|
+
- Native shares the WGSL and exposes the same two estimators.
|
|
108
|
+
- Compare raw HDR, not denoised output, when judging energy; see the guide's
|
|
109
|
+
limits for denoiser artifacts.
|
|
@@ -53,6 +53,35 @@ Photon gathering filters photon flux by the camera path's channel. This splits R
|
|
|
53
53
|
across the camera paths and applies no second spectral weight, so energy is shared
|
|
54
54
|
between path tracing and caustics the same way as without dispersion.
|
|
55
55
|
|
|
56
|
+
## Shared prefixes
|
|
57
|
+
|
|
58
|
+
With `dispersionWavelengths: 3`, the three channel paths of a pixel sample are
|
|
59
|
+
identical until the first wavelength-dependent IOR: they use the same random numbers
|
|
60
|
+
and carry full RGB until then. The integrators trace that prefix once, checkpoint
|
|
61
|
+
the path, material, auxiliary outputs and random-stream state at the first
|
|
62
|
+
dispersive interaction, and replay only the wavelength-specific suffix for each
|
|
63
|
+
channel. RGB results completed before any dispersion are reused for all three.
|
|
64
|
+
WGSL replays the suffixes inside the flat, alpha, volume and guide paths; GLSL
|
|
65
|
+
traces all three in one fragment invocation (`spectralPrefix.glsl.ts`). Images are
|
|
66
|
+
the same as with independent paths; only the work is shared. MNEE keeps independent
|
|
67
|
+
paths, because its connection solver can disperse before the camera boundary.
|
|
68
|
+
|
|
69
|
+
Tracing three suffixes in one WebGL draw makes that draw about three times longer.
|
|
70
|
+
See [WebGL 2 backend](./webgl.md) for the timeout risk this adds on large images.
|
|
71
|
+
|
|
72
|
+
## Direct-light resampling
|
|
73
|
+
|
|
74
|
+
Direct lighting selects among `directLightCandidates` light samples by resampled
|
|
75
|
+
importance sampling. When the three channel paths share a prefix, they share one
|
|
76
|
+
reservoir, so the target cannot depend on the channel a path carries. The target
|
|
77
|
+
is the full RGB contribution with equal channel weights; only the final estimator
|
|
78
|
+
keeps the path's channel (`sampleMaterial.wgsl.ts`). A luminance target would
|
|
79
|
+
underweight saturated red and blue light and raise their noise. Equal weights reduce
|
|
80
|
+
that, but a strongly colored region can still converge more slowly in one channel
|
|
81
|
+
than with independent per-channel paths; [sampling](../sampling.md) documents this
|
|
82
|
+
caveat. Single-wavelength previews and non-dispersive renders keep the luminance
|
|
83
|
+
target. WebGL draws one light candidate and has no reservoir.
|
|
84
|
+
|
|
56
85
|
## Short-wavelength IOR limit
|
|
57
86
|
|
|
58
87
|
Cauchy IOR rises quickly at short wavelengths. At strong dispersion scales, violet
|