@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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveSurfaceHit } from './surfaceHit.js';
|
|
2
|
+
import { compactVertexLayout, packCompactVertices, packTriangleMaterials } from './compactVertices.js';
|
|
1
3
|
import { causticDiagnostics } from './causticDiagnostics.js';
|
|
2
4
|
import { WGPUPhotonMap, photonRadius } from './WGPUPhotonMap.js';
|
|
3
5
|
import { defaultPhotonMapPhotons } from './wgsl/photonMap.compute.js';
|
|
@@ -8,10 +10,10 @@ import { causticLightCompute } from './wgsl/causticLight.compute.js';
|
|
|
8
10
|
import { causticCasterSpheres, hasStochasticCausticCaster, causticCasterSphere, isCausticSpecular } from './caustics.js';
|
|
9
11
|
import { AovPrimitiveCache } from './AovPrimitiveCache.js';
|
|
10
12
|
import { packAovScene } from './aovScene.js';
|
|
11
|
-
import { aovMask } from './aov.js';
|
|
13
|
+
import { aovMask, AOV_ACCUMULATED_MASK, AOV_REFLECTANCE_MASK, COMPACT_AOV_KINDS } from './aov.js';
|
|
12
14
|
import { proceduralEnvironmentPower } from './proceduralEnvironmentPower.js';
|
|
13
15
|
import { WGPUSkyBaker } from './WGPUSkyBaker.js';
|
|
14
|
-
import { initialSceneConstants,
|
|
16
|
+
import { initialSceneConstants, sceneTraversalConstants, prepareSceneLightSampling, writeTraceLighting, packSceneAnalyticLights, writeTraceQuality, traceSampling, writeTraceSampling } from './sceneAssembly.js';
|
|
15
17
|
import { rayTraceBindGroupLayouts } from './sceneLayoutSchema.js';
|
|
16
18
|
import { WGPUBindlessMaterialData } from './WGPUBindlessMaterialData.js';
|
|
17
19
|
import { WGPUBindlessTextures } from './WGPUBindlessTextures.js';
|
|
@@ -22,7 +24,7 @@ import { wgpuShaderSource, wgpuPipelineConstantKeys, WGPU_SHADER_DEFINE_KEYS } f
|
|
|
22
24
|
import { makeRayTraceUniform, WGPU_SCENE_BUFFER_MIN_BYTES } from './wgpuSceneUniform.js';
|
|
23
25
|
import { constants } from './webgl.js';
|
|
24
26
|
import { MATERIAL_FLOAT_COUNT } from './materialLayoutSchema.js';
|
|
25
|
-
import { normalizeBounces } from './pathLimits.js';
|
|
27
|
+
import { normalizeBounces, MAX_PATH_EVENTS_WGPU } from './pathLimits.js';
|
|
26
28
|
import { updateMeshInstanceColors } from './prepareMeshBVH.js';
|
|
27
29
|
import { updateTLASInstanceColors } from './bvhAccel.js';
|
|
28
30
|
import { getMaterialHashKey } from '../scene/openPbrSchema.js';
|
|
@@ -35,8 +37,7 @@ import { packCameraUniform } from './cameraUniform.js';
|
|
|
35
37
|
import { SHADOW_CATCHER_ACCUMULATION_BYTES } from './wgsl/chunks/shadowCatcherAccumulation.wgsl.js';
|
|
36
38
|
import { DEPTH_SAMPLE_COUNT, packDepthSampleArea, unpackDepthSamples } from './depthQuery.js';
|
|
37
39
|
import { MeshMembershipCache } from './meshMembership.js';
|
|
38
|
-
import {
|
|
39
|
-
import { updatePreparedGeometries, canUpdateGeometries, geometryTopologyChanged, packVertexAttributes } from './geometryUpdates.js';
|
|
40
|
+
import { updatePreparedGeometries, canUpdateGeometries, geometryTopologyChanged, } from './geometryUpdates.js';
|
|
40
41
|
import { SceneEnvironmentCache, RectLightTextureTracker } from './sceneLightChanges.js';
|
|
41
42
|
import { MaterialChangeTracker, materialIsEmissive } from './materialChanges.js';
|
|
42
43
|
import { WGPUEnvMapDistribution } from './WGPUEnvMapDistribution.js';
|
|
@@ -51,7 +52,7 @@ import { generateBackgroundMapFromSceneBackground, environmentRotation, backgrou
|
|
|
51
52
|
import { WORKGROUP_SIZE } from './wgsl/rayTrace.compute.js';
|
|
52
53
|
import { envMapDistribution, environmentMapSourcesMatch } from './envMapDistribution.js';
|
|
53
54
|
import { updateMeshInstances, updateMeshInstanceTransforms } from './prepareMeshBVH.js';
|
|
54
|
-
import {
|
|
55
|
+
import { buildWebTLAS, getTraversalStackSizes, refitBLAS, refitTLAS } from './bvhAccel.js';
|
|
55
56
|
import { isTextureDataSource } from '../scene/Texture.js';
|
|
56
57
|
import { DEFAULT_BEVEL_SAMPLES, DEFAULT_DIRECT_LIGHT_CANDIDATES, normalizeBevelSamples, normalizeDirectLightCandidates } from './RenderingPipeline.js';
|
|
57
58
|
import { EmissiveTriangleCache, LightChoiceBuffer, estimateEnvironmentPower } from './lightSampling.js';
|
|
@@ -271,6 +272,7 @@ class WGPURayTracePass {
|
|
|
271
272
|
_clamping;
|
|
272
273
|
_transmissiveAlphaMin = 1;
|
|
273
274
|
_viewProjInv = mat4.create();
|
|
275
|
+
_projectionInv = mat4.create();
|
|
274
276
|
_cameraWorld = mat4.create();
|
|
275
277
|
_apertureRadius = 0;
|
|
276
278
|
_focusDistance = 10;
|
|
@@ -286,7 +288,8 @@ class WGPURayTracePass {
|
|
|
286
288
|
_depthTracePipeline;
|
|
287
289
|
_depthPipeline;
|
|
288
290
|
_shaderCache;
|
|
289
|
-
|
|
291
|
+
_bvhCPU;
|
|
292
|
+
_bvhDataBytes = 0;
|
|
290
293
|
// Fold scene invariants before backend inlining; runtime edits use uniforms.
|
|
291
294
|
_bakePipelineConstants = true;
|
|
292
295
|
constructor(device, _textureSelection = { requested: 'atlas' }) {
|
|
@@ -296,7 +299,7 @@ class WGPURayTracePass {
|
|
|
296
299
|
if (_textureSelection.support)
|
|
297
300
|
this._bindless = new WGPUBindlessTextures(device);
|
|
298
301
|
this._uniforms = {
|
|
299
|
-
cameraUniform: this._uniformBuffer(
|
|
302
|
+
cameraUniform: this._uniformBuffer(52 * 4),
|
|
300
303
|
rtUniform: this._uniformBuffer(this._rtUniform.buffer.byteLength),
|
|
301
304
|
analyticLights: this._uniformBuffer(FIXED_LIGHT_COUNT * PIXELS_PER_LIGHT * 4 * 4)
|
|
302
305
|
};
|
|
@@ -558,6 +561,9 @@ class WGPURayTracePass {
|
|
|
558
561
|
_updateGPUBuffer(label, gpuBuffer, data, minSize = WGPU_SCENE_BUFFER_MIN_BYTES) {
|
|
559
562
|
const device = this._device;
|
|
560
563
|
const size = Math.max(data.byteLength, minSize);
|
|
564
|
+
const limit = Math.min(device.limits?.maxBufferSize ?? Infinity, device.limits?.maxStorageBufferBindingSize ?? Infinity);
|
|
565
|
+
if (size > limit)
|
|
566
|
+
throw new RangeError(`${label} buffer requires ${size} bytes; device storage buffer limit is ${limit} bytes.`);
|
|
561
567
|
if (gpuBuffer == null || gpuBuffer.size < size) {
|
|
562
568
|
this._needsUpdateBindGroups = true;
|
|
563
569
|
if (gpuBuffer) {
|
|
@@ -568,10 +574,22 @@ class WGPURayTracePass {
|
|
|
568
574
|
size,
|
|
569
575
|
usage: GPUBufferUsage.STORAGE |
|
|
570
576
|
GPUBufferUsage.COPY_DST |
|
|
571
|
-
GPUBufferUsage.COPY_SRC
|
|
577
|
+
GPUBufferUsage.COPY_SRC,
|
|
578
|
+
// Chromium's mapped-creation IPC payload is limited to a signed 32-bit
|
|
579
|
+
// size even when the adapter supports larger storage buffers.
|
|
580
|
+
mappedAtCreation: size < 0x80000000
|
|
572
581
|
});
|
|
582
|
+
if (size < 0x80000000) {
|
|
583
|
+
new Uint8Array(gpuBuffer.getMappedRange()).set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
584
|
+
gpuBuffer.unmap();
|
|
585
|
+
return gpuBuffer;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// Bound each staging allocation/IPC payload for large or reused buffers.
|
|
589
|
+
const chunkBytes = 64 * 1024 * 1024;
|
|
590
|
+
for (let offset = 0; offset < data.byteLength; offset += chunkBytes) {
|
|
591
|
+
this._device.queue.writeBuffer(gpuBuffer, offset, data.buffer, data.byteOffset + offset, Math.min(chunkBytes, data.byteLength - offset));
|
|
573
592
|
}
|
|
574
|
-
this._device.queue.writeBuffer(gpuBuffer, 0, data.buffer);
|
|
575
593
|
return gpuBuffer;
|
|
576
594
|
}
|
|
577
595
|
_uniformBuffer(size) {
|
|
@@ -646,6 +664,7 @@ class WGPURayTracePass {
|
|
|
646
664
|
this._preparePhotonTarget();
|
|
647
665
|
const pipelineInputs = JSON.stringify([
|
|
648
666
|
this._constants,
|
|
667
|
+
Boolean(this._constants.SPECTRAL) && this._shareSpectralPrefix,
|
|
649
668
|
this._hasDisplacement,
|
|
650
669
|
this._alphaBlendStrategy,
|
|
651
670
|
this._blasLayoutMask,
|
|
@@ -675,6 +694,7 @@ class WGPURayTracePass {
|
|
|
675
694
|
const pipelineConstantsKeys = wgpuPipelineConstantKeys(constants);
|
|
676
695
|
const defineCode = WGPU_SHADER_DEFINE_KEYS.map((key) => `const ${key} = ${constants[key]};`).join('\n');
|
|
677
696
|
const structure = {
|
|
697
|
+
shareSpectralPrefix: Boolean(constants.SPECTRAL) && this._shareSpectralPrefix,
|
|
678
698
|
hasDisplacement: this._hasDisplacement,
|
|
679
699
|
caustics: this._causticKey,
|
|
680
700
|
bindless: !!this._bindless,
|
|
@@ -756,13 +776,14 @@ class WGPURayTracePass {
|
|
|
756
776
|
}
|
|
757
777
|
/** Snapshots everything compilation needs. The task must not read mutable pass state afterwards. */
|
|
758
778
|
_startTraceVariant(signature, constants, shader) {
|
|
779
|
+
const shareSpectralPrefix = Boolean(constants.SPECTRAL) && this._shareSpectralPrefix;
|
|
759
780
|
const bake = this._bakePipelineConstants, bindless = this._bindless;
|
|
760
781
|
const hasDisplacement = this._hasDisplacement, blasLayoutMask = this._blasLayoutMask;
|
|
761
782
|
const lightTracing = this._lightTracing, photonMapping = this._photonMapping;
|
|
762
783
|
const causticKey = this._causticKey, transport = this._transport;
|
|
763
784
|
const { hasAlpha, hasSceneAlpha, defineCode, pipelineConstantsKeys } = shader;
|
|
764
785
|
const emitterSource = (mode) => {
|
|
765
|
-
const code = causticLightCompute(constants, blasLayoutMask, hasDisplacement, mode, '', causticDiagnostics.fullEmissionRandom !== false);
|
|
786
|
+
const code = causticLightCompute(constants, blasLayoutMask, hasDisplacement, mode, '', causticDiagnostics.fullEmissionRandom !== false, true, true);
|
|
766
787
|
return bindless ? bindlessShaderSource(code, this._textureSelection.support.enable) : code;
|
|
767
788
|
};
|
|
768
789
|
const lightEmitter = lightTracing ? this._causticLight ??= new WGPUCausticLightPass(this._device) : undefined;
|
|
@@ -786,13 +807,16 @@ class WGPURayTracePass {
|
|
|
786
807
|
startedAt = shaderCompilationNow();
|
|
787
808
|
// Override values are not part of the WGSL unless they are baked, so a
|
|
788
809
|
// quality edit can share the module that the driver has already parsed.
|
|
789
|
-
const moduleKey = JSON.stringify([causticKey, !!bindless, hasAlpha, hasSceneAlpha, hasDisplacement,
|
|
810
|
+
const moduleKey = JSON.stringify([causticKey, !!bindless, shareSpectralPrefix, Boolean(constants.SPECTRAL), hasAlpha, hasSceneAlpha, hasDisplacement,
|
|
790
811
|
constants.USE_ANISOTROPY_DIRECTIONS, constants.USE_COAT_NORMAL_FRAMES, blasLayoutMask, defineCode, pipelineConstantsKeys,
|
|
791
812
|
bake && pipelineConstantsKeys.map((key) => constants[key])]);
|
|
792
813
|
let source = this._traceModules.get(moduleKey);
|
|
793
814
|
if (!source) {
|
|
794
815
|
let code = wgpuShaderSource(constants, {
|
|
816
|
+
maxPathEvents: MAX_PATH_EVENTS_WGPU,
|
|
795
817
|
hasDisplacement,
|
|
818
|
+
channelIndependentRis: Boolean(constants.SPECTRAL),
|
|
819
|
+
shareSpectralPrefix,
|
|
796
820
|
hasAlpha,
|
|
797
821
|
hasSceneAlpha,
|
|
798
822
|
...transport?.features,
|
|
@@ -805,7 +829,11 @@ class WGPURayTracePass {
|
|
|
805
829
|
hasAnisotropyDirections: Boolean(constants.USE_ANISOTROPY_DIRECTIONS),
|
|
806
830
|
hasCoatNormals: Boolean(constants.USE_COAT_NORMAL_FRAMES),
|
|
807
831
|
blasLayoutMask,
|
|
808
|
-
|
|
832
|
+
cameraProjectionInverse: true,
|
|
833
|
+
perInstanceBounds: true,
|
|
834
|
+
compactVertices: true,
|
|
835
|
+
dynamicEnvironment: true,
|
|
836
|
+
displayAovStorage: true
|
|
809
837
|
}, bake);
|
|
810
838
|
if (bindless)
|
|
811
839
|
code = bindlessShaderSource(code, this._textureSelection.support.enable);
|
|
@@ -948,20 +976,21 @@ class WGPURayTracePass {
|
|
|
948
976
|
if (index >= 0)
|
|
949
977
|
this._queuedCompiles.push(...this._queuedCompiles.splice(index, 1));
|
|
950
978
|
}
|
|
951
|
-
_prepareAovPipelines(kinds) {
|
|
979
|
+
_prepareAovPipelines(kinds, compact = false) {
|
|
952
980
|
const trace = this._rayTracePipeline;
|
|
953
981
|
if (!trace || !this._depthCompute)
|
|
954
982
|
return;
|
|
955
|
-
const reflectance = (aovMask(kinds) &
|
|
983
|
+
const reflectance = (aovMask(kinds) & AOV_REFLECTANCE_MASK) !== 0;
|
|
956
984
|
let variants = this._aovPipelines.get(trace);
|
|
957
985
|
if (!variants) {
|
|
958
986
|
variants = new Map();
|
|
959
987
|
this._aovPipelines.set(trace, variants);
|
|
960
988
|
}
|
|
961
|
-
|
|
989
|
+
const key = Number(reflectance) + Number(compact) * 2;
|
|
990
|
+
let pipelines = variants.get(key);
|
|
962
991
|
if (!pipelines) {
|
|
963
992
|
pipelines = {};
|
|
964
|
-
variants.set(
|
|
993
|
+
variants.set(key, pipelines);
|
|
965
994
|
const pending = pipelines;
|
|
966
995
|
const textures = this._bindless, groupIndex = textures ? 2 : 3;
|
|
967
996
|
const output = this._device.createBindGroupLayout({ entries: [
|
|
@@ -973,7 +1002,7 @@ class WGPURayTracePass {
|
|
|
973
1002
|
] });
|
|
974
1003
|
const descriptor = { bindGroupLayouts: Array.from({ length: groupIndex }, (_, i) => trace.getBindGroupLayout(i)).concat(output) };
|
|
975
1004
|
const layout = this._device.createPipelineLayout(textures ? resourceTableLayout(descriptor) : descriptor);
|
|
976
|
-
const compute = { ...this._depthCompute, constants: { ...this._depthCompute.constants, DEPTH_QUERY_MODE: 1, AOV_REFLECTANCE: reflectance ? 1 : 0 } };
|
|
1005
|
+
const compute = { ...this._depthCompute, constants: { ...this._depthCompute.constants, DEPTH_QUERY_MODE: 1, AOV_REFLECTANCE: reflectance ? 1 : 0, AOV_COMPACT: compact ? 1 : 0 } };
|
|
977
1006
|
// Keep the UI responsive during first use, and reuse both variants across
|
|
978
1007
|
// preview/final target changes rather than recreating synchronous pipelines.
|
|
979
1008
|
void Promise.all([
|
|
@@ -985,30 +1014,33 @@ class WGPURayTracePass {
|
|
|
985
1014
|
throw pipelines.error;
|
|
986
1015
|
return pipelines;
|
|
987
1016
|
}
|
|
988
|
-
prepareAovs(kinds) {
|
|
989
|
-
const pipelines = this._prepareAovPipelines(kinds);
|
|
1017
|
+
prepareAovs(kinds, compact = false) {
|
|
1018
|
+
const pipelines = this._prepareAovPipelines(kinds, compact);
|
|
990
1019
|
return !!pipelines?.accumulation && !!pipelines.center;
|
|
991
1020
|
}
|
|
992
|
-
renderAovs(state, camera, samples, cap, kinds) {
|
|
1021
|
+
renderAovs(state, camera, samples, cap, kinds, resolution) {
|
|
993
1022
|
const groups = this._rayTraceBindGroups;
|
|
994
1023
|
if (!groups || !this._tlas || !this._preparedMeshData || !kinds.length)
|
|
995
1024
|
return false;
|
|
996
|
-
const
|
|
1025
|
+
const compact = !!resolution && kinds.every(kind => COMPACT_AOV_KINDS.includes(kind));
|
|
1026
|
+
const pipelines = this._prepareAovPipelines(kinds, compact);
|
|
997
1027
|
if (!pipelines?.accumulation || !pipelines.center)
|
|
998
1028
|
return false;
|
|
999
|
-
state.resize(this._width, this._height);
|
|
1029
|
+
state.resize(resolution?.width ?? this._width, resolution?.height ?? this._height, compact);
|
|
1000
1030
|
const textures = this._bindless, groupIndex = textures ? 2 : 3;
|
|
1001
1031
|
const target = Math.min(samples, cap);
|
|
1002
1032
|
if (state.centerReady && state.samples >= target)
|
|
1003
1033
|
return true;
|
|
1004
1034
|
if (!state.frame) {
|
|
1005
|
-
|
|
1006
|
-
|
|
1035
|
+
// Only the center pass reads primitive IDs and compact display AOVs skip
|
|
1036
|
+
// it; building the map walks every BVH leaf on the main thread.
|
|
1037
|
+
const primitiveIds = compact ? undefined : this._aovPrimitiveCache.get(this._preparedMeshData, this._tlas);
|
|
1038
|
+
const packed = packAovScene(this._preparedMeshData, this._tlas, camera, state.width, state.height, state.history, primitiveIds, false);
|
|
1007
1039
|
state.frame = packed.frame;
|
|
1008
1040
|
state.setScene(packed.words, primitiveIds);
|
|
1009
1041
|
}
|
|
1010
1042
|
this._device.queue.writeBuffer(this._uniforms.rtUniform, 0, this._rtUniform.buffer);
|
|
1011
|
-
this._device.queue.writeBuffer(this._uniforms.cameraUniform, 0, packCameraUniform(this._viewProjInv, this._cameraWorld, this._apertureRadius, this._focusDistance));
|
|
1043
|
+
this._device.queue.writeBuffer(this._uniforms.cameraUniform, 0, packCameraUniform(this._viewProjInv, this._cameraWorld, this._apertureRadius, this._focusDistance, this._projectionInv));
|
|
1012
1044
|
const device = this._device;
|
|
1013
1045
|
const run = (pipeline, sample) => {
|
|
1014
1046
|
// A fresh uniform for each queued dispatch keeps batch samples independent.
|
|
@@ -1032,11 +1064,12 @@ class WGPURayTracePass {
|
|
|
1032
1064
|
parameters.destroy();
|
|
1033
1065
|
};
|
|
1034
1066
|
if (!state.centerReady) {
|
|
1035
|
-
|
|
1067
|
+
if (!compact)
|
|
1068
|
+
run(pipelines.center, 0);
|
|
1036
1069
|
state.centerReady = true;
|
|
1037
1070
|
state.history.accept(state.frame);
|
|
1038
1071
|
}
|
|
1039
|
-
if ((aovMask(kinds) &
|
|
1072
|
+
if ((aovMask(kinds) & AOV_ACCUMULATED_MASK) === 0)
|
|
1040
1073
|
state.samples = target;
|
|
1041
1074
|
while (state.samples < target) {
|
|
1042
1075
|
run(pipelines.accumulation, state.samples);
|
|
@@ -1044,13 +1077,27 @@ class WGPURayTracePass {
|
|
|
1044
1077
|
}
|
|
1045
1078
|
return true;
|
|
1046
1079
|
}
|
|
1047
|
-
async
|
|
1080
|
+
async pickSurface(x, y, aspect) {
|
|
1081
|
+
const source = this._preparedMeshData, tlas = this._tlas;
|
|
1082
|
+
if (!source || !tlas)
|
|
1083
|
+
return;
|
|
1084
|
+
const values = await this._readDepthSamples({ x, y, size: 0 }, aspect, true);
|
|
1085
|
+
if (!values || source !== this._preparedMeshData || tlas !== this._tlas)
|
|
1086
|
+
return;
|
|
1087
|
+
return resolveSurfaceHit(source, tlas, values);
|
|
1088
|
+
}
|
|
1089
|
+
readDepthSamples(area, aspect) {
|
|
1090
|
+
return this._readDepthSamples(area, aspect);
|
|
1091
|
+
}
|
|
1092
|
+
async _readDepthSamples(area, aspect, picking = false) {
|
|
1048
1093
|
const tracePipeline = this._rayTracePipeline;
|
|
1049
1094
|
const groups = this._rayTraceBindGroups;
|
|
1050
1095
|
const textures = this._bindless, textureRevision = textures?.revision;
|
|
1051
1096
|
if (!tracePipeline || !groups || !this._depthCompute || this.isCompilingShader())
|
|
1052
1097
|
return;
|
|
1053
1098
|
const packed = packDepthSampleArea(area, aspect ?? this._width / this._height);
|
|
1099
|
+
if (picking)
|
|
1100
|
+
packed.set([-1, -1], 2);
|
|
1054
1101
|
if (this._depthTracePipeline !== tracePipeline || !this._depthPipeline) {
|
|
1055
1102
|
const outputLayout = this._shaderCache.createBindGroupLayout({
|
|
1056
1103
|
label: 'Depth query output',
|
|
@@ -1102,7 +1149,8 @@ class WGPURayTracePass {
|
|
|
1102
1149
|
encoder.copyBufferToBuffer(output, 0, readback, 0, bytes);
|
|
1103
1150
|
device.queue.submit([encoder.finish()]);
|
|
1104
1151
|
await readback.mapAsync(GPUMapMode.READ);
|
|
1105
|
-
|
|
1152
|
+
const rgba = new Float32Array(readback.getMappedRange());
|
|
1153
|
+
return picking ? rgba.slice(0, 4) : unpackDepthSamples(rgba);
|
|
1106
1154
|
}
|
|
1107
1155
|
finally {
|
|
1108
1156
|
if (readback.mapState === 'mapped')
|
|
@@ -1333,12 +1381,12 @@ class WGPURayTracePass {
|
|
|
1333
1381
|
return (causticBatch ? 1 : 0) | (photonBatch ? 2 : 0);
|
|
1334
1382
|
}
|
|
1335
1383
|
async getDebugBVHData() {
|
|
1336
|
-
if (!this.
|
|
1337
|
-
throw new Error(
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
};
|
|
1384
|
+
if (!this._bvhCPU)
|
|
1385
|
+
throw new Error('software-bvh exposes no CPU-readable BVH debug buffer');
|
|
1386
|
+
// Debug capture pays for a combined copy only when explicitly requested.
|
|
1387
|
+
const buffer = new ArrayBuffer(this._bvhDataBytes);
|
|
1388
|
+
this._writeBVH(buffer, this._bvhCPU.tlas, this._bvhCPU.blases);
|
|
1389
|
+
return { buffer };
|
|
1342
1390
|
}
|
|
1343
1391
|
getDiagnostics() {
|
|
1344
1392
|
const atlas = this._materialData instanceof MaterialTable ? this._materialData.textureAtlasStats : undefined;
|
|
@@ -1379,7 +1427,7 @@ class WGPURayTracePass {
|
|
|
1379
1427
|
return this._apertureRadius > 0;
|
|
1380
1428
|
}
|
|
1381
1429
|
setBounce(bounce) {
|
|
1382
|
-
const next = normalizeBounces(bounce);
|
|
1430
|
+
const next = normalizeBounces(bounce, MAX_PATH_EVENTS_WGPU);
|
|
1383
1431
|
const changed = this._bounces !== next;
|
|
1384
1432
|
this._bounces = next;
|
|
1385
1433
|
this._rtUniform.views.bounces[0] = next;
|
|
@@ -1435,9 +1483,11 @@ class WGPURayTracePass {
|
|
|
1435
1483
|
this._ensureAdaptiveSamplingTexture(width, height);
|
|
1436
1484
|
this._device.queue.writeTexture({ texture: this._adaptiveSamplingTexture }, data, { bytesPerRow: width * Float32Array.BYTES_PER_ELEMENT }, [width, height]);
|
|
1437
1485
|
}
|
|
1486
|
+
_shareSpectralPrefix = true;
|
|
1438
1487
|
setQuality(options) {
|
|
1488
|
+
this._shareSpectralPrefix = options.dispersionWavelengths !== 1;
|
|
1439
1489
|
WGPURayTracePass.prototype._setCaustics.call(this, options.caustics);
|
|
1440
|
-
writeTraceQuality(this._rtUniform.views, options);
|
|
1490
|
+
writeTraceQuality(this._rtUniform.views, options, MAX_PATH_EVENTS_WGPU);
|
|
1441
1491
|
}
|
|
1442
1492
|
_setCaustics(settings) {
|
|
1443
1493
|
this._causticSettings = settings;
|
|
@@ -1870,22 +1920,54 @@ class WGPURayTracePass {
|
|
|
1870
1920
|
const stacks = getTraversalStackSizes(tlas, blases);
|
|
1871
1921
|
this._constants.TLAS_STACK_SIZE = retainedShaderCapacity(stacks.tlas, Number(this._constants.TLAS_STACK_SIZE ?? 0));
|
|
1872
1922
|
this._constants.BLAS_STACK_SIZE = retainedShaderCapacity(stacks.blas, Number(this._constants.BLAS_STACK_SIZE ?? 0), 32);
|
|
1873
|
-
const
|
|
1874
|
-
const
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1923
|
+
const size = tlas.buffer.byteLength + blases.reduce((sum, b) => sum + b.bvh.buffer.byteLength, 0);
|
|
1924
|
+
const limit = Math.min(this._device.limits.maxBufferSize, this._device.limits.maxStorageBufferBindingSize);
|
|
1925
|
+
if (size > limit)
|
|
1926
|
+
throw new RangeError(`BVH buffer requires ${size} bytes; device storage buffer limit is ${limit} bytes.`);
|
|
1927
|
+
let bvhBuffer = this._bvhBuffer;
|
|
1928
|
+
if (!bvhBuffer || bvhBuffer.size < Math.max(size, WGPU_SCENE_BUFFER_MIN_BYTES)) {
|
|
1929
|
+
bvhBuffer?.destroy();
|
|
1930
|
+
bvhBuffer = this._device.createBuffer({ label: 'BVH', size: Math.max(size, WGPU_SCENE_BUFFER_MIN_BYTES),
|
|
1931
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, mappedAtCreation: size < 0x80000000 });
|
|
1932
|
+
if (size < 0x80000000) {
|
|
1933
|
+
this._writeBVH(bvhBuffer.getMappedRange(), tlas, blases);
|
|
1934
|
+
bvhBuffer.unmap();
|
|
1935
|
+
}
|
|
1936
|
+
else
|
|
1937
|
+
this._uploadBVHBlocks(bvhBuffer, tlas, blases);
|
|
1938
|
+
}
|
|
1939
|
+
else
|
|
1940
|
+
this._uploadBVHBlocks(bvhBuffer, tlas, blases);
|
|
1941
|
+
this._bvhCPU = { tlas, blases };
|
|
1942
|
+
this._bvhDataBytes = size;
|
|
1943
|
+
const blasOffset = tlas.buffer.byteLength / 16;
|
|
1880
1944
|
const instancesBuffer = this._updateGPUBuffer('Instances', this._instancesBuffer, new Float32Array(tlas.instancesBuffer));
|
|
1881
|
-
if (bvhBuffer !== this._bvhBuffer || instancesBuffer !== this._instancesBuffer)
|
|
1945
|
+
if (bvhBuffer !== this._bvhBuffer || instancesBuffer !== this._instancesBuffer)
|
|
1882
1946
|
this._needsUpdateBindGroups = true;
|
|
1883
|
-
}
|
|
1884
1947
|
this._bvhBuffer = bvhBuffer;
|
|
1885
1948
|
this._instancesBuffer = instancesBuffer;
|
|
1886
|
-
this._debugBVHBuffer = bvhData.buffer.slice(0);
|
|
1887
1949
|
this._rtUniform.views.blasOffset.set([blasOffset]);
|
|
1888
1950
|
}
|
|
1951
|
+
_uploadBVHBlocks(buffer, tlas, blases) {
|
|
1952
|
+
this._device.queue.writeBuffer(buffer, 0, tlas.buffer);
|
|
1953
|
+
let target = tlas.buffer.byteLength;
|
|
1954
|
+
for (const blas of blases) {
|
|
1955
|
+
const chunkBytes = 64 * 1024 * 1024;
|
|
1956
|
+
for (let offset = 0; offset < blas.bvh.buffer.byteLength; offset += chunkBytes) {
|
|
1957
|
+
this._device.queue.writeBuffer(buffer, target + offset, blas.bvh.buffer, offset, Math.min(chunkBytes, blas.bvh.buffer.byteLength - offset));
|
|
1958
|
+
}
|
|
1959
|
+
target += blas.bvh.buffer.byteLength;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
_writeBVH(buffer, tlas, blases) {
|
|
1963
|
+
const bytes = new Uint8Array(buffer);
|
|
1964
|
+
bytes.set(new Uint8Array(tlas.buffer));
|
|
1965
|
+
let offset = tlas.buffer.byteLength;
|
|
1966
|
+
for (const blas of blases) {
|
|
1967
|
+
bytes.set(new Uint8Array(blas.bvh.buffer), offset);
|
|
1968
|
+
offset += blas.bvh.buffer.byteLength;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1889
1971
|
_updateMeshData() {
|
|
1890
1972
|
this._pendingGeometryUpdates.clear();
|
|
1891
1973
|
this._emissiveCache = new EmissiveTriangleCache();
|
|
@@ -1900,7 +1982,7 @@ class WGPURayTracePass {
|
|
|
1900
1982
|
}
|
|
1901
1983
|
this._geometriesNeedRefit.clear();
|
|
1902
1984
|
// TODO check bvh needs to change
|
|
1903
|
-
const res = updateMeshInstances(meshes);
|
|
1985
|
+
const res = updateMeshInstances(meshes, { mergeAttributes: false });
|
|
1904
1986
|
this._preparedMeshData = res;
|
|
1905
1987
|
this._membershipCache.capture(res);
|
|
1906
1988
|
this._pendingMembershipData = undefined;
|
|
@@ -1908,7 +1990,7 @@ class WGPURayTracePass {
|
|
|
1908
1990
|
const mergedGeometry = res.geometry;
|
|
1909
1991
|
const materials = res.materials;
|
|
1910
1992
|
const isEmpty = meshes.length === 0 || res.instances.length === 0;
|
|
1911
|
-
const tlas =
|
|
1993
|
+
const tlas = buildWebTLAS(res.instances, res.blases);
|
|
1912
1994
|
this._tlas = tlas;
|
|
1913
1995
|
this._uploadBVH(tlas, res.blases);
|
|
1914
1996
|
const materialData = (this._materialData = this._createMaterialData(materials, this._analyticLights, {
|
|
@@ -1918,13 +2000,23 @@ class WGPURayTracePass {
|
|
|
1918
2000
|
}));
|
|
1919
2001
|
this._emissiveTriangles = this._emissiveCache.collect(res.emissiveBindings, materials);
|
|
1920
2002
|
this._needsUpdateLightSamplingData = true;
|
|
1921
|
-
|
|
2003
|
+
// Displacement geometry and its CPU BVH bounds must use the same normal.
|
|
2004
|
+
// Preserve f32 normals in these scenes, avoiding quantization outside bounds.
|
|
2005
|
+
const attributeLayout = compactVertexLayout(res.geometries, materials.some(m => !!m.displacementMap));
|
|
1922
2006
|
const { stride, offsets } = attributeLayout;
|
|
1923
|
-
const
|
|
1924
|
-
|
|
2007
|
+
const vertexWords = res.geometries.reduce((sum, g) => sum + g.vertexCount, 0) * stride;
|
|
2008
|
+
const materialWords = attributeLayout.constants.HAS_TRIANGLE_MATERIAL ? this._bvhDataBytes / 16 : 0;
|
|
2009
|
+
const attrBufferData = new Uint32Array(vertexWords + materialWords);
|
|
2010
|
+
attributeLayout.constants.MATERIALINDEX_OFF = vertexWords;
|
|
2011
|
+
for (const geometry of res.geometries) {
|
|
2012
|
+
const region = res.geometryRegions.get(geometry);
|
|
2013
|
+
packCompactVertices(geometry, attrBufferData, stride, offsets, 0, geometry.vertexCount, region.vertexOffset, false, !!attributeLayout.constants.COLOR_FLOAT, !!attributeLayout.constants.NORMAL_FLOAT);
|
|
2014
|
+
}
|
|
1925
2015
|
this._attributeData = attrBufferData;
|
|
1926
2016
|
this._attributeStride = stride;
|
|
1927
2017
|
this._attributeOffsets = offsets;
|
|
2018
|
+
Object.assign(this._constants, attributeLayout.constants);
|
|
2019
|
+
this._packTriangleMaterials(res, tlas);
|
|
1928
2020
|
this._attrBuffers = this._updateGPUBuffer('Attributes', this._attrBuffers, attrBufferData);
|
|
1929
2021
|
this._materialsBuffer = this._updateGPUBuffer('Materials', this._materialsBuffer, materialData.getBufferArray(),
|
|
1930
2022
|
// WGSL requires a runtime array binding to contain at least one
|
|
@@ -1971,11 +2063,47 @@ class WGPURayTracePass {
|
|
|
1971
2063
|
if (this._bindless)
|
|
1972
2064
|
this._constants.NUM_MAPS = 20;
|
|
1973
2065
|
}
|
|
2066
|
+
_packTriangleMaterials(res, tlas) {
|
|
2067
|
+
if (!this._constants.HAS_TRIANGLE_MATERIAL)
|
|
2068
|
+
return;
|
|
2069
|
+
let offset = Number(this._constants.MATERIALINDEX_OFF) + tlas.buffer.byteLength / 16;
|
|
2070
|
+
res.geometries.forEach((g, i) => {
|
|
2071
|
+
packTriangleMaterials(g, res.geometryRegions.get(g).materialIndices, res.blases[i].bvh.buffer, this._attributeData, offset);
|
|
2072
|
+
offset += res.blases[i].bvh.buffer.byteLength / 16;
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
_refreshTriangleMaterials(res, tlas) {
|
|
2076
|
+
if (!this._constants.HAS_TRIANGLE_MATERIAL)
|
|
2077
|
+
return;
|
|
2078
|
+
const vertexWords = Number(this._constants.MATERIALINDEX_OFF);
|
|
2079
|
+
const required = vertexWords + this._bvhDataBytes / 16;
|
|
2080
|
+
if (this._attributeData.length !== required) {
|
|
2081
|
+
const next = new Uint32Array(required);
|
|
2082
|
+
next.set(this._attributeData.subarray(0, vertexWords));
|
|
2083
|
+
this._attributeData = next;
|
|
2084
|
+
}
|
|
2085
|
+
this._packTriangleMaterials(res, tlas);
|
|
2086
|
+
if (this._attrBuffers.size < this._attributeData.byteLength) {
|
|
2087
|
+
this._attrBuffers = this._updateGPUBuffer('Attributes', this._attrBuffers, this._attributeData);
|
|
2088
|
+
}
|
|
2089
|
+
else {
|
|
2090
|
+
const first = vertexWords * 4, end = this._attributeData.byteLength, chunk = 64 * 1024 * 1024;
|
|
2091
|
+
for (let offset = first; offset < end; offset += chunk) {
|
|
2092
|
+
this._device.queue.writeBuffer(this._attrBuffers, offset, this._attributeData.buffer, offset, Math.min(chunk, end - offset));
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
1974
2096
|
_updateGeometryData() {
|
|
1975
2097
|
const res = this._preparedMeshData, tlas = this._tlas;
|
|
2098
|
+
// Promote the scene color plane if an edit introduces HDR/negative RGB.
|
|
2099
|
+
if (!this._constants.COLOR_FLOAT && [...this._pendingGeometryUpdates].some(g => g.color?.array.some(value => !(value >= 0 && value <= 1)))) {
|
|
2100
|
+
this._updateMeshData();
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
1976
2103
|
const update = updatePreparedGeometries(res, this._pendingGeometryUpdates);
|
|
1977
|
-
for (const { first, count,
|
|
1978
|
-
|
|
2104
|
+
for (const { first, count, deformationOnly } of update.vertices) {
|
|
2105
|
+
const geometry = res.geometries.find(g => res.geometryRegions.get(g).vertexOffset === first);
|
|
2106
|
+
packCompactVertices(geometry, this._attributeData, this._attributeStride, this._attributeOffsets, 0, count, first, deformationOnly, !!this._constants.COLOR_FLOAT, !!this._constants.NORMAL_FLOAT);
|
|
1979
2107
|
const offset = first * this._attributeStride * 4, size = count * this._attributeStride * 4;
|
|
1980
2108
|
this._device.queue.writeBuffer(this._attrBuffers, offset, this._attributeData.buffer, offset, size);
|
|
1981
2109
|
}
|
|
@@ -1991,17 +2119,13 @@ class WGPURayTracePass {
|
|
|
1991
2119
|
this._uploadBVH(tlas, res.blases);
|
|
1992
2120
|
}
|
|
1993
2121
|
else {
|
|
1994
|
-
const bytes = new Uint8Array(this._debugBVHBuffer);
|
|
1995
|
-
const ranges = [];
|
|
1996
2122
|
for (const { blas, offset } of update.blases) {
|
|
1997
|
-
|
|
1998
|
-
bytes.set(new Uint8Array(blas.buffer), target);
|
|
1999
|
-
ranges.push({ offset: target, size: blas.buffer.byteLength });
|
|
2000
|
-
}
|
|
2001
|
-
for (const { offset, size } of mergeRefitRanges(ranges)) {
|
|
2002
|
-
this._device.queue.writeBuffer(this._bvhBuffer, offset, this._debugBVHBuffer, offset, size);
|
|
2123
|
+
this._device.queue.writeBuffer(this._bvhBuffer, tlas.buffer.byteLength + offset, blas.buffer);
|
|
2003
2124
|
}
|
|
2004
2125
|
}
|
|
2126
|
+
if (this._constants.HAS_TRIANGLE_MATERIAL && (update.relocated || update.vertices.some(v => v.topologyChanged))) {
|
|
2127
|
+
this._refreshTriangleMaterials(res, tlas);
|
|
2128
|
+
}
|
|
2005
2129
|
const bits = { bvh2: 1, bvh4: 2, 'bvh-gpu': 4, cwbvh: 8 };
|
|
2006
2130
|
this._blasLayoutMask = res.blases.reduce((mask, b) => mask | bits[b.bvh.layout ?? 'bvh2'], 0);
|
|
2007
2131
|
const stacks = getTraversalStackSizes(tlas, res.blases);
|
|
@@ -2061,9 +2185,10 @@ class WGPURayTracePass {
|
|
|
2061
2185
|
if (pending)
|
|
2062
2186
|
this._residentPreparedMeshData = res;
|
|
2063
2187
|
this._pendingMembershipData = undefined;
|
|
2064
|
-
const tlas =
|
|
2188
|
+
const tlas = buildWebTLAS(instances, res.blases);
|
|
2065
2189
|
this._tlas = tlas;
|
|
2066
2190
|
this._uploadBVH(tlas, res.blases);
|
|
2191
|
+
this._refreshTriangleMaterials(res, tlas);
|
|
2067
2192
|
this._emissiveTriangles = this._emissiveCache.collect(emissiveBindings, res.materials);
|
|
2068
2193
|
this._needsUpdateLightSamplingData = true;
|
|
2069
2194
|
this._rtUniform.views.isEmpty[0] = +(instances.length === 0);
|
|
@@ -2097,8 +2222,9 @@ class WGPURayTracePass {
|
|
|
2097
2222
|
const previousInstances = res.instances;
|
|
2098
2223
|
res.instances = updateMeshInstanceTransforms(res.instanceBindings, incremental ? res.instances : undefined, incremental ? dirtyIndices : undefined);
|
|
2099
2224
|
if (!sameInstanceMembership(previousInstances, res.instances)) {
|
|
2100
|
-
this._tlas =
|
|
2225
|
+
this._tlas = buildWebTLAS(res.instances, res.blases);
|
|
2101
2226
|
this._uploadBVH(this._tlas, res.blases);
|
|
2227
|
+
this._refreshTriangleMaterials(res, this._tlas);
|
|
2102
2228
|
this._emissiveTriangles = this._emissiveCache.collect(res.emissiveBindings, res.materials);
|
|
2103
2229
|
this._needsUpdateLightSamplingData = true;
|
|
2104
2230
|
this._rtUniform.views.isEmpty[0] = +(res.instances.length === 0);
|
|
@@ -2107,16 +2233,12 @@ class WGPURayTracePass {
|
|
|
2107
2233
|
return;
|
|
2108
2234
|
}
|
|
2109
2235
|
const ranges = refitTLAS(tlas, res.instances, res.blases, incremental ? dirtyIndices : undefined);
|
|
2110
|
-
const tlasData = new Float32Array(tlas.buffer);
|
|
2111
2236
|
for (const { offset, size } of ranges.tlasRanges) {
|
|
2112
2237
|
this._device.queue.writeBuffer(this._bvhBuffer, offset, tlas.buffer, offset, size);
|
|
2113
2238
|
}
|
|
2114
2239
|
for (const { offset, size } of ranges.instanceRanges) {
|
|
2115
2240
|
this._device.queue.writeBuffer(this._instancesBuffer, offset, tlas.instancesBuffer, offset, size);
|
|
2116
2241
|
}
|
|
2117
|
-
if (this._debugBVHBuffer) {
|
|
2118
|
-
new Float32Array(this._debugBVHBuffer).set(tlasData);
|
|
2119
|
-
}
|
|
2120
2242
|
if (!incremental ||
|
|
2121
2243
|
res.emissiveBindings.some(({ mesh }) => this._dirtyTransformMeshes.has(mesh))) {
|
|
2122
2244
|
this._emissiveTriangles = this._emissiveCache.collect(res.emissiveBindings, res.materials);
|
|
@@ -2254,7 +2376,8 @@ class WGPURayTracePass {
|
|
|
2254
2376
|
const viewProjectionInvMat = this._viewProjInv;
|
|
2255
2377
|
this._apertureRadius = cameraApertureRadius(camera);
|
|
2256
2378
|
this._focusDistance = camera.focusDistance;
|
|
2257
|
-
this.
|
|
2379
|
+
mat4.invert(this._projectionInv, projection);
|
|
2380
|
+
mat4.mul(viewProjectionInvMat, camera.transform, this._projectionInv);
|
|
2258
2381
|
mat4.copy(this._cameraWorld, camera.transform);
|
|
2259
2382
|
}
|
|
2260
2383
|
cameraChanged(camera) {
|
|
@@ -2310,7 +2433,7 @@ class WGPURayTracePass {
|
|
|
2310
2433
|
const arr = this._rtUniform.views.jitter;
|
|
2311
2434
|
arr[0] = x;
|
|
2312
2435
|
arr[1] = y;
|
|
2313
|
-
this._device.queue.writeBuffer(this._uniforms.cameraUniform, 0, packCameraUniform(this._viewProjInv, this._cameraWorld, this._apertureRadius, this._focusDistance));
|
|
2436
|
+
this._device.queue.writeBuffer(this._uniforms.cameraUniform, 0, packCameraUniform(this._viewProjInv, this._cameraWorld, this._apertureRadius, this._focusDistance, this._projectionInv));
|
|
2314
2437
|
}
|
|
2315
2438
|
setSampleTiles(columns, rows, tileX, tileY) {
|
|
2316
2439
|
const arr = this._rtUniform.views.scaleOffset;
|