@driftengine/core 3.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +9 -0
- package/dist/behavior/behaviorTree.d.ts +140 -0
- package/dist/behavior/behaviorTree.js +289 -0
- package/dist/build/shaderComments.d.ts +64 -0
- package/dist/build/shaderComments.js +0 -0
- package/dist/cinematic/player.d.ts +80 -0
- package/dist/cinematic/player.js +184 -0
- package/dist/cinematic/script.d.ts +63 -0
- package/dist/cinematic/script.js +141 -0
- package/dist/core/bootGate.d.ts +37 -0
- package/dist/core/bootGate.js +47 -0
- package/dist/core/loadTracker.d.ts +78 -0
- package/dist/core/loadTracker.js +106 -0
- package/dist/core/loop.d.ts +118 -0
- package/dist/core/loop.js +84 -0
- package/dist/core/messageQueue.d.ts +61 -0
- package/dist/core/messageQueue.js +104 -0
- package/dist/core/onceSet.d.ts +27 -0
- package/dist/core/onceSet.js +62 -0
- package/dist/core/preferences.d.ts +47 -0
- package/dist/core/preferences.js +140 -0
- package/dist/core/remoteSave.d.ts +154 -0
- package/dist/core/remoteSave.js +249 -0
- package/dist/core/rng.d.ts +64 -0
- package/dist/core/rng.js +72 -0
- package/dist/core/stepBudget.d.ts +91 -0
- package/dist/core/stepBudget.js +105 -0
- package/dist/core/storage.d.ts +52 -0
- package/dist/core/storage.js +85 -0
- package/dist/core/tickTrace.d.ts +72 -0
- package/dist/core/tickTrace.js +102 -0
- package/dist/core/timeCurve.d.ts +83 -0
- package/dist/core/timeCurve.js +107 -0
- package/dist/core/withDefaults.d.ts +21 -0
- package/dist/core/withDefaults.js +29 -0
- package/dist/dev/contactProbe.d.ts +41 -0
- package/dist/dev/contactProbe.js +58 -0
- package/dist/dev/fpsMeter.d.ts +45 -0
- package/dist/dev/fpsMeter.js +86 -0
- package/dist/environment/celestialClock.d.ts +141 -0
- package/dist/environment/celestialClock.js +262 -0
- package/dist/geometry/decal.d.ts +61 -0
- package/dist/geometry/decal.js +178 -0
- package/dist/geometry/filmPatch.d.ts +35 -0
- package/dist/geometry/filmPatch.js +112 -0
- package/dist/geometry/growable.d.ts +70 -0
- package/dist/geometry/growable.js +167 -0
- package/dist/geometry/lightVolume.d.ts +76 -0
- package/dist/geometry/lightVolume.js +65 -0
- package/dist/geometry/meshBuilder.d.ts +426 -0
- package/dist/geometry/meshBuilder.js +1184 -0
- package/dist/geometry/pixelFont.d.ts +59 -0
- package/dist/geometry/pixelFont.js +179 -0
- package/dist/geometry/ribbon.d.ts +101 -0
- package/dist/geometry/ribbon.js +546 -0
- package/dist/geometry/shellFill.d.ts +101 -0
- package/dist/geometry/shellFill.js +203 -0
- package/dist/geometry/spline.d.ts +162 -0
- package/dist/geometry/spline.js +527 -0
- package/dist/geometry/tangents.d.ts +30 -0
- package/dist/geometry/tangents.js +142 -0
- package/dist/geometry/textMesh.d.ts +51 -0
- package/dist/geometry/textMesh.js +57 -0
- package/dist/geometry/treeBuilder.d.ts +37 -0
- package/dist/geometry/treeBuilder.js +56 -0
- package/dist/host/display.d.ts +135 -0
- package/dist/host/display.js +114 -0
- package/dist/host/files.d.ts +25 -0
- package/dist/host/files.js +44 -0
- package/dist/host/lifecycle.d.ts +45 -0
- package/dist/host/lifecycle.js +28 -0
- package/dist/host/platformServices.d.ts +23 -0
- package/dist/host/platformServices.js +1 -0
- package/dist/host/screen.d.ts +49 -0
- package/dist/host/screen.js +90 -0
- package/dist/index.d.ts +289 -0
- package/dist/index.js +320 -0
- package/dist/input/actionMap.d.ts +181 -0
- package/dist/input/actionMap.js +314 -0
- package/dist/input/activeDevice.d.ts +55 -0
- package/dist/input/activeDevice.js +83 -0
- package/dist/input/gamepadIdentity.d.ts +43 -0
- package/dist/input/gamepadIdentity.js +108 -0
- package/dist/input/gamepadMapping.d.ts +56 -0
- package/dist/input/gamepadMapping.js +91 -0
- package/dist/input/input.d.ts +281 -0
- package/dist/input/input.js +703 -0
- package/dist/input/inputHarness.d.ts +42 -0
- package/dist/input/inputHarness.js +193 -0
- package/dist/input/rightGesture.d.ts +57 -0
- package/dist/input/rightGesture.js +49 -0
- package/dist/input/rumble.d.ts +71 -0
- package/dist/input/rumble.js +119 -0
- package/dist/input/touchControls.d.ts +138 -0
- package/dist/input/touchControls.js +352 -0
- package/dist/input/typingTarget.d.ts +6 -0
- package/dist/input/typingTarget.js +27 -0
- package/dist/math/bounds.d.ts +61 -0
- package/dist/math/bounds.js +121 -0
- package/dist/math/color.d.ts +8 -0
- package/dist/math/color.js +35 -0
- package/dist/math/exact.d.ts +66 -0
- package/dist/math/exact.js +262 -0
- package/dist/math/frustum.d.ts +44 -0
- package/dist/math/frustum.js +90 -0
- package/dist/math/intersect.d.ts +76 -0
- package/dist/math/intersect.js +185 -0
- package/dist/math/scalar.d.ts +51 -0
- package/dist/math/scalar.js +99 -0
- package/dist/math/spring.d.ts +59 -0
- package/dist/math/spring.js +88 -0
- package/dist/nav/navGraph.d.ts +71 -0
- package/dist/nav/navGraph.js +111 -0
- package/dist/nav/navPath.d.ts +93 -0
- package/dist/nav/navPath.js +162 -0
- package/dist/nav/navSearch.d.ts +74 -0
- package/dist/nav/navSearch.js +198 -0
- package/dist/physics/boxSurface.d.ts +48 -0
- package/dist/physics/boxSurface.js +73 -0
- package/dist/physics/colliderSurface.d.ts +46 -0
- package/dist/physics/colliderSurface.js +146 -0
- package/dist/physics/compositeSurface.d.ts +33 -0
- package/dist/physics/compositeSurface.js +108 -0
- package/dist/physics/heightSurface.d.ts +103 -0
- package/dist/physics/heightSurface.js +153 -0
- package/dist/physics/ribbonSurface.d.ts +239 -0
- package/dist/physics/ribbonSurface.js +522 -0
- package/dist/render/ambientOcclusionPass.d.ts +53 -0
- package/dist/render/ambientOcclusionPass.js +179 -0
- package/dist/render/areaLights.d.ts +116 -0
- package/dist/render/areaLights.js +91 -0
- package/dist/render/areaShadowSet.d.ts +184 -0
- package/dist/render/areaShadowSet.js +277 -0
- package/dist/render/atmosphere.d.ts +94 -0
- package/dist/render/atmosphere.js +91 -0
- package/dist/render/backend/api.d.ts +496 -0
- package/dist/render/backend/api.js +1 -0
- package/dist/render/backend/budget.d.ts +82 -0
- package/dist/render/backend/budget.js +99 -0
- package/dist/render/backend/createRenderer.d.ts +135 -0
- package/dist/render/backend/createRenderer.js +201 -0
- package/dist/render/backend/deadline.d.ts +24 -0
- package/dist/render/backend/deadline.js +38 -0
- package/dist/render/backend/probe.d.ts +30 -0
- package/dist/render/backend/probe.js +129 -0
- package/dist/render/backend/select.d.ts +70 -0
- package/dist/render/backend/select.js +249 -0
- package/dist/render/backend/timer.d.ts +50 -0
- package/dist/render/backend/timer.js +1 -0
- package/dist/render/backend/webgl2/instanced.d.ts +21 -0
- package/dist/render/backend/webgl2/instanced.js +42 -0
- package/dist/render/backend/webgl2/morphTexture.d.ts +21 -0
- package/dist/render/backend/webgl2/morphTexture.js +55 -0
- package/dist/render/backend/webgl2/renderer.d.ts +3027 -0
- package/dist/render/backend/webgl2/renderer.js +6041 -0
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +32 -0
- package/dist/render/backend/webgl2/skinPaletteTexture.js +68 -0
- package/dist/render/backend/webgpu/boltPass.d.ts +42 -0
- package/dist/render/backend/webgpu/boltPass.js +160 -0
- package/dist/render/backend/webgpu/buffers.d.ts +159 -0
- package/dist/render/backend/webgpu/buffers.js +402 -0
- package/dist/render/backend/webgpu/causticsPass.d.ts +36 -0
- package/dist/render/backend/webgpu/causticsPass.js +138 -0
- package/dist/render/backend/webgpu/clusterBinner.d.ts +51 -0
- package/dist/render/backend/webgpu/clusterBinner.js +206 -0
- package/dist/render/backend/webgpu/depthPass.d.ts +114 -0
- package/dist/render/backend/webgpu/depthPass.js +228 -0
- package/dist/render/backend/webgpu/device.d.ts +52 -0
- package/dist/render/backend/webgpu/device.js +121 -0
- package/dist/render/backend/webgpu/drawCommand.d.ts +43 -0
- package/dist/render/backend/webgpu/drawCommand.js +54 -0
- package/dist/render/backend/webgpu/environmentTexels.d.ts +28 -0
- package/dist/render/backend/webgpu/environmentTexels.js +79 -0
- package/dist/render/backend/webgpu/filmPass.d.ts +29 -0
- package/dist/render/backend/webgpu/filmPass.js +97 -0
- package/dist/render/backend/webgpu/flatPass.d.ts +213 -0
- package/dist/render/backend/webgpu/flatPass.js +482 -0
- package/dist/render/backend/webgpu/flockPass.d.ts +34 -0
- package/dist/render/backend/webgpu/flockPass.js +129 -0
- package/dist/render/backend/webgpu/gpuTimestamps.d.ts +94 -0
- package/dist/render/backend/webgpu/gpuTimestamps.js +213 -0
- package/dist/render/backend/webgpu/insetPass.d.ts +19 -0
- package/dist/render/backend/webgpu/insetPass.js +108 -0
- package/dist/render/backend/webgpu/instanced.d.ts +27 -0
- package/dist/render/backend/webgpu/instanced.js +49 -0
- package/dist/render/backend/webgpu/lightVolumePass.d.ts +75 -0
- package/dist/render/backend/webgpu/lightVolumePass.js +154 -0
- package/dist/render/backend/webgpu/linePass.d.ts +90 -0
- package/dist/render/backend/webgpu/linePass.js +220 -0
- package/dist/render/backend/webgpu/morphTexture.d.ts +18 -0
- package/dist/render/backend/webgpu/morphTexture.js +51 -0
- package/dist/render/backend/webgpu/panelPass.d.ts +37 -0
- package/dist/render/backend/webgpu/panelPass.js +114 -0
- package/dist/render/backend/webgpu/particlePass.d.ts +89 -0
- package/dist/render/backend/webgpu/particlePass.js +280 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +93 -0
- package/dist/render/backend/webgpu/pipelineCache.js +140 -0
- package/dist/render/backend/webgpu/plumePass.d.ts +69 -0
- package/dist/render/backend/webgpu/plumePass.js +213 -0
- package/dist/render/backend/webgpu/pointShadowPass.d.ts +88 -0
- package/dist/render/backend/webgpu/pointShadowPass.js +280 -0
- package/dist/render/backend/webgpu/postPass.d.ts +342 -0
- package/dist/render/backend/webgpu/postPass.js +366 -0
- package/dist/render/backend/webgpu/probePass.d.ts +108 -0
- package/dist/render/backend/webgpu/probePass.js +188 -0
- package/dist/render/backend/webgpu/reflectionPass.d.ts +29 -0
- package/dist/render/backend/webgpu/reflectionPass.js +87 -0
- package/dist/render/backend/webgpu/renderer.d.ts +3082 -0
- package/dist/render/backend/webgpu/renderer.js +10911 -0
- package/dist/render/backend/webgpu/scatterPass.d.ts +95 -0
- package/dist/render/backend/webgpu/scatterPass.js +266 -0
- package/dist/render/backend/webgpu/sdfTextPass.d.ts +86 -0
- package/dist/render/backend/webgpu/sdfTextPass.js +190 -0
- package/dist/render/backend/webgpu/shaderModules.d.ts +9 -0
- package/dist/render/backend/webgpu/shaderModules.js +45 -0
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +23 -0
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.js +208 -0
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +67 -0
- package/dist/render/backend/webgpu/skinPaletteRing.js +97 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +17 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +68 -0
- package/dist/render/backend/webgpu/skyPass.d.ts +102 -0
- package/dist/render/backend/webgpu/skyPass.js +70 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +41 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.js +228 -0
- package/dist/render/backend/webgpu/textPass.d.ts +73 -0
- package/dist/render/backend/webgpu/textPass.js +190 -0
- package/dist/render/backend/webgpu/uniformRing.d.ts +133 -0
- package/dist/render/backend/webgpu/uniformRing.js +208 -0
- package/dist/render/backend/webgpu/waterPass.d.ts +73 -0
- package/dist/render/backend/webgpu/waterPass.js +160 -0
- package/dist/render/backend/webgpu/windStreakPass.d.ts +46 -0
- package/dist/render/backend/webgpu/windStreakPass.js +153 -0
- package/dist/render/billboard.d.ts +27 -0
- package/dist/render/billboard.js +79 -0
- package/dist/render/bloomChain.d.ts +66 -0
- package/dist/render/bloomChain.js +83 -0
- package/dist/render/bloomPass.d.ts +54 -0
- package/dist/render/bloomPass.js +219 -0
- package/dist/render/boltBatch.d.ts +39 -0
- package/dist/render/boltBatch.js +121 -0
- package/dist/render/boltPool.d.ts +135 -0
- package/dist/render/boltPool.js +259 -0
- package/dist/render/boom.d.ts +46 -0
- package/dist/render/boom.js +81 -0
- package/dist/render/camera.d.ts +119 -0
- package/dist/render/camera.js +304 -0
- package/dist/render/causticsRenderer.d.ts +63 -0
- package/dist/render/causticsRenderer.js +119 -0
- package/dist/render/cinematicCamera.d.ts +102 -0
- package/dist/render/cinematicCamera.js +227 -0
- package/dist/render/clusteredLights.d.ts +260 -0
- package/dist/render/clusteredLights.js +479 -0
- package/dist/render/colourGrade.d.ts +62 -0
- package/dist/render/colourGrade.js +91 -0
- package/dist/render/compute.d.ts +74 -0
- package/dist/render/compute.js +8 -0
- package/dist/render/contextLoss.d.ts +32 -0
- package/dist/render/contextLoss.js +46 -0
- package/dist/render/debugLines.d.ts +75 -0
- package/dist/render/debugLines.js +281 -0
- package/dist/render/decalPass.d.ts +34 -0
- package/dist/render/decalPass.js +103 -0
- package/dist/render/decalProjector.d.ts +140 -0
- package/dist/render/decalProjector.js +282 -0
- package/dist/render/decalQueue.d.ts +53 -0
- package/dist/render/decalQueue.js +87 -0
- package/dist/render/depthConvention.d.ts +314 -0
- package/dist/render/depthConvention.js +346 -0
- package/dist/render/drawingBuffer.d.ts +52 -0
- package/dist/render/drawingBuffer.js +67 -0
- package/dist/render/emptyTexture.d.ts +60 -0
- package/dist/render/emptyTexture.js +103 -0
- package/dist/render/envProbeArray.d.ts +85 -0
- package/dist/render/envProbeArray.js +164 -0
- package/dist/render/equirectToCube.d.ts +54 -0
- package/dist/render/equirectToCube.js +123 -0
- package/dist/render/flockGeometry.d.ts +23 -0
- package/dist/render/flockGeometry.js +43 -0
- package/dist/render/flockRenderer.d.ts +37 -0
- package/dist/render/flockRenderer.js +70 -0
- package/dist/render/frame/arena.d.ts +32 -0
- package/dist/render/frame/arena.js +65 -0
- package/dist/render/frame/index.d.ts +18 -0
- package/dist/render/frame/index.js +4 -0
- package/dist/render/frame/replay.d.ts +34 -0
- package/dist/render/frame/replay.js +48 -0
- package/dist/render/frame/resources.d.ts +25 -0
- package/dist/render/frame/resources.js +55 -0
- package/dist/render/frame/schedule.d.ts +37 -0
- package/dist/render/frame/schedule.js +61 -0
- package/dist/render/frameView.d.ts +19 -0
- package/dist/render/frameView.js +1 -0
- package/dist/render/gizmo.d.ts +236 -0
- package/dist/render/gizmo.js +727 -0
- package/dist/render/globalMedium.d.ts +124 -0
- package/dist/render/globalMedium.js +100 -0
- package/dist/render/globalMediumPass.d.ts +101 -0
- package/dist/render/globalMediumPass.js +250 -0
- package/dist/render/gpuCapability.d.ts +111 -0
- package/dist/render/gpuCapability.js +194 -0
- package/dist/render/gpuTimer.d.ts +87 -0
- package/dist/render/gpuTimer.js +145 -0
- package/dist/render/halfFloat.d.ts +4 -0
- package/dist/render/halfFloat.js +38 -0
- package/dist/render/handleRegistry.d.ts +54 -0
- package/dist/render/handleRegistry.js +84 -0
- package/dist/render/iesProfile.d.ts +64 -0
- package/dist/render/iesProfile.js +179 -0
- package/dist/render/imageTexels.d.ts +50 -0
- package/dist/render/imageTexels.js +91 -0
- package/dist/render/instancedMesh.d.ts +48 -0
- package/dist/render/instancedMesh.js +127 -0
- package/dist/render/instances.d.ts +69 -0
- package/dist/render/instances.js +52 -0
- package/dist/render/lightBudget.d.ts +397 -0
- package/dist/render/lightBudget.js +524 -0
- package/dist/render/lightMatrix.d.ts +3 -0
- package/dist/render/lightMatrix.js +45 -0
- package/dist/render/lightVolumeDraw.d.ts +132 -0
- package/dist/render/lightVolumeDraw.js +181 -0
- package/dist/render/lineBatch.d.ts +60 -0
- package/dist/render/lineBatch.js +160 -0
- package/dist/render/linePoints.d.ts +33 -0
- package/dist/render/linePoints.js +46 -0
- package/dist/render/livePointShadowSet.d.ts +72 -0
- package/dist/render/livePointShadowSet.js +258 -0
- package/dist/render/lod.d.ts +35 -0
- package/dist/render/lod.js +65 -0
- package/dist/render/mesh.d.ts +177 -0
- package/dist/render/mesh.js +466 -0
- package/dist/render/occlusion.d.ts +81 -0
- package/dist/render/occlusion.js +378 -0
- package/dist/render/oitPass.d.ts +67 -0
- package/dist/render/oitPass.js +213 -0
- package/dist/render/orderIndependent.d.ts +92 -0
- package/dist/render/orderIndependent.js +108 -0
- package/dist/render/particleBatch.d.ts +140 -0
- package/dist/render/particleBatch.js +186 -0
- package/dist/render/particleMaterial.d.ts +54 -0
- package/dist/render/particleMaterial.js +42 -0
- package/dist/render/particlePool.d.ts +124 -0
- package/dist/render/particlePool.js +182 -0
- package/dist/render/pass.d.ts +195 -0
- package/dist/render/pass.js +9 -0
- package/dist/render/passTarget.d.ts +86 -0
- package/dist/render/passTarget.js +121 -0
- package/dist/render/pickable.d.ts +31 -0
- package/dist/render/pickable.js +172 -0
- package/dist/render/planarReflection.d.ts +59 -0
- package/dist/render/planarReflection.js +194 -0
- package/dist/render/planarReflectionDraw.d.ts +31 -0
- package/dist/render/planarReflectionDraw.js +65 -0
- package/dist/render/plumeGeometry.d.ts +25 -0
- package/dist/render/plumeGeometry.js +61 -0
- package/dist/render/plumeMaterial.d.ts +31 -0
- package/dist/render/plumeMaterial.js +64 -0
- package/dist/render/plumeRenderer.d.ts +96 -0
- package/dist/render/plumeRenderer.js +185 -0
- package/dist/render/pointLightSelection.d.ts +175 -0
- package/dist/render/pointLightSelection.js +301 -0
- package/dist/render/pointShadowArray.d.ts +95 -0
- package/dist/render/pointShadowArray.js +219 -0
- package/dist/render/pointShadowBudget.d.ts +118 -0
- package/dist/render/pointShadowBudget.js +221 -0
- package/dist/render/pointShadowImage.d.ts +265 -0
- package/dist/render/pointShadowImage.js +339 -0
- package/dist/render/pointShadowMap.d.ts +93 -0
- package/dist/render/pointShadowMap.js +167 -0
- package/dist/render/pointShadowSystem.d.ts +195 -0
- package/dist/render/pointShadowSystem.js +336 -0
- package/dist/render/prefilterEnvMap.d.ts +124 -0
- package/dist/render/prefilterEnvMap.js +146 -0
- package/dist/render/prefilterPass.d.ts +44 -0
- package/dist/render/prefilterPass.js +98 -0
- package/dist/render/probeGrid.d.ts +122 -0
- package/dist/render/probeGrid.js +174 -0
- package/dist/render/rainField.d.ts +99 -0
- package/dist/render/rainField.js +168 -0
- package/dist/render/reflectionProbe.d.ts +188 -0
- package/dist/render/reflectionProbe.js +437 -0
- package/dist/render/renderQuality.d.ts +699 -0
- package/dist/render/renderQuality.js +293 -0
- package/dist/render/rendererHarness.d.ts +39 -0
- package/dist/render/rendererHarness.js +185 -0
- package/dist/render/resolutionGovernor.d.ts +107 -0
- package/dist/render/resolutionGovernor.js +144 -0
- package/dist/render/scatterDeform.d.ts +17 -0
- package/dist/render/scatterDeform.js +46 -0
- package/dist/render/sceneTarget.d.ts +288 -0
- package/dist/render/sceneTarget.js +856 -0
- package/dist/render/screenSpaceReflection.d.ts +233 -0
- package/dist/render/screenSpaceReflection.js +415 -0
- package/dist/render/sdfFont.d.ts +77 -0
- package/dist/render/sdfFont.js +86 -0
- package/dist/render/sdfTextLayout.d.ts +46 -0
- package/dist/render/sdfTextLayout.js +145 -0
- package/dist/render/sdfTextRenderer.d.ts +75 -0
- package/dist/render/sdfTextRenderer.js +194 -0
- package/dist/render/seaState.d.ts +25 -0
- package/dist/render/seaState.js +34 -0
- package/dist/render/segmentQuads.d.ts +29 -0
- package/dist/render/segmentQuads.js +75 -0
- package/dist/render/shader.d.ts +5 -0
- package/dist/render/shader.js +172 -0
- package/dist/render/shaders/ambientOcclusion.d.ts +45 -0
- package/dist/render/shaders/ambientOcclusion.js +352 -0
- package/dist/render/shaders/arcane.d.ts +19 -0
- package/dist/render/shaders/arcane.js +102 -0
- package/dist/render/shaders/bloom.d.ts +70 -0
- package/dist/render/shaders/bloom.js +227 -0
- package/dist/render/shaders/bolt.d.ts +17 -0
- package/dist/render/shaders/bolt.js +161 -0
- package/dist/render/shaders/caustics.d.ts +38 -0
- package/dist/render/shaders/caustics.js +167 -0
- package/dist/render/shaders/conditionals.d.ts +21 -0
- package/dist/render/shaders/conditionals.js +55 -0
- package/dist/render/shaders/decalProject.d.ts +25 -0
- package/dist/render/shaders/decalProject.js +125 -0
- package/dist/render/shaders/depth.d.ts +14 -0
- package/dist/render/shaders/depth.js +114 -0
- package/dist/render/shaders/depthOfField.d.ts +41 -0
- package/dist/render/shaders/depthOfField.js +139 -0
- package/dist/render/shaders/film.d.ts +15 -0
- package/dist/render/shaders/film.js +283 -0
- package/dist/render/shaders/fire.d.ts +12 -0
- package/dist/render/shaders/fire.js +178 -0
- package/dist/render/shaders/flat/directionalShadow.d.ts +1 -0
- package/dist/render/shaders/flat/directionalShadow.js +195 -0
- package/dist/render/shaders/flat/index.d.ts +135 -0
- package/dist/render/shaders/flat/index.js +387 -0
- package/dist/render/shaders/flat/lobes.d.ts +1 -0
- package/dist/render/shaders/flat/lobes.js +398 -0
- package/dist/render/shaders/flat/main.d.ts +2 -0
- package/dist/render/shaders/flat/main.js +1630 -0
- package/dist/render/shaders/flat/pointShadow.d.ts +1 -0
- package/dist/render/shaders/flat/pointShadow.js +322 -0
- package/dist/render/shaders/flat/preamble.d.ts +15 -0
- package/dist/render/shaders/flat/preamble.js +864 -0
- package/dist/render/shaders/flat/probeGrid.d.ts +21 -0
- package/dist/render/shaders/flat/probeGrid.js +151 -0
- package/dist/render/shaders/flat/surface.d.ts +2 -0
- package/dist/render/shaders/flat/surface.js +40 -0
- package/dist/render/shaders/flock.d.ts +11 -0
- package/dist/render/shaders/flock.js +102 -0
- package/dist/render/shaders/fog.d.ts +37 -0
- package/dist/render/shaders/fog.js +98 -0
- package/dist/render/shaders/fullscreen.d.ts +16 -0
- package/dist/render/shaders/fullscreen.js +27 -0
- package/dist/render/shaders/generated/ambientOcclusion.wgsl.d.ts +65 -0
- package/dist/render/shaders/generated/ambientOcclusion.wgsl.js +71 -0
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +90 -0
- package/dist/render/shaders/generated/arcane.wgsl.js +96 -0
- package/dist/render/shaders/generated/bloom.wgsl.d.ts +69 -0
- package/dist/render/shaders/generated/bloom.wgsl.js +75 -0
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +118 -0
- package/dist/render/shaders/generated/bolt.wgsl.js +124 -0
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +118 -0
- package/dist/render/shaders/generated/caustics.wgsl.js +124 -0
- package/dist/render/shaders/generated/decalProject.wgsl.d.ts +61 -0
- package/dist/render/shaders/generated/decalProject.wgsl.js +67 -0
- package/dist/render/shaders/generated/depth.wgsl.d.ts +131 -0
- package/dist/render/shaders/generated/depth.wgsl.js +137 -0
- package/dist/render/shaders/generated/film.wgsl.d.ts +134 -0
- package/dist/render/shaders/generated/film.wgsl.js +140 -0
- package/dist/render/shaders/generated/fire.wgsl.d.ts +128 -0
- package/dist/render/shaders/generated/fire.wgsl.js +134 -0
- package/dist/render/shaders/generated/flat.wgsl.d.ts +9163 -0
- package/dist/render/shaders/generated/flat.wgsl.js +9192 -0
- package/dist/render/shaders/generated/flock.wgsl.d.ts +73 -0
- package/dist/render/shaders/generated/flock.wgsl.js +79 -0
- package/dist/render/shaders/generated/fullscreen.wgsl.d.ts +12 -0
- package/dist/render/shaders/generated/fullscreen.wgsl.js +18 -0
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +130 -0
- package/dist/render/shaders/generated/globalMedium.wgsl.js +136 -0
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +230 -0
- package/dist/render/shaders/generated/lightVolume.wgsl.js +239 -0
- package/dist/render/shaders/generated/line.wgsl.d.ts +128 -0
- package/dist/render/shaders/generated/line.wgsl.js +134 -0
- package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +51 -0
- package/dist/render/shaders/generated/octahedralResolve.wgsl.js +57 -0
- package/dist/render/shaders/generated/oitResolve.wgsl.d.ts +23 -0
- package/dist/render/shaders/generated/oitResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/panel.wgsl.d.ts +48 -0
- package/dist/render/shaders/generated/panel.wgsl.js +54 -0
- package/dist/render/shaders/generated/particle.wgsl.d.ts +332 -0
- package/dist/render/shaders/generated/particle.wgsl.js +338 -0
- package/dist/render/shaders/generated/prefilter.wgsl.d.ts +61 -0
- package/dist/render/shaders/generated/prefilter.wgsl.js +67 -0
- package/dist/render/shaders/generated/rush.wgsl.d.ts +131 -0
- package/dist/render/shaders/generated/rush.wgsl.js +137 -0
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +195 -0
- package/dist/render/shaders/generated/scatter.wgsl.js +201 -0
- package/dist/render/shaders/generated/sdfText.wgsl.d.ts +69 -0
- package/dist/render/shaders/generated/sdfText.wgsl.js +75 -0
- package/dist/render/shaders/generated/sky.wgsl.d.ts +100 -0
- package/dist/render/shaders/generated/sky.wgsl.js +106 -0
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +85 -0
- package/dist/render/shaders/generated/smoke.wgsl.js +91 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +18 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.js +24 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +86 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +92 -0
- package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +46 -0
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +52 -0
- package/dist/render/shaders/generated/text.wgsl.d.ts +98 -0
- package/dist/render/shaders/generated/text.wgsl.js +104 -0
- package/dist/render/shaders/generated/water.wgsl.d.ts +247 -0
- package/dist/render/shaders/generated/water.wgsl.js +253 -0
- package/dist/render/shaders/generated/windStreaks.wgsl.d.ts +73 -0
- package/dist/render/shaders/generated/windStreaks.wgsl.js +79 -0
- package/dist/render/shaders/gerstner.d.ts +21 -0
- package/dist/render/shaders/gerstner.js +110 -0
- package/dist/render/shaders/globalMedium.d.ts +56 -0
- package/dist/render/shaders/globalMedium.js +393 -0
- package/dist/render/shaders/lightVolume.d.ts +61 -0
- package/dist/render/shaders/lightVolume.js +527 -0
- package/dist/render/shaders/line.d.ts +18 -0
- package/dist/render/shaders/line.js +122 -0
- package/dist/render/shaders/morph.d.ts +26 -0
- package/dist/render/shaders/morph.js +61 -0
- package/dist/render/shaders/octahedral.d.ts +76 -0
- package/dist/render/shaders/octahedral.js +161 -0
- package/dist/render/shaders/octahedralResolve.d.ts +25 -0
- package/dist/render/shaders/octahedralResolve.js +81 -0
- package/dist/render/shaders/oitResolve.d.ts +17 -0
- package/dist/render/shaders/oitResolve.js +42 -0
- package/dist/render/shaders/outputTransform.d.ts +37 -0
- package/dist/render/shaders/outputTransform.js +106 -0
- package/dist/render/shaders/panel.d.ts +17 -0
- package/dist/render/shaders/panel.js +50 -0
- package/dist/render/shaders/particle.d.ts +82 -0
- package/dist/render/shaders/particle.js +431 -0
- package/dist/render/shaders/prefilter.d.ts +37 -0
- package/dist/render/shaders/prefilter.js +276 -0
- package/dist/render/shaders/rush.d.ts +21 -0
- package/dist/render/shaders/rush.js +355 -0
- package/dist/render/shaders/scatter.d.ts +14 -0
- package/dist/render/shaders/scatter.js +206 -0
- package/dist/render/shaders/sdfText.d.ts +9 -0
- package/dist/render/shaders/sdfText.js +65 -0
- package/dist/render/shaders/skinning.d.ts +17 -0
- package/dist/render/shaders/skinning.js +59 -0
- package/dist/render/shaders/sky.d.ts +10 -0
- package/dist/render/shaders/sky.js +242 -0
- package/dist/render/shaders/smoke.d.ts +8 -0
- package/dist/render/shaders/smoke.js +88 -0
- package/dist/render/shaders/ssrResolve.d.ts +15 -0
- package/dist/render/shaders/ssrResolve.js +28 -0
- package/dist/render/shaders/ssrTrace.d.ts +22 -0
- package/dist/render/shaders/ssrTrace.js +230 -0
- package/dist/render/shaders/tangentFrame.d.ts +17 -0
- package/dist/render/shaders/tangentFrame.js +70 -0
- package/dist/render/shaders/temporalResolve.d.ts +1 -0
- package/dist/render/shaders/temporalResolve.js +150 -0
- package/dist/render/shaders/text.d.ts +17 -0
- package/dist/render/shaders/text.js +155 -0
- package/dist/render/shaders/vertexChannel.d.ts +39 -0
- package/dist/render/shaders/vertexChannel.js +69 -0
- package/dist/render/shaders/water.d.ts +18 -0
- package/dist/render/shaders/water.js +354 -0
- package/dist/render/shaders/windStreaks.d.ts +14 -0
- package/dist/render/shaders/windStreaks.js +129 -0
- package/dist/render/shadowCasters.d.ts +107 -0
- package/dist/render/shadowCasters.js +1 -0
- package/dist/render/shadowMap.d.ts +10 -0
- package/dist/render/shadowMap.js +80 -0
- package/dist/render/shotPlacement.d.ts +80 -0
- package/dist/render/shotPlacement.js +183 -0
- package/dist/render/skinPalette.d.ts +90 -0
- package/dist/render/skinPalette.js +136 -0
- package/dist/render/ssrPass.d.ts +59 -0
- package/dist/render/ssrPass.js +196 -0
- package/dist/render/surfaceSheet.d.ts +52 -0
- package/dist/render/surfaceSheet.js +99 -0
- package/dist/render/surfaceTexture.d.ts +197 -0
- package/dist/render/surfaceTexture.js +116 -0
- package/dist/render/temporalAa.d.ts +104 -0
- package/dist/render/temporalAa.js +194 -0
- package/dist/render/temporalPass.d.ts +54 -0
- package/dist/render/temporalPass.js +135 -0
- package/dist/render/textLayout.d.ts +88 -0
- package/dist/render/textLayout.js +201 -0
- package/dist/render/textRenderer.d.ts +32 -0
- package/dist/render/textRenderer.js +176 -0
- package/dist/render/thirdPersonCamera.d.ts +272 -0
- package/dist/render/thirdPersonCamera.js +479 -0
- package/dist/render/trample.d.ts +57 -0
- package/dist/render/trample.js +134 -0
- package/dist/render/translucentQueue.d.ts +76 -0
- package/dist/render/translucentQueue.js +90 -0
- package/dist/render/uniformVectorBudget.d.ts +105 -0
- package/dist/render/uniformVectorBudget.js +201 -0
- package/dist/render/uploadStep.d.ts +14 -0
- package/dist/render/uploadStep.js +14 -0
- package/dist/render/vertexDefaults.d.ts +48 -0
- package/dist/render/vertexDefaults.js +111 -0
- package/dist/render/visibility.d.ts +22 -0
- package/dist/render/visibility.js +47 -0
- package/dist/render/waterDraw.d.ts +57 -0
- package/dist/render/waterDraw.js +102 -0
- package/dist/render/waterGrid.d.ts +62 -0
- package/dist/render/waterGrid.js +151 -0
- package/dist/render/waterRenderer.d.ts +163 -0
- package/dist/render/waterRenderer.js +165 -0
- package/dist/render/wind.d.ts +45 -0
- package/dist/render/wind.js +32 -0
- package/dist/render/windField.d.ts +34 -0
- package/dist/render/windField.js +13 -0
- package/dist/render/windStreakDraw.d.ts +73 -0
- package/dist/render/windStreakDraw.js +86 -0
- package/dist/render/windStreakRenderer.d.ts +37 -0
- package/dist/render/windStreakRenderer.js +86 -0
- package/dist/scene/node.d.ts +128 -0
- package/dist/scene/node.js +319 -0
- package/dist/scene/visit.d.ts +38 -0
- package/dist/scene/visit.js +43 -0
- package/dist/ui/clipMime.d.ts +46 -0
- package/dist/ui/clipMime.js +88 -0
- package/dist/ui/exportTarget.d.ts +305 -0
- package/dist/ui/exportTarget.js +368 -0
- package/dist/ui/frameOverlay.d.ts +59 -0
- package/dist/ui/frameOverlay.js +76 -0
- package/dist/ui/framePacer.d.ts +142 -0
- package/dist/ui/framePacer.js +284 -0
- package/dist/ui/frameRecorder.d.ts +188 -0
- package/dist/ui/frameRecorder.js +221 -0
- package/dist/ui/fullscreen.d.ts +72 -0
- package/dist/ui/fullscreen.js +92 -0
- package/dist/ui/pixelCursor.d.ts +28 -0
- package/dist/ui/pixelCursor.js +66 -0
- package/dist/ui/splash.d.ts +86 -0
- package/dist/ui/splash.js +300 -0
- package/dist/ui/stillFrame.d.ts +22 -0
- package/dist/ui/stillFrame.js +40 -0
- package/package.json +60 -0
- package/src/behavior/behaviorTree.ts +346 -0
- package/src/build/shaderComments.ts +0 -0
- package/src/cinematic/player.ts +209 -0
- package/src/cinematic/script.ts +231 -0
- package/src/core/bootGate.ts +49 -0
- package/src/core/loadTracker.ts +144 -0
- package/src/core/loop.ts +211 -0
- package/src/core/messageQueue.ts +145 -0
- package/src/core/onceSet.ts +65 -0
- package/src/core/preferences.ts +177 -0
- package/src/core/remoteSave.ts +347 -0
- package/src/core/rng.ts +101 -0
- package/src/core/stepBudget.ts +136 -0
- package/src/core/storage.ts +114 -0
- package/src/core/tickTrace.ts +129 -0
- package/src/core/timeCurve.ts +175 -0
- package/src/core/withDefaults.ts +28 -0
- package/src/dev/contactProbe.ts +115 -0
- package/src/dev/fpsMeter.ts +101 -0
- package/src/environment/celestialClock.ts +385 -0
- package/src/geometry/decal.ts +260 -0
- package/src/geometry/filmPatch.ts +158 -0
- package/src/geometry/growable.ts +165 -0
- package/src/geometry/lightVolume.ts +161 -0
- package/src/geometry/meshBuilder.ts +1397 -0
- package/src/geometry/pixelFont.ts +189 -0
- package/src/geometry/ribbon.ts +790 -0
- package/src/geometry/shellFill.ts +265 -0
- package/src/geometry/spline.ts +659 -0
- package/src/geometry/tangents.ts +173 -0
- package/src/geometry/textMesh.ts +96 -0
- package/src/geometry/treeBuilder.ts +114 -0
- package/src/host/display.ts +180 -0
- package/src/host/files.ts +77 -0
- package/src/host/lifecycle.ts +63 -0
- package/src/host/platformServices.ts +23 -0
- package/src/host/screen.ts +134 -0
- package/src/index.ts +730 -0
- package/src/input/actionMap.ts +377 -0
- package/src/input/activeDevice.ts +86 -0
- package/src/input/gamepadIdentity.ts +131 -0
- package/src/input/gamepadMapping.ts +121 -0
- package/src/input/input.ts +872 -0
- package/src/input/inputHarness.ts +226 -0
- package/src/input/rightGesture.ts +76 -0
- package/src/input/rumble.ts +138 -0
- package/src/input/touchControls.ts +451 -0
- package/src/input/typingTarget.ts +26 -0
- package/src/math/bounds.ts +153 -0
- package/src/math/color.ts +37 -0
- package/src/math/exact.ts +274 -0
- package/src/math/frustum.ts +115 -0
- package/src/math/intersect.ts +228 -0
- package/src/math/scalar.ts +109 -0
- package/src/math/spring.ts +106 -0
- package/src/nav/navGraph.ts +168 -0
- package/src/nav/navPath.ts +217 -0
- package/src/nav/navSearch.ts +200 -0
- package/src/physics/boxSurface.ts +96 -0
- package/src/physics/colliderSurface.ts +213 -0
- package/src/physics/compositeSurface.ts +111 -0
- package/src/physics/heightSurface.ts +234 -0
- package/src/physics/ribbonSurface.ts +642 -0
- package/src/render/ambientOcclusionPass.ts +200 -0
- package/src/render/areaLights.ts +194 -0
- package/src/render/areaShadowSet.ts +405 -0
- package/src/render/atmosphere.ts +186 -0
- package/src/render/backend/api.ts +802 -0
- package/src/render/backend/budget.ts +139 -0
- package/src/render/backend/createRenderer.ts +343 -0
- package/src/render/backend/deadline.ts +37 -0
- package/src/render/backend/probe.ts +152 -0
- package/src/render/backend/select.ts +288 -0
- package/src/render/backend/timer.ts +59 -0
- package/src/render/backend/webgl2/instanced.ts +46 -0
- package/src/render/backend/webgl2/morphTexture.ts +58 -0
- package/src/render/backend/webgl2/renderer.ts +7484 -0
- package/src/render/backend/webgl2/skinPaletteTexture.ts +70 -0
- package/src/render/backend/webgpu/boltPass.ts +205 -0
- package/src/render/backend/webgpu/buffers.ts +553 -0
- package/src/render/backend/webgpu/causticsPass.ts +174 -0
- package/src/render/backend/webgpu/clusterBinner.ts +259 -0
- package/src/render/backend/webgpu/depthPass.ts +261 -0
- package/src/render/backend/webgpu/device.ts +148 -0
- package/src/render/backend/webgpu/drawCommand.ts +79 -0
- package/src/render/backend/webgpu/environmentTexels.ts +96 -0
- package/src/render/backend/webgpu/filmPass.ts +123 -0
- package/src/render/backend/webgpu/flatPass.ts +635 -0
- package/src/render/backend/webgpu/flockPass.ts +163 -0
- package/src/render/backend/webgpu/gpuTimestamps.ts +255 -0
- package/src/render/backend/webgpu/insetPass.ts +123 -0
- package/src/render/backend/webgpu/instanced.ts +55 -0
- package/src/render/backend/webgpu/lightVolumePass.ts +203 -0
- package/src/render/backend/webgpu/linePass.ts +270 -0
- package/src/render/backend/webgpu/morphTexture.ts +61 -0
- package/src/render/backend/webgpu/panelPass.ts +138 -0
- package/src/render/backend/webgpu/particlePass.ts +370 -0
- package/src/render/backend/webgpu/pipelineCache.ts +152 -0
- package/src/render/backend/webgpu/plumePass.ts +292 -0
- package/src/render/backend/webgpu/pointShadowPass.ts +368 -0
- package/src/render/backend/webgpu/postPass.ts +470 -0
- package/src/render/backend/webgpu/probePass.ts +218 -0
- package/src/render/backend/webgpu/reflectionPass.ts +137 -0
- package/src/render/backend/webgpu/renderer.ts +13004 -0
- package/src/render/backend/webgpu/scatterPass.ts +354 -0
- package/src/render/backend/webgpu/sdfTextPass.ts +220 -0
- package/src/render/backend/webgpu/shaderModules.ts +49 -0
- package/src/render/backend/webgpu/shaders/clusterBin.wgsl.ts +219 -0
- package/src/render/backend/webgpu/skinPaletteRing.ts +105 -0
- package/src/render/backend/webgpu/skinPaletteTexture.ts +79 -0
- package/src/render/backend/webgpu/skyPass.ts +85 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +257 -0
- package/src/render/backend/webgpu/textPass.ts +224 -0
- package/src/render/backend/webgpu/uniformRing.ts +228 -0
- package/src/render/backend/webgpu/waterPass.ts +211 -0
- package/src/render/backend/webgpu/windStreakPass.ts +196 -0
- package/src/render/billboard.ts +108 -0
- package/src/render/bloomChain.ts +101 -0
- package/src/render/bloomPass.ts +256 -0
- package/src/render/boltBatch.ts +141 -0
- package/src/render/boltPool.ts +360 -0
- package/src/render/boom.ts +123 -0
- package/src/render/camera.ts +348 -0
- package/src/render/causticsRenderer.ts +171 -0
- package/src/render/cinematicCamera.ts +278 -0
- package/src/render/clusteredLights.ts +598 -0
- package/src/render/colourGrade.ts +109 -0
- package/src/render/compute.ts +83 -0
- package/src/render/contextLoss.ts +50 -0
- package/src/render/debugLines.ts +411 -0
- package/src/render/decalPass.ts +124 -0
- package/src/render/decalProjector.ts +390 -0
- package/src/render/decalQueue.ts +110 -0
- package/src/render/depthConvention.ts +383 -0
- package/src/render/drawingBuffer.ts +89 -0
- package/src/render/emptyTexture.ts +130 -0
- package/src/render/envProbeArray.ts +201 -0
- package/src/render/equirectToCube.ts +160 -0
- package/src/render/flockGeometry.ts +53 -0
- package/src/render/flockRenderer.ts +111 -0
- package/src/render/frame/arena.ts +93 -0
- package/src/render/frame/index.ts +29 -0
- package/src/render/frame/replay.ts +50 -0
- package/src/render/frame/resources.ts +61 -0
- package/src/render/frame/schedule.ts +85 -0
- package/src/render/frameView.ts +20 -0
- package/src/render/gizmo.ts +923 -0
- package/src/render/globalMedium.ts +154 -0
- package/src/render/globalMediumPass.ts +323 -0
- package/src/render/gpuCapability.ts +244 -0
- package/src/render/gpuTimer.ts +182 -0
- package/src/render/halfFloat.ts +39 -0
- package/src/render/handleRegistry.ts +96 -0
- package/src/render/iesProfile.ts +215 -0
- package/src/render/imageTexels.ts +109 -0
- package/src/render/instancedMesh.ts +187 -0
- package/src/render/instances.ts +92 -0
- package/src/render/lightBudget.ts +655 -0
- package/src/render/lightMatrix.ts +69 -0
- package/src/render/lightVolumeDraw.ts +216 -0
- package/src/render/lineBatch.ts +180 -0
- package/src/render/linePoints.ts +61 -0
- package/src/render/livePointShadowSet.ts +285 -0
- package/src/render/lod.ts +86 -0
- package/src/render/mesh.ts +536 -0
- package/src/render/occlusion.ts +406 -0
- package/src/render/oitPass.ts +230 -0
- package/src/render/orderIndependent.ts +136 -0
- package/src/render/particleBatch.ts +299 -0
- package/src/render/particleMaterial.ts +84 -0
- package/src/render/particlePool.ts +291 -0
- package/src/render/pass.ts +203 -0
- package/src/render/passTarget.ts +225 -0
- package/src/render/pickable.ts +222 -0
- package/src/render/planarReflection.ts +233 -0
- package/src/render/planarReflectionDraw.ts +87 -0
- package/src/render/plumeGeometry.ts +75 -0
- package/src/render/plumeMaterial.ts +99 -0
- package/src/render/plumeRenderer.ts +272 -0
- package/src/render/pointLightSelection.ts +447 -0
- package/src/render/pointShadowArray.ts +276 -0
- package/src/render/pointShadowBudget.ts +305 -0
- package/src/render/pointShadowImage.ts +470 -0
- package/src/render/pointShadowMap.ts +228 -0
- package/src/render/pointShadowSystem.ts +408 -0
- package/src/render/prefilterEnvMap.ts +162 -0
- package/src/render/prefilterPass.ts +115 -0
- package/src/render/probeGrid.ts +248 -0
- package/src/render/rainField.ts +240 -0
- package/src/render/reflectionProbe.ts +530 -0
- package/src/render/renderQuality.ts +1054 -0
- package/src/render/rendererHarness.ts +214 -0
- package/src/render/resolutionGovernor.ts +189 -0
- package/src/render/scatterDeform.ts +72 -0
- package/src/render/sceneTarget.ts +1032 -0
- package/src/render/screenSpaceReflection.ts +524 -0
- package/src/render/sdfFont.ts +157 -0
- package/src/render/sdfTextLayout.ts +206 -0
- package/src/render/sdfTextRenderer.ts +233 -0
- package/src/render/seaState.ts +55 -0
- package/src/render/segmentQuads.ts +92 -0
- package/src/render/shader.ts +190 -0
- package/src/render/shaders/ambientOcclusion.ts +354 -0
- package/src/render/shaders/arcane.ts +103 -0
- package/src/render/shaders/bloom.ts +232 -0
- package/src/render/shaders/bolt.ts +164 -0
- package/src/render/shaders/caustics.ts +169 -0
- package/src/render/shaders/conditionals.ts +58 -0
- package/src/render/shaders/decalProject.ts +127 -0
- package/src/render/shaders/depth.ts +131 -0
- package/src/render/shaders/depthOfField.ts +141 -0
- package/src/render/shaders/film.ts +285 -0
- package/src/render/shaders/fire.ts +180 -0
- package/src/render/shaders/flat/directionalShadow.ts +196 -0
- package/src/render/shaders/flat/index.ts +502 -0
- package/src/render/shaders/flat/lobes.ts +399 -0
- package/src/render/shaders/flat/main.ts +1631 -0
- package/src/render/shaders/flat/pointShadow.ts +323 -0
- package/src/render/shaders/flat/preamble.ts +875 -0
- package/src/render/shaders/flat/probeGrid.ts +152 -0
- package/src/render/shaders/flat/surface.ts +41 -0
- package/src/render/shaders/flock.ts +103 -0
- package/src/render/shaders/fog.ts +99 -0
- package/src/render/shaders/fullscreen.ts +28 -0
- package/src/render/shaders/generated/ambientOcclusion.wgsl.ts +74 -0
- package/src/render/shaders/generated/arcane.wgsl.ts +98 -0
- package/src/render/shaders/generated/bloom.wgsl.ts +79 -0
- package/src/render/shaders/generated/bolt.wgsl.ts +127 -0
- package/src/render/shaders/generated/caustics.wgsl.ts +127 -0
- package/src/render/shaders/generated/decalProject.wgsl.ts +69 -0
- package/src/render/shaders/generated/depth.wgsl.ts +142 -0
- package/src/render/shaders/generated/film.wgsl.ts +143 -0
- package/src/render/shaders/generated/fire.wgsl.ts +137 -0
- package/src/render/shaders/generated/flat.wgsl.ts +9195 -0
- package/src/render/shaders/generated/flock.wgsl.ts +82 -0
- package/src/render/shaders/generated/fullscreen.wgsl.ts +20 -0
- package/src/render/shaders/generated/globalMedium.wgsl.ts +139 -0
- package/src/render/shaders/generated/lightVolume.wgsl.ts +242 -0
- package/src/render/shaders/generated/line.wgsl.ts +137 -0
- package/src/render/shaders/generated/octahedralResolve.wgsl.ts +60 -0
- package/src/render/shaders/generated/oitResolve.wgsl.ts +31 -0
- package/src/render/shaders/generated/panel.wgsl.ts +57 -0
- package/src/render/shaders/generated/particle.wgsl.ts +343 -0
- package/src/render/shaders/generated/prefilter.wgsl.ts +69 -0
- package/src/render/shaders/generated/rush.wgsl.ts +139 -0
- package/src/render/shaders/generated/scatter.wgsl.ts +205 -0
- package/src/render/shaders/generated/sdfText.wgsl.ts +78 -0
- package/src/render/shaders/generated/sky.wgsl.ts +109 -0
- package/src/render/shaders/generated/smoke.wgsl.ts +93 -0
- package/src/render/shaders/generated/ssrResolve.wgsl.ts +26 -0
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +94 -0
- package/src/render/shaders/generated/temporalResolve.wgsl.ts +54 -0
- package/src/render/shaders/generated/text.wgsl.ts +107 -0
- package/src/render/shaders/generated/water.wgsl.ts +256 -0
- package/src/render/shaders/generated/windStreaks.wgsl.ts +82 -0
- package/src/render/shaders/gerstner.ts +110 -0
- package/src/render/shaders/globalMedium.ts +396 -0
- package/src/render/shaders/lightVolume.ts +546 -0
- package/src/render/shaders/line.ts +125 -0
- package/src/render/shaders/morph.ts +62 -0
- package/src/render/shaders/octahedral.ts +170 -0
- package/src/render/shaders/octahedralResolve.ts +83 -0
- package/src/render/shaders/oitResolve.ts +42 -0
- package/src/render/shaders/outputTransform.ts +107 -0
- package/src/render/shaders/panel.ts +51 -0
- package/src/render/shaders/particle.ts +438 -0
- package/src/render/shaders/prefilter.ts +278 -0
- package/src/render/shaders/rush.ts +357 -0
- package/src/render/shaders/scatter.ts +211 -0
- package/src/render/shaders/sdfText.ts +68 -0
- package/src/render/shaders/skinning.ts +59 -0
- package/src/render/shaders/sky.ts +243 -0
- package/src/render/shaders/smoke.ts +89 -0
- package/src/render/shaders/ssrResolve.ts +28 -0
- package/src/render/shaders/ssrTrace.ts +233 -0
- package/src/render/shaders/tangentFrame.ts +70 -0
- package/src/render/shaders/temporalResolve.ts +151 -0
- package/src/render/shaders/text.ts +156 -0
- package/src/render/shaders/vertexChannel.ts +71 -0
- package/src/render/shaders/water.ts +356 -0
- package/src/render/shaders/windStreaks.ts +130 -0
- package/src/render/shadowCasters.ts +124 -0
- package/src/render/shadowMap.ts +89 -0
- package/src/render/shotPlacement.ts +266 -0
- package/src/render/skinPalette.ts +157 -0
- package/src/render/ssrPass.ts +241 -0
- package/src/render/surfaceSheet.ts +158 -0
- package/src/render/surfaceTexture.ts +310 -0
- package/src/render/temporalAa.ts +221 -0
- package/src/render/temporalPass.ts +153 -0
- package/src/render/textLayout.ts +239 -0
- package/src/render/textRenderer.ts +201 -0
- package/src/render/thirdPersonCamera.ts +578 -0
- package/src/render/trample.ts +140 -0
- package/src/render/translucentQueue.ts +161 -0
- package/src/render/uniformVectorBudget.ts +246 -0
- package/src/render/uploadStep.ts +14 -0
- package/src/render/vertexDefaults.ts +115 -0
- package/src/render/visibility.ts +56 -0
- package/src/render/waterDraw.ts +167 -0
- package/src/render/waterGrid.ts +180 -0
- package/src/render/waterRenderer.ts +352 -0
- package/src/render/wind.ts +79 -0
- package/src/render/windField.ts +50 -0
- package/src/render/windStreakDraw.ts +131 -0
- package/src/render/windStreakRenderer.ts +130 -0
- package/src/scene/node.ts +336 -0
- package/src/scene/visit.ts +82 -0
- package/src/ui/clipMime.ts +109 -0
- package/src/ui/exportTarget.ts +491 -0
- package/src/ui/frameOverlay.ts +159 -0
- package/src/ui/framePacer.ts +351 -0
- package/src/ui/frameRecorder.ts +333 -0
- package/src/ui/fullscreen.ts +113 -0
- package/src/ui/pixelCursor.ts +99 -0
- package/src/ui/splash.ts +347 -0
- package/src/ui/stillFrame.ts +44 -0
|
@@ -0,0 +1,1054 @@
|
|
|
1
|
+
/** Construction-time GPU quality controls shared by every renderer resource. */
|
|
2
|
+
|
|
3
|
+
import { MAX_AREA_LIGHTS } from './areaLights.ts';
|
|
4
|
+
import { MAX_GLOBAL_MEDIUM_STEPS } from './globalMedium.ts';
|
|
5
|
+
import { MAX_POINT_LIGHTS } from './lightBudget.ts';
|
|
6
|
+
import { PREFILTER_SAMPLE_COUNTS } from './prefilterEnvMap.ts';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* What happens to a shaded colour on its way to the framebuffer.
|
|
10
|
+
*
|
|
11
|
+
* `none` writes it unchanged, which is what this renderer has always done and what its
|
|
12
|
+
* worlds are authored against.
|
|
13
|
+
*
|
|
14
|
+
* `srgb` applies the sRGB transfer function. This is not a stylistic choice: shading
|
|
15
|
+
* maths is linear and a display is not, so writing linear values into an 8-bit
|
|
16
|
+
* framebuffer crushes the midtones — a surface at 0.2 linear should read as 0.48 and
|
|
17
|
+
* instead reads as 0.2. It is why an untransformed render looks dark and muddy in
|
|
18
|
+
* exactly the places a lit one should look ordinary.
|
|
19
|
+
*
|
|
20
|
+
* `aces` adds filmic tone mapping before that, rolling highlights off instead of
|
|
21
|
+
* clipping them flat. Together they are what three.js does by default, which is why a
|
|
22
|
+
* world ported from it looks wrong until this exists.
|
|
23
|
+
*/
|
|
24
|
+
export type OutputTransform = 'none' | 'srgb' | 'aces';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The three settings whose accepted values are a closed set, written as one.
|
|
28
|
+
*
|
|
29
|
+
* Each of these already threw at construction with a message naming the allowed values, which is
|
|
30
|
+
* the right refusal at the wrong moment: it survives `tsc` and lands as a blank page. A union moves
|
|
31
|
+
* the same failure to the call site and costs nothing, because these are decisions rather than
|
|
32
|
+
* quantities and a caller computing one is choosing between named tiers either way.
|
|
33
|
+
*
|
|
34
|
+
* Exported so a consumer building a quality profile can name the type of the field it is filling.
|
|
35
|
+
*/
|
|
36
|
+
export type ShadowFilterTaps = 4 | 8 | 12;
|
|
37
|
+
export type DirectionalShadowDepthLayers = 1 | 2;
|
|
38
|
+
export type WaterReflectionFilterTaps = 1 | 5 | 9;
|
|
39
|
+
|
|
40
|
+
export interface RenderQuality {
|
|
41
|
+
/**
|
|
42
|
+
* The transfer curve applied at the end of every shaded pass.
|
|
43
|
+
*
|
|
44
|
+
* Construction-time, like every other quality control here, and `none` by default so
|
|
45
|
+
* no existing world changes by a single bit.
|
|
46
|
+
*
|
|
47
|
+
* **The symptom, written down because nobody searches for a transfer curve they do not know
|
|
48
|
+
* exists.** With `none`, values above 1 clip flat rather than rolling off, so a scene with
|
|
49
|
+
* bright sources against dark surroundings reads as crushed and desaturated: the highlights
|
|
50
|
+
* go to a hard white with no colour left in them and the midtones look muddy. That is
|
|
51
|
+
* reported by eye as "dark", "flat" or "not vivid", which sounds like a lighting problem, so
|
|
52
|
+
* that is where people look. A consumer built, tuned and shipped six worlds before anybody
|
|
53
|
+
* said the word. If a scene looks like that, try `outputTransform: 'aces'` with an
|
|
54
|
+
* `outputExposure` before touching a single light.
|
|
55
|
+
*
|
|
56
|
+
* The default stays `none`, and that is not the fault: a curve that changed every existing
|
|
57
|
+
* consumer's output would be far worse than one nobody found.
|
|
58
|
+
*/
|
|
59
|
+
readonly outputTransform: OutputTransform;
|
|
60
|
+
/**
|
|
61
|
+
* How far the scene is scaled into the tone curve before it is applied. 1 is neutral.
|
|
62
|
+
*
|
|
63
|
+
* A tone curve is only meaningful relative to an exposure, and the reference ACES
|
|
64
|
+
* transform is graded for a dark cinema. Renderers that ship it therefore scale their
|
|
65
|
+
* input to suit the room the image will actually be seen in, and the factor each one
|
|
66
|
+
* chooses is a look rather than a standard — three.js uses 1/0.6 and says so. This
|
|
67
|
+
* engine holds no opinion and takes the number from whoever is authoring the world, so
|
|
68
|
+
* that matching another renderer, or simply preferring a different grade, is a setting
|
|
69
|
+
* rather than a patch. Ignored when `outputTransform` is not `aces`.
|
|
70
|
+
*/
|
|
71
|
+
readonly outputExposure: number;
|
|
72
|
+
/**
|
|
73
|
+
* How a point light fades with distance.
|
|
74
|
+
*
|
|
75
|
+
* `smooth` shapes the curve to the light's own radius — zero exactly at the edge, gentle
|
|
76
|
+
* near the source — which is what makes a light cullable without a seam and is what
|
|
77
|
+
* every world built on this engine is authored against. `inverseSquare` is the physical
|
|
78
|
+
* law, windowed by the radius so it still ends where it says it does; it is far brighter
|
|
79
|
+
* close in, which matters when a source sits centimetres from a surface. Neither is more
|
|
80
|
+
* correct than the other for a stylised world, so this engine ships both and holds no
|
|
81
|
+
* opinion about which a game should want.
|
|
82
|
+
*/
|
|
83
|
+
readonly pointLightFalloff: 'smooth' | 'inverseSquare';
|
|
84
|
+
/** Drawing-buffer pixel density cap. */
|
|
85
|
+
readonly maxDevicePixelRatio: number;
|
|
86
|
+
/**
|
|
87
|
+
* Drawing-buffer *area* cap, in pixels. Zero is uncapped.
|
|
88
|
+
*
|
|
89
|
+
* The companion to `maxDevicePixelRatio` and not a duplicate of it: density answers
|
|
90
|
+
* "is this panel high-DPI", area answers "how much frame is this". With only the
|
|
91
|
+
* density cap, the cost of a frame is whatever area the window happens to be, which
|
|
92
|
+
* makes the size of somebody's window an uncontrolled multiplier on a renderer that is
|
|
93
|
+
* roughly 90% fragment-bound. See `drawingBuffer.ts` for why vsync turns that into a
|
|
94
|
+
* halved frame rate rather than a slightly slower one.
|
|
95
|
+
*/
|
|
96
|
+
readonly maxDrawingBufferPixels: number;
|
|
97
|
+
readonly directionalShadows: boolean;
|
|
98
|
+
readonly pointShadows: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* The most point lights the lit shader will be built to shade at once. A ceiling, not a promise.
|
|
101
|
+
*
|
|
102
|
+
* **What it is for is fitting a device, not tuning a picture.** Ten of the lit shader's uniform
|
|
103
|
+
* arrays are sized by this with point shadows off and twenty with them on, and GLSL ES spends a
|
|
104
|
+
* whole row of the fragment uniform grid per array *element* whatever its base type — so the
|
|
105
|
+
* full budget declares 440 rows where an Adreno 740 offers 256 and WebGL2 guarantees 224. A
|
|
106
|
+
* shader that does not link is not a slower frame, it is no frame at all.
|
|
107
|
+
*
|
|
108
|
+
* **The renderer already lowers this on its own when the part is short**, counting the shader it
|
|
109
|
+
* is about to compile against what the device reports and saying so in the console. So a
|
|
110
|
+
* consumer never has to set it to boot — this is here for the one who wants the arrays smaller
|
|
111
|
+
* than the device would force, to spend the rows on something else or to hold a scene to a
|
|
112
|
+
* budget they have measured.
|
|
113
|
+
*
|
|
114
|
+
* Lowering it costs lights. `Renderer.shadedLights` reports what was actually resolved, and a
|
|
115
|
+
* `PointLightBuffer` should be sized from that: the selection evicts the weakest when the buffer
|
|
116
|
+
* is full, so a buffer wider than the shader leaves an arbitrary subset lit rather than the
|
|
117
|
+
* nearest ones.
|
|
118
|
+
*
|
|
119
|
+
* **WebGL2 only.** The generated WGSL is built and committed at the full budget, and WebGPU has
|
|
120
|
+
* no per-stage uniform-vector ceiling to be short of. A consumer that lowers this and lands on
|
|
121
|
+
* WebGPU gets all sixteen, which is both the better picture and the one that device can afford.
|
|
122
|
+
*/
|
|
123
|
+
readonly maxLights: number;
|
|
124
|
+
/** The most rectangular emitters the lit shader will be built to shade at once. See `maxLights`. */
|
|
125
|
+
readonly maxAreaLights: number;
|
|
126
|
+
readonly directionalShadowMapSize: number;
|
|
127
|
+
/** Side length of each of the six point-shadow cubemap faces. */
|
|
128
|
+
readonly pointShadowFaceSize: number;
|
|
129
|
+
/**
|
|
130
|
+
* Shared PCF budget for directional and point-light shadows.
|
|
131
|
+
*
|
|
132
|
+
* A closed set written as one, so a value outside it is a red squiggle rather than a blank
|
|
133
|
+
* page. **Reported from outside**: `shadowFilterTaps: 9` type-checked and then threw at
|
|
134
|
+
* construction, which is the right refusal arriving at the worst moment. The runtime check
|
|
135
|
+
* stays for JavaScript consumers, which have no types to be helped by.
|
|
136
|
+
*/
|
|
137
|
+
readonly shadowFilterTaps: ShadowFilterTaps;
|
|
138
|
+
/**
|
|
139
|
+
* How many samples a volume of light takes along each view ray. See `drawLightVolume`.
|
|
140
|
+
*
|
|
141
|
+
* The pass integrates the air rather than drawing sheets through it, so this is the dial
|
|
142
|
+
* between banding and cost, and it is the only quality control the volume has. Thirty-two is
|
|
143
|
+
* clean at the size a shaft usually occupies because the march is dithered per pixel, which
|
|
144
|
+
* turns what would be concentric shells into grain the effect wants anyway. Below about
|
|
145
|
+
* eight that grain becomes the picture; above thirty-two nothing here could see a change.
|
|
146
|
+
*
|
|
147
|
+
* It costs nothing when no volume is drawn, which is most frames in most worlds.
|
|
148
|
+
*/
|
|
149
|
+
readonly lightVolumeSamples: number;
|
|
150
|
+
/** Independently composited static sun depths; two preserves common overlaps. */
|
|
151
|
+
readonly directionalShadowDepthLayers: DirectionalShadowDepthLayers;
|
|
152
|
+
/** Horizontal world-space reach over which a directional shadow dissolves. */
|
|
153
|
+
readonly directionalShadowMaxDistance: number;
|
|
154
|
+
/** Maximum horizontal projection per vertical metre before low-angle shadows vanish. */
|
|
155
|
+
readonly directionalShadowMaxSlope: number;
|
|
156
|
+
/**
|
|
157
|
+
* Metres a point light may drift from where its shadow was baked before re-baking.
|
|
158
|
+
*
|
|
159
|
+
* Zero is the old behaviour and it was the wrong default. See
|
|
160
|
+
* `PointShadowMap.matchesSource`: a light that wanders to look alive invalidated
|
|
161
|
+
* its map every frame, and a re-bake is six passes over the static world. Eight
|
|
162
|
+
* sampled lights flickering at once accounted for 174 of the frame's 296 draw
|
|
163
|
+
* calls, and for the game being unplayable exactly where lamps cluster.
|
|
164
|
+
*
|
|
165
|
+
* The default clears a flame's own wander with room to spare, because drift is
|
|
166
|
+
* measured from the baked origin and a wander can be caught at either extreme
|
|
167
|
+
* of its travel. A light that really moves still re-bakes; it just does so once
|
|
168
|
+
* per this much movement instead of once per frame.
|
|
169
|
+
*/
|
|
170
|
+
readonly pointShadowRebakeDistance: number;
|
|
171
|
+
/**
|
|
172
|
+
* Cubemap faces of point-shadow bake the renderer may spend in one frame.
|
|
173
|
+
*
|
|
174
|
+
* A face is a full pass over the static casters, so six of them is one light. Baking
|
|
175
|
+
* every stale light in the frame it goes stale is fine in the steady state and ruinous
|
|
176
|
+
* on the frame that stops being true: walking into a courtyard makes eight lights stale at
|
|
177
|
+
* once, and 48 passes measured as two consecutive frames of 89 ms and 99 ms against an
|
|
178
|
+
* 8.3 ms budget. That is the hitch a second after a page load.
|
|
179
|
+
*
|
|
180
|
+
* Two faces is about 6 ms of the same work, and the backlog drains over the next
|
|
181
|
+
* handful of frames while shadows resolve progressively. Raising it trades that
|
|
182
|
+
* smoothness for lamps that light sooner.
|
|
183
|
+
*/
|
|
184
|
+
readonly pointShadowFacesPerFrame: number;
|
|
185
|
+
/**
|
|
186
|
+
* Cubemap faces of *live* point-shadow bake the renderer may spend in one frame.
|
|
187
|
+
*
|
|
188
|
+
* The companion to `pointShadowFacesPerFrame` and not a duplicate of it. That one budgets the
|
|
189
|
+
* static maps, which go stale when a lamp drifts; this budgets the live maps, which hold the
|
|
190
|
+
* movers and are stale every frame by definition — a character is somewhere new each frame, and
|
|
191
|
+
* no `matchesSource` tolerance will ever say otherwise.
|
|
192
|
+
*
|
|
193
|
+
* **It defaults to a whole cubemap because that is what the renderer did before this existed,
|
|
194
|
+
* and that default is wrong for a phone.** The live loop had no budget at all: it asked for
|
|
195
|
+
* all six faces per live map per frame, outside the static budget. Measured as
|
|
196
|
+
* `pointShadow.face` six times a frame in the consumer and in three of the engine's own
|
|
197
|
+
* demos, in frames that were otherwise nine to fourteen passes. There are two live maps and
|
|
198
|
+
* the second wakes during an ownership handoff, so running past a row of lamps costs twelve
|
|
199
|
+
* full passes over the dynamic casters every frame.
|
|
200
|
+
*
|
|
201
|
+
* Lowering it spreads a mover's shadow across two or three frames instead of finishing it in
|
|
202
|
+
* one. The shadow then trails a fast character slightly, which is a real cost and a smaller one
|
|
203
|
+
* than the frame it was taking. Six keeps the old behaviour exactly.
|
|
204
|
+
*/
|
|
205
|
+
readonly liveShadowFacesPerFrame: number;
|
|
206
|
+
readonly water: boolean;
|
|
207
|
+
/** Cells per side; the vertex count is this value plus one, squared. */
|
|
208
|
+
readonly waterResolution: number;
|
|
209
|
+
/** Full planar scene reflection sampled by water; false keeps the sky fallback. */
|
|
210
|
+
readonly waterReflections: boolean;
|
|
211
|
+
/** Reflection-target dimensions relative to the drawing buffer. */
|
|
212
|
+
readonly waterReflectionScale: number;
|
|
213
|
+
/** Water-material samples used to broaden the otherwise sharp planar image. */
|
|
214
|
+
readonly waterReflectionFilterTaps: WaterReflectionFilterTaps;
|
|
215
|
+
/**
|
|
216
|
+
* Allocate the planar reflection target even where there is no water to sample it.
|
|
217
|
+
*
|
|
218
|
+
* **The reflection was a water feature by accident of its wiring rather than by design.** The
|
|
219
|
+
* target existed only when `water` and `waterReflections` were both on, so a scene whose ground
|
|
220
|
+
* is a mesh slab with wet film over it, which is what a street at night is, could not mirror
|
|
221
|
+
* anything into it however it asked. A consumer attempted exactly that on the strength of
|
|
222
|
+
* `beginPlanarReflection`'s name and had to do without.
|
|
223
|
+
*
|
|
224
|
+
* Off by default, because the target is a second colour buffer sized from the drawing one and
|
|
225
|
+
* a scene that does not sample it should not pay for it. `water && waterReflections` still
|
|
226
|
+
* turns it on by itself, so nothing that had a reflection loses one.
|
|
227
|
+
*/
|
|
228
|
+
readonly planarReflections: boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Keep the scene's real brightness through the composite, and grade at the end instead of in
|
|
231
|
+
* the mesh pass.
|
|
232
|
+
*
|
|
233
|
+
* **Off by default and it has to be, because it is not neutral.** With it on, the scene target
|
|
234
|
+
* holds half floats, so a value above 1 survives to the composite instead of being clamped on
|
|
235
|
+
* the way in, and every effect there works on what the scene actually emitted. Measured on the
|
|
236
|
+
* gilded chamber, held: pixels the scene had already driven near white changed **19.4% of the
|
|
237
|
+
* time with a mean delta of 3.21**, while every other band moved by 0.02 to 0.04, which is
|
|
238
|
+
* rounding between eight bits and a half float. That is the change being correct rather than
|
|
239
|
+
* the change being small, and it is still a change to a shipped picture.
|
|
240
|
+
*
|
|
241
|
+
* **What it is for.** Nothing downstream can tell a star at five times white from a sheet of
|
|
242
|
+
* white paper once the buffer has clamped both to 1, so a brightness threshold cannot exist.
|
|
243
|
+
* This is the prerequisite for one. It also moves the tone curve to the resolve, which fixes an
|
|
244
|
+
* inconsistency that predates it: the mesh pass was the only pass that graded, so the sky, the
|
|
245
|
+
* particles, the wet film and the water were composited ungraded beside a world that was.
|
|
246
|
+
*
|
|
247
|
+
* Needs `screenEffects`, since without a composite there is nothing at the end to grade in, and
|
|
248
|
+
* `EXT_color_buffer_float`, which is asked for rather than assumed: without it the target stays
|
|
249
|
+
* eight-bit and this buys only the consistent grading.
|
|
250
|
+
*/
|
|
251
|
+
readonly hdrScene: boolean;
|
|
252
|
+
/** Camera-depth water tint and scattering across every visible pass. */
|
|
253
|
+
readonly underwaterAtmosphere: boolean;
|
|
254
|
+
/** Procedural noise octaves evaluated by plume shaders. */
|
|
255
|
+
readonly plumeNoiseOctaves: number;
|
|
256
|
+
/**
|
|
257
|
+
* Whether a GPU family known to struggle may have its pixel terms clamped at construction.
|
|
258
|
+
*
|
|
259
|
+
* True by default, because the overwhelming majority of players never open a settings
|
|
260
|
+
* screen and a phone opening at a desktop profile is how `NFD6QQ` happened.
|
|
261
|
+
*
|
|
262
|
+
* **A caller passes false to mean "this person chose these numbers themselves."** A player
|
|
263
|
+
* who has deliberately asked for the good profile on a part that cannot hold it is entitled
|
|
264
|
+
* to have it, and to the frame rate that comes with it. Guessing over the top of an explicit
|
|
265
|
+
* choice is worse than a slow game, because it is a setting that silently does not apply.
|
|
266
|
+
*/
|
|
267
|
+
readonly capabilityClamp: boolean;
|
|
268
|
+
/**
|
|
269
|
+
* Throw away a multisampled attachment once it has been resolved, instead of writing it back.
|
|
270
|
+
*
|
|
271
|
+
* True is correct and is what the engine wants: the resolve happens either way, and no shader
|
|
272
|
+
* can read the four-sample texture because it carries no `TEXTURE_BINDING` usage. It is worth
|
|
273
|
+
* 115 MB a frame at a phone-sized frame with four samples.
|
|
274
|
+
*
|
|
275
|
+
* **It is a switch because it cannot be verified anywhere but on a tile-based GPU.** On an
|
|
276
|
+
* immediate-mode desktop part `discard` costs nothing and changes nothing — the samples have
|
|
277
|
+
* nowhere else to be — so a screenshot gate cannot tell a correct discard from a wrong one. A
|
|
278
|
+
* tiler really drops them. If a device flashes black or shows a stale frame, turn this off
|
|
279
|
+
* first: it is the one change in this area whose blast radius is a whole frame.
|
|
280
|
+
*/
|
|
281
|
+
/**
|
|
282
|
+
* Measure GPU time with timestamp queries. **Off by default, and that is the lesson.**
|
|
283
|
+
*
|
|
284
|
+
* A frame timer is a diagnostic, and a diagnostic must never be able to break the thing it
|
|
285
|
+
* observes. This one could: enabling it attaches a `timestampWrites` block to **every render
|
|
286
|
+
* pass in the frame**, so an implementation that disagrees about any part of it invalidates
|
|
287
|
+
* the whole command buffer, and an invalid command buffer draws nothing at all. That is a
|
|
288
|
+
* black canvas caused by a profiler.
|
|
289
|
+
*
|
|
290
|
+
* It shipped on by default and had only ever run against one implementation. Turning it on
|
|
291
|
+
* costs two queries a pass and is worth it while measuring; paying that risk on every
|
|
292
|
+
* consumer's frame for a number nobody is reading is not.
|
|
293
|
+
*
|
|
294
|
+
* Requires the adapter's `timestamp-query` feature. Without it this reports `available: false`
|
|
295
|
+
* and measures nothing, which is the honest answer rather than a silent zero.
|
|
296
|
+
*/
|
|
297
|
+
readonly gpuTiming: boolean;
|
|
298
|
+
readonly discardResolvedAttachments: boolean;
|
|
299
|
+
/**
|
|
300
|
+
* Open the frame's render pass on the first draw that wants it, rather than in `beginFrame`.
|
|
301
|
+
*
|
|
302
|
+
* True avoids closing and reloading the frame's attachment around every planar reflection,
|
|
303
|
+
* measured at 155 MB a frame on a scene with one mirror. False restores the eager open.
|
|
304
|
+
*
|
|
305
|
+
* A switch for the same reason as the one above: it moves *when* a pass is opened relative to
|
|
306
|
+
* everything else a consumer does in a frame, and the failure it could cause is a frame that
|
|
307
|
+
* does not present rather than a pixel that is wrong.
|
|
308
|
+
*/
|
|
309
|
+
readonly deferFramePass: boolean;
|
|
310
|
+
/**
|
|
311
|
+
* Route the verbs that have been migrated through the frame graph rather than issuing them
|
|
312
|
+
* directly.
|
|
313
|
+
*
|
|
314
|
+
* **On by default as of 2026-08-25.** The graph records a draw instead of executing it and
|
|
315
|
+
* schedules what accumulated at each boundary. `graphVerbFlushes` is zero — no verb flushes to
|
|
316
|
+
* issue its own calls any more — and the seven published scenes are **pixel-identical with it on
|
|
317
|
+
* and with it off**, 0 of 921,600 each at delta 16, measured on an AMD RX 9070 XT with no device
|
|
318
|
+
* errors on either setting.
|
|
319
|
+
*
|
|
320
|
+
* What kept it off was two defects that only recording could expose, both fixed the same day:
|
|
321
|
+
* a draw took the pipeline of whichever pass happened to be open rather than the one it would
|
|
322
|
+
* land in, and a probe bake never replayed its records, so it baked an empty cube and leaked six
|
|
323
|
+
* draws into the next pass to open. `IMPROVEMENTS.md` carries both.
|
|
324
|
+
*
|
|
325
|
+
* It remains a switch on the same reasoning as the two above: it changes *when* work reaches the
|
|
326
|
+
* GPU relative to everything else a consumer does, so a regression wants to be bisectable to this
|
|
327
|
+
* rather than to a release. `?graph=0` turns it off in one reload.
|
|
328
|
+
*/
|
|
329
|
+
readonly frameGraph: boolean;
|
|
330
|
+
/**
|
|
331
|
+
* Light the world from a froxel table rather than from a fixed set of uniform-array slots.
|
|
332
|
+
*
|
|
333
|
+
* **Off, and off is what every published scene is gated at.** With it off the clustered lines
|
|
334
|
+
* are not in the compiled shader at all — `resolveConditionals` cuts them — so a consumer that
|
|
335
|
+
* does not ask for this compiles and runs exactly the shader it did before, which is what makes
|
|
336
|
+
* the zero-pixel gate on the published scenes mean something.
|
|
337
|
+
*
|
|
338
|
+
* On, the point-light budget stops being `MAX_POINT_LIGHTS` and becomes `MAX_CLUSTERED_LIGHTS`,
|
|
339
|
+
* and a fragment shades against the lights in its own froxel rather than against every light the
|
|
340
|
+
* CPU chose for the whole scene.
|
|
341
|
+
*
|
|
342
|
+
* **What it gives up.** One texture unit on WebGL2, permanently, for the table. A per-frame
|
|
343
|
+
* binning cost that is on the main thread on WebGL2 and on the GPU on WebGPU — measured in
|
|
344
|
+
* `clusteredLights.ts`, 0.411 ms a frame at sixteen lights and 2.6 ms at 256. And the froxel
|
|
345
|
+
* bounds are the AABB of a truncated pyramid, so a light is occasionally shaded against a
|
|
346
|
+
* fragment it only nearly reaches.
|
|
347
|
+
*
|
|
348
|
+
* **What would make it wrong.** A scene whose lights are few and enormous: binning cost scales
|
|
349
|
+
* with a light's screen area rather than with the light count, so sixteen lights each covering
|
|
350
|
+
* the frame is the shape that pays most and gains least. The fixed path is still there and is
|
|
351
|
+
* still the right answer for it.
|
|
352
|
+
*/
|
|
353
|
+
readonly clusteredLights: boolean;
|
|
354
|
+
/**
|
|
355
|
+
* Skip a mesh draw whose bounds are outside the frame.
|
|
356
|
+
*
|
|
357
|
+
* **Off, and it is a behaviour change rather than a switch between two right answers.** A
|
|
358
|
+
* correct cull is invisible: the pixels are identical and the work is not done. A cull with
|
|
359
|
+
* wrong bounds is a missing object, and bounds come from vertex positions the renderer was
|
|
360
|
+
* handed — so a mesh whose geometry is displaced in its vertex shader, as foliage under wind
|
|
361
|
+
* is, occupies more space than its positions describe.
|
|
362
|
+
*
|
|
363
|
+
* A consumer that knows its own world is better placed to cull than this is: `visible` lets it
|
|
364
|
+
* skip the model matrix, the animation update and the material switch as well, none of which
|
|
365
|
+
* the renderer can avoid once it has been called. This flag exists to prove the test is right
|
|
366
|
+
* and to serve a consumer for whom that restructuring is not worth it.
|
|
367
|
+
*/
|
|
368
|
+
readonly cullDraws: boolean;
|
|
369
|
+
/**
|
|
370
|
+
* Resolve the scene through an off-screen target so screen-space effects can run.
|
|
371
|
+
*
|
|
372
|
+
* Off is not "no blur" — it is *no post-process stage at all*: the scene draws straight
|
|
373
|
+
* to the canvas as it always did, and the extra colour target and full-viewport pass are
|
|
374
|
+
* never allocated. That is the honest low-end setting, because the cost is one write and
|
|
375
|
+
* one read of every pixel and it does not shrink with a smaller effect.
|
|
376
|
+
*/
|
|
377
|
+
readonly screenEffects: boolean;
|
|
378
|
+
/**
|
|
379
|
+
* Multisample the off-screen scene target: 1 is off, 4 is the usual asked-for figure.
|
|
380
|
+
*
|
|
381
|
+
* **This is the missing half of a decision that was only half made.** The renderer asks
|
|
382
|
+
* the canvas for `antialias: !screenEffects`, and that reasoning is sound and measured:
|
|
383
|
+
* with the scene drawn into an off-screen target, the only thing reaching the default
|
|
384
|
+
* framebuffer is one fullscreen triangle, which has no interior edges to multisample.
|
|
385
|
+
* Forcing it off moved `gl.SAMPLES` from 4 to 0 with identical screenshots and saved a
|
|
386
|
+
* multisampled backbuffer and a resolve every frame. What never happened is anything
|
|
387
|
+
* replacing it, so the default configuration — every screen effect on — has had no
|
|
388
|
+
* anti-aliasing at all, and it shows on an imported model as hard-stepped edges along
|
|
389
|
+
* anything seen at a shallow angle.
|
|
390
|
+
*
|
|
391
|
+
* True multisampling rather than a post filter, because it works on geometry edges and
|
|
392
|
+
* does not touch texture detail: FXAA is cheaper and softens a 4K base colour map, which
|
|
393
|
+
* is a real loss on exactly the assets this matters for. It costs memory bandwidth
|
|
394
|
+
* proportional to the sample count and nothing else.
|
|
395
|
+
*
|
|
396
|
+
* **Defaults to 1, so nothing changes for anyone who does not ask.** Clamped to what the
|
|
397
|
+
* driver reports through `MAX_SAMPLES`, since asking for more than a part supports is a
|
|
398
|
+
* framebuffer that never completes.
|
|
399
|
+
*/
|
|
400
|
+
readonly sceneSamples: number;
|
|
401
|
+
/**
|
|
402
|
+
* Camera motion blur, 0 to 1. Off by default.
|
|
403
|
+
*
|
|
404
|
+
* Camera rather than per-object, and that is a decision rather than a stage. Per-object
|
|
405
|
+
* blur needs a velocity buffer: every mesh writing its own screen-space motion into a
|
|
406
|
+
* second render target, so a second set of matrices per draw and a wider G-buffer, which
|
|
407
|
+
* is a structural change to a forward renderer that writes one colour target. Camera blur
|
|
408
|
+
* needs only the previous view-projection, which is one matrix, and it covers the case
|
|
409
|
+
* that actually matters — a camera whipping round a turntable or through a world.
|
|
410
|
+
*
|
|
411
|
+
* Runs inside the composite pass, so it costs a depth sample and eight taps on the pixels
|
|
412
|
+
* that are moving and nothing on a still frame. Needs `screenEffects`, since without the
|
|
413
|
+
* off-screen target there is no finished image or depth to sample.
|
|
414
|
+
*/
|
|
415
|
+
readonly cameraMotionBlur: number;
|
|
416
|
+
/**
|
|
417
|
+
* Temporal antialiasing: an edge stops crawling as the camera moves. Off by default.
|
|
418
|
+
*
|
|
419
|
+
* **Antialiasing across frames instead of inside one.** The projection is jittered a fraction of
|
|
420
|
+
* a pixel each frame and the result is blended into where the last frame was, so an edge that
|
|
421
|
+
* fell one side of a pixel centre falls the other side next frame. What MSAA buys per frame this
|
|
422
|
+
* buys over eight of them, for one texture and one fullscreen pass instead of a multiplied fill
|
|
423
|
+
* rate — which is the trade a browser target wants, where MSAA on a float target is not free.
|
|
424
|
+
*
|
|
425
|
+
* **Off by default, and that is not timidity.** Jittering the projection moves every pixel of
|
|
426
|
+
* every frame by construction, so turning it on by default would change every capture in the
|
|
427
|
+
* repository and every consumer's reference images with them.
|
|
428
|
+
*
|
|
429
|
+
* The motion is the camera's: reprojection is exact for a static world under a moving camera and
|
|
430
|
+
* wrong for a moving object under a still one, which the neighbourhood clip rejects rather than
|
|
431
|
+
* corrects. A velocity buffer is what fixes that, and the README carries it as its own gap.
|
|
432
|
+
*
|
|
433
|
+
* Needs `screenEffects`, since without the off-screen target there is no finished image to
|
|
434
|
+
* resolve or depth to reproject through.
|
|
435
|
+
*/
|
|
436
|
+
readonly temporalAa: boolean;
|
|
437
|
+
/**
|
|
438
|
+
* Order-independent transparency: two panes of glass stop depending on submission order. Off by
|
|
439
|
+
* default.
|
|
440
|
+
*
|
|
441
|
+
* **Sorted alpha blending is order-dependent by construction** — `over` does not commute — so a
|
|
442
|
+
* translucent set is drawn back to front and anything the sort cannot separate wins arbitrarily
|
|
443
|
+
* or flickers: two panes that intersect, a pane containing another, a pane and the smoke inside
|
|
444
|
+
* it. Sorting harder cannot fix an intersection at all.
|
|
445
|
+
*
|
|
446
|
+
* Weighted blending replaces the ordering with a sum and a product, both of which commute. It is
|
|
447
|
+
* **exact for a single layer** and an approximation of the ordering for several, where near
|
|
448
|
+
* layers count for more than far ones — which is what a pane of glass needs and what a
|
|
449
|
+
* stained-glass window of eight overlapping leaves does not.
|
|
450
|
+
*
|
|
451
|
+
* The cost is two extra targets and a **second submission of the translucent geometry**: the
|
|
452
|
+
* accumulation and the revealage are separate blend states, and this renderer draws immediately
|
|
453
|
+
* rather than into a G-buffer. That was chosen over writing both from one pass, which would need
|
|
454
|
+
* a second fragment output and therefore another `flatFrag` permutation — measured at about
|
|
455
|
+
* 247 KB gzipped, paid by every consumer whether or not they enable this.
|
|
456
|
+
*
|
|
457
|
+
* Needs `screenEffects`, since the resolve composites over the finished scene.
|
|
458
|
+
*/
|
|
459
|
+
readonly orderIndependent: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* Depth of field: how wide the blur may reach, as a fraction of the frame's height. Off by
|
|
462
|
+
* default.
|
|
463
|
+
*
|
|
464
|
+
* **A ceiling rather than the effect**, the same split `cameraMotionBlur` takes: this says how
|
|
465
|
+
* far a defocused point may spread and therefore what the pass may cost, and
|
|
466
|
+
* `setDepthOfField` says where this frame's lens is focused and how much of the ceiling it
|
|
467
|
+
* takes. A camera focuses on a subject; a quality profile decides how expensive that is
|
|
468
|
+
* allowed to be, and a device that cannot afford eight extra taps caps it in one place.
|
|
469
|
+
*
|
|
470
|
+
* Runs inside the composite pass, so it costs a depth sample and eight taps on the pixels that
|
|
471
|
+
* are out of focus and one comparison on a frame that has not asked for it. Needs
|
|
472
|
+
* `screenEffects`, since without the off-screen target there is no finished image or depth to
|
|
473
|
+
* sample.
|
|
474
|
+
*
|
|
475
|
+
* **0.02 is a strong, visible defocus** — two per cent of the frame's height is about twenty
|
|
476
|
+
* pixels at 1080 — and 1 is the top of the range rather than a value anybody wants.
|
|
477
|
+
*/
|
|
478
|
+
readonly depthOfField: number;
|
|
479
|
+
/**
|
|
480
|
+
* Occlusion culling: how many texels wide the occlusion buffer is. **0 is off and is the
|
|
481
|
+
* default.**
|
|
482
|
+
*
|
|
483
|
+
* A width rather than a boolean, because the only dial this has is its resolution and a second
|
|
484
|
+
* option for it would be a second thing to keep in step. 256 is a reasonable frame's worth: at
|
|
485
|
+
* 16:9 that is a buffer of 256 by 144, which rasterises a handful of occluder boxes in well under
|
|
486
|
+
* a millisecond and answers a rectangle test in a few reads.
|
|
487
|
+
*
|
|
488
|
+
* **It culls nothing until a consumer declares an occluder**, which is what `addOccluder` is for.
|
|
489
|
+
* Nothing is inferred from the scene: an occluder is the box you may safely be hidden by, and
|
|
490
|
+
* only the consumer knows which of its objects that is true of. See `OcclusionBuffer`.
|
|
491
|
+
*
|
|
492
|
+
* Costs nothing on the GPU at all — the whole thing is arithmetic on the CPU, which is what lets
|
|
493
|
+
* it be identical on both backends and asserted without one.
|
|
494
|
+
*/
|
|
495
|
+
readonly occlusionCulling: number;
|
|
496
|
+
/**
|
|
497
|
+
* Ambient occlusion, 0 to 1. Off by default.
|
|
498
|
+
*
|
|
499
|
+
* Contact shading where geometry meets: a wheel arch against a tyre, a plinth against a
|
|
500
|
+
* floor, the inside of a panel gap. It is most of what makes an imported model sit in a
|
|
501
|
+
* room rather than float in it, and its absence does not read as a missing feature — it
|
|
502
|
+
* reads as the model being pasted over the picture.
|
|
503
|
+
*
|
|
504
|
+
* Depth compared against its neighbours, in the pass that already holds the depth, so it
|
|
505
|
+
* costs no extra target and no second submission of the scene. Needs `screenEffects`,
|
|
506
|
+
* since without the off-screen target there is no depth to sample; on a driver that
|
|
507
|
+
* refuses to resolve multisampled depth it turns itself off rather than sampling a
|
|
508
|
+
* texture holding whatever was there before.
|
|
509
|
+
*
|
|
510
|
+
* **1 is not the intended look.** It is the top of the range, and a value that dark is
|
|
511
|
+
* useful mostly for seeing where the effect is landing while tuning it.
|
|
512
|
+
*/
|
|
513
|
+
readonly ambientOcclusion: number;
|
|
514
|
+
/**
|
|
515
|
+
* Compile the night-side emissive term into the surface shader. Off by default.
|
|
516
|
+
*
|
|
517
|
+
* The amount is `Environment.nightEmissive` and is per frame; this decides whether the term
|
|
518
|
+
* exists at all, and it is construction-time because it changes the shader that gets compiled
|
|
519
|
+
* rather than a value uploaded to one.
|
|
520
|
+
*
|
|
521
|
+
* **It is two options rather than one because the term is not free when it is switched off**,
|
|
522
|
+
* and that was measured rather than assumed. It names `emissiveTint` and `vEmissive`, which
|
|
523
|
+
* the ordinary emissive line also names, so its mere presence lets the compiler re-plan the
|
|
524
|
+
* arithmetic they share: held on the gilded chamber with the amount at 0, **109 pixels of
|
|
525
|
+
* 750,080 moved** against the build before the term existed, where a shadow tap sat exactly on
|
|
526
|
+
* its boundary and flipped. Cut out of the source, the same scene is identical.
|
|
527
|
+
*
|
|
528
|
+
* So a consumer that wants city lights on a rotating planet asks for it and accepts that its
|
|
529
|
+
* pictures move by that much, and every consumer that does not is charged nothing and sees
|
|
530
|
+
* nothing. See `shaders/flat.ts` for the elimination that established which half cost what.
|
|
531
|
+
*/
|
|
532
|
+
readonly nightEmissive: boolean;
|
|
533
|
+
/**
|
|
534
|
+
* Bloom, 0 to 1. Off by default.
|
|
535
|
+
*
|
|
536
|
+
* How far a bright thing spreads past its own pixels. Without it an emissive surface is
|
|
537
|
+
* exactly as bright as the pixels it covers and not one wider, so anything meant to
|
|
538
|
+
* overwhelm the eye — a lamp, a star, a neon strip, a shaft of daylight — has to be built
|
|
539
|
+
* out of geometry that imitates a halo. A consumer asked for this after building one star
|
|
540
|
+
* from a core sphere, a second sphere at 1.22 times the radius and fifty-four additive
|
|
541
|
+
* particles, which is a hundred lines standing in for one pass.
|
|
542
|
+
*
|
|
543
|
+
* **Composed with `outputTransform` rather than replacing it.** The curve decides how a
|
|
544
|
+
* bright pixel rolls off; this decides how far it spreads. The bloom is added in linear
|
|
545
|
+
* scene units and the curve then rolls off the sum.
|
|
546
|
+
*
|
|
547
|
+
* **It wants `hdrScene`, and it says so at construction if it does not have it.** The
|
|
548
|
+
* threshold below is in scene units, and with an eight-bit target the scene has already been
|
|
549
|
+
* clipped to 0..1 by the time the composite sees it: a star and a sheet of white paper are
|
|
550
|
+
* the same colour there, so a threshold can only mean whiteness. Needs `screenEffects` too,
|
|
551
|
+
* since without the off-screen target there is no finished image to threshold.
|
|
552
|
+
*
|
|
553
|
+
* Deliberately absent, because they were asked against by name: lens dirt, anamorphic
|
|
554
|
+
* streaks and ghosting. One threshold, one radius, one strength.
|
|
555
|
+
*/
|
|
556
|
+
readonly bloom: number;
|
|
557
|
+
/**
|
|
558
|
+
* How bright a pixel has to be before it blooms, in scene units.
|
|
559
|
+
*
|
|
560
|
+
* 1.0 means "brighter than white", which is the useful place to start with a tone curve and
|
|
561
|
+
* an exposure: everything a surface reflects sits below it and only sources of light climb
|
|
562
|
+
* past. Lower it to bloom bright paint as well as lamps.
|
|
563
|
+
*
|
|
564
|
+
* **Subtracted rather than cut**, so there is no second knee knob and no visible edge where
|
|
565
|
+
* a gradient crosses the threshold: a pixel just over it contributes almost nothing and one
|
|
566
|
+
* far over contributes nearly all of itself.
|
|
567
|
+
*
|
|
568
|
+
* Only consulted while `bloom` is non-zero. It is not clamped to any range because a scene
|
|
569
|
+
* is free to define its own units, though it must be positive: a threshold of zero blooms
|
|
570
|
+
* the entire frame including the parts of it that are meant to be dark.
|
|
571
|
+
*/
|
|
572
|
+
readonly bloomThreshold: number;
|
|
573
|
+
/**
|
|
574
|
+
* How far the occlusion sampling reaches, in metres.
|
|
575
|
+
*
|
|
576
|
+
* A world-space radius rather than a pixel one, because contact shading is a fact about
|
|
577
|
+
* the geometry: a gap of two centimetres should darken by the same amount from across the
|
|
578
|
+
* room as from a metre away, and a radius in pixels does the opposite. It is projected to
|
|
579
|
+
* a screen radius per pixel from the depth there.
|
|
580
|
+
*
|
|
581
|
+
* The scale to match is the size of the gaps that matter. Half a metre suits a room and a
|
|
582
|
+
* vehicle; a landscape wants more, a model of a watch wants very much less.
|
|
583
|
+
*/
|
|
584
|
+
readonly ambientOcclusionRadius: number;
|
|
585
|
+
/**
|
|
586
|
+
* How many steps a global-medium march takes per pixel. **0 is off, and is the default.**
|
|
587
|
+
*
|
|
588
|
+
* A ceiling rather than the effect, in the shape `depthOfField` and `bloom` already use: this
|
|
589
|
+
* says what the pass may cost and `setGlobalMedium` says how thick this frame's air is. At 0 no
|
|
590
|
+
* target is allocated, no program is built and no composite runs, so a consumer who never asks
|
|
591
|
+
* for weather pays nothing — which is the property `scripts/medium-check.mjs` asserts by
|
|
592
|
+
* photographing a frame at density 0 against a frame with the ceiling at 0 and demanding they
|
|
593
|
+
* be identical rather than close.
|
|
594
|
+
*
|
|
595
|
+
* **It is the only thing here that costs linearly.** Each step is a shadow lookup and an
|
|
596
|
+
* exponential; the march is otherwise a fixed setup. 24 is a room, 48 is a landscape where the
|
|
597
|
+
* sun is low enough to make the steps visible as banding at fewer, and above about 48 the
|
|
598
|
+
* picture stops changing. Clamped to 64, which is the shader's own loop bound.
|
|
599
|
+
*
|
|
600
|
+
* What the medium *is* — a body of light inside a hull, or the air itself — is the distinction
|
|
601
|
+
* `globalMedium.ts` opens with: `drawLightVolume` is a shaft somebody placed, and this is
|
|
602
|
+
* everything between the camera and the wall.
|
|
603
|
+
*/
|
|
604
|
+
readonly globalMediumSteps: number;
|
|
605
|
+
/**
|
|
606
|
+
* Whether the march runs at half the frame each way. On by default, and it should stay on.
|
|
607
|
+
*
|
|
608
|
+
* Half is a quarter of the march, and what pays for it is that a homogeneous medium is smooth
|
|
609
|
+
* everywhere except at a silhouette — which is the one thing the depth-aware upsample is built
|
|
610
|
+
* to handle. Full resolution is here for a capture that has to rule the upsample out as the
|
|
611
|
+
* cause of something, and for a part with pixels to spare.
|
|
612
|
+
*/
|
|
613
|
+
readonly globalMediumHalfResolution: boolean;
|
|
614
|
+
/**
|
|
615
|
+
* Cubemap face size for a baked reflection probe. Zero is off, and is the default.
|
|
616
|
+
*
|
|
617
|
+
* A probe is how a reflective surface shows the *room* rather than a sky-and-ground gradient:
|
|
618
|
+
* a car body carrying the light panels above it and the walls around it. It is baked by the
|
|
619
|
+
* caller through `bakeReflectionProbe`, once, so it costs six submissions of the scene at that
|
|
620
|
+
* moment and one cubemap fetch per reflective pixel afterwards. Nothing per frame.
|
|
621
|
+
*
|
|
622
|
+
* **It needs a seventeenth texture unit**, and WebGL2 guarantees sixteen. On a device at the
|
|
623
|
+
* guarantee the probe is declined with a warning and reflective surfaces keep the
|
|
624
|
+
* approximation, rather than point shadows being dropped to make room. See
|
|
625
|
+
* `ENVIRONMENT_TEXTURE_UNIT`.
|
|
626
|
+
*/
|
|
627
|
+
readonly reflectionProbeSize: number;
|
|
628
|
+
/**
|
|
629
|
+
* Whether a surface may reflect its surroundings at all. On by default.
|
|
630
|
+
*
|
|
631
|
+
* **The switch beside the size, in the shape `water`/`waterReflections` and
|
|
632
|
+
* `pointShadows`/`pointShadowFaceSize` already use.** `reflectionProbeSize` says how good the
|
|
633
|
+
* reflection is and this says whether there is one, which is what a settings screen needs: a
|
|
634
|
+
* player turning reflections off should not have to know that a cubemap of zero pixels is the
|
|
635
|
+
* spelling for it, and a consumer scaling a quality preset should be able to drop the whole
|
|
636
|
+
* feature in one field rather than remembering which number means absent.
|
|
637
|
+
*
|
|
638
|
+
* **What it costs to leave on**, since that is the question this answers: one cubemap fetch per
|
|
639
|
+
* pixel of every surface that reflects anything, plus six submissions of the scene and a blur
|
|
640
|
+
* chain each time a caller bakes. Nothing per frame beyond the fetch. What it costs to turn off
|
|
641
|
+
* is the room: a metal has no diffuse term, so what it shows *is* its reflection.
|
|
642
|
+
*
|
|
643
|
+
* **Off is a defined picture rather than an absence**, which is the half worth stating. With no
|
|
644
|
+
* probe the mesh shader keeps the sky-and-ground gradient it had before probes existed —
|
|
645
|
+
* `uAmbient` above, `uAmbientGround` below, mixed by the mirror direction — so a reflective
|
|
646
|
+
* surface still reads as reflective and still varies with the view, it just carries an
|
|
647
|
+
* approximation of the sky instead of an image of the room. Nothing renders black and no caller
|
|
648
|
+
* has to branch: `bakeReflectionProbe` answers false and may be issued unconditionally.
|
|
649
|
+
*
|
|
650
|
+
* What would make this wrong: image-based lighting. With a real irradiance term and a
|
|
651
|
+
* prefiltered environment the gradient stops being the honest fallback, because there would be
|
|
652
|
+
* a cheaper *correct* answer to fall back to.
|
|
653
|
+
*/
|
|
654
|
+
readonly environmentReflections: boolean;
|
|
655
|
+
/**
|
|
656
|
+
* Samples per texel in the environment prefilter's GGX convolution.
|
|
657
|
+
*
|
|
658
|
+
* **A quality option because a phone and a workstation should not agree on it**, and it is
|
|
659
|
+
* affordable at all only because a bake happens once per scene rather than once per frame. The
|
|
660
|
+
* named tiers live in `prefilterEnvMap.ts`; this is the number one of them resolved to, so a
|
|
661
|
+
* consumer can also state its own.
|
|
662
|
+
*
|
|
663
|
+
* **What it costs:** the convolution is this many cube fetches per texel per level, against the
|
|
664
|
+
* single fetch the box-filtered chain it replaces cost. **What would make a low count wrong** is
|
|
665
|
+
* a small very bright source in an otherwise dark environment, which is the worst case for
|
|
666
|
+
* variance and is where a rough level shows the samples separately rather than as a lobe.
|
|
667
|
+
*
|
|
668
|
+
* Consulted only when a probe exists, so at the default `reflectionProbeSize` of zero this
|
|
669
|
+
* changes nothing at all.
|
|
670
|
+
*/
|
|
671
|
+
readonly environmentPrefilterSamples: number;
|
|
672
|
+
/**
|
|
673
|
+
* Whether the lit pass reads the **GGX-prefiltered** cube rather than the capture's box chain.
|
|
674
|
+
*
|
|
675
|
+
* **Off by default, and that default is a correction rather than a preference.** The prefilter
|
|
676
|
+
* shipped in 3.2.0 wired straight into the lit pass, so it changed the picture of every consumer
|
|
677
|
+
* that had a probe — which this file's own rule forbids: every feature's default reproduces
|
|
678
|
+
* today's picture, and a scene that changes because a feature was added is a regression however
|
|
679
|
+
* good it looks. It was reported as metals reading opaque, twice, before anybody connected it to
|
|
680
|
+
* a feature nobody had asked for.
|
|
681
|
+
*
|
|
682
|
+
* **What the two chains are.** A box level is a smaller picture of the room; a prefiltered level
|
|
683
|
+
* is the room convolved with the lobe for the roughness that level stands for. At the same
|
|
684
|
+
* material roughness the prefiltered one is far blurrier — which is the physically correct
|
|
685
|
+
* answer and is why it exists — so a surface authored against the box chain reads as a wash.
|
|
686
|
+
*
|
|
687
|
+
* **On is the better construction and costs a cube of memory plus the bake.** Turn it on when a
|
|
688
|
+
* scene's materials were authored for it, and note that `envLod` changes meaning with it: the
|
|
689
|
+
* texel-footprint floor is right for a box chain and a roughness combined in quadrature is right
|
|
690
|
+
* for a lobe chain, and the shader picks by this flag rather than by a guess.
|
|
691
|
+
*/
|
|
692
|
+
readonly environmentPrefilter: boolean;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/** Callers override only the levers selected by a future settings profile. */
|
|
696
|
+
export type RenderQualityOptions = Partial<RenderQuality>;
|
|
697
|
+
|
|
698
|
+
export const MAX_SHADOW_FILTER_TAPS = 12;
|
|
699
|
+
export const MAX_WATER_REFLECTION_FILTER_TAPS = 9;
|
|
700
|
+
export const POINT_SHADOW_FADE_START = 0.35;
|
|
701
|
+
export const DIRECTIONAL_SHADOW_FADE_START = 0.65;
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Current fidelity target. Different shadow projections use different texture
|
|
705
|
+
* dimensions for comparable visible detail: a cubemap spends its allocation
|
|
706
|
+
* six times, while the directional map spends all of it on one focused area.
|
|
707
|
+
*/
|
|
708
|
+
export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
|
|
709
|
+
outputTransform: 'none',
|
|
710
|
+
outputExposure: 1,
|
|
711
|
+
pointLightFalloff: 'smooth',
|
|
712
|
+
/**
|
|
713
|
+
* Render at the display's own density, up to 2×.
|
|
714
|
+
*
|
|
715
|
+
* It was 1.75, which is a number that renders *nothing* at native resolution: every
|
|
716
|
+
* retina panel reports 2, so the drawing buffer was 87% of the pixels the screen has and
|
|
717
|
+
* the browser stretched the difference. It was found by comparing a small figure in a
|
|
718
|
+
* box against the world behind it: both were blurred, and for the same reason.
|
|
719
|
+
*
|
|
720
|
+
* 2 is where the ceiling belongs. It is what the overwhelming majority of high-density
|
|
721
|
+
* displays report, so it is the point at which a game stops being upscaled; past it the
|
|
722
|
+
* cost is quadratic for detail almost nobody can resolve, which is why there is a cap at
|
|
723
|
+
* all. A device that cannot hold its rate at 2 has the Low profile, which is a decision
|
|
724
|
+
* about pixels rather than a blur applied to everyone.
|
|
725
|
+
*/
|
|
726
|
+
maxDevicePixelRatio: 2,
|
|
727
|
+
/**
|
|
728
|
+
* 12 megapixels, which is a guard rail rather than a haircut.
|
|
729
|
+
*
|
|
730
|
+
* At a density cap of 2 the drawing buffer is the panel's own pixels, so this does
|
|
731
|
+
* nothing at all up to and including 4K (8.3 MP) — the resolutions almost everybody is
|
|
732
|
+
* on keep every pixel they have. It starts holding at 5K and above, and on the
|
|
733
|
+
* high-density laptop panels whose logical size is large enough to ask for more than a
|
|
734
|
+
* 4K frame, which are exactly the cases where the density cap has stopped meaning
|
|
735
|
+
* anything about cost.
|
|
736
|
+
*
|
|
737
|
+
* A ceiling that never binds on common hardware is the point: the failure it exists to
|
|
738
|
+
* prevent is a frame that quietly grew past a vsync slot, and a cap only prevents that
|
|
739
|
+
* if it is above where people actually are. Consumers wanting the pixels set it to 0.
|
|
740
|
+
*/
|
|
741
|
+
maxDrawingBufferPixels: 12_000_000,
|
|
742
|
+
directionalShadows: true,
|
|
743
|
+
pointShadows: true,
|
|
744
|
+
/* The engine's own budgets, which the renderer lowers per device when it has to. */
|
|
745
|
+
maxLights: MAX_POINT_LIGHTS,
|
|
746
|
+
maxAreaLights: MAX_AREA_LIGHTS,
|
|
747
|
+
directionalShadowMapSize: 2048,
|
|
748
|
+
pointShadowFaceSize: 512,
|
|
749
|
+
shadowFilterTaps: MAX_SHADOW_FILTER_TAPS,
|
|
750
|
+
lightVolumeSamples: 32,
|
|
751
|
+
directionalShadowDepthLayers: 2,
|
|
752
|
+
directionalShadowMaxDistance: 6,
|
|
753
|
+
directionalShadowMaxSlope: 3,
|
|
754
|
+
pointShadowRebakeDistance: 0.4,
|
|
755
|
+
pointShadowFacesPerFrame: 2,
|
|
756
|
+
/*
|
|
757
|
+
* Twelve, which is `LIVE_POINT_SHADOW_MAPS` cubemaps of six faces: exactly what the live
|
|
758
|
+
* loop took before it had a budget at all, so no existing consumer's shadows arrive at a
|
|
759
|
+
* different moment.
|
|
760
|
+
*
|
|
761
|
+
* **Six would have been the wrong default and looked like the right one.** The budget is
|
|
762
|
+
* shared across every live map rather than granted to each, so at six the first map takes
|
|
763
|
+
* the whole cubemap and the second — the one that exists only during an ownership handoff —
|
|
764
|
+
* gets nothing and never bakes. That is a mover's shadow vanishing exactly while a character
|
|
765
|
+
* crosses between two lamps, which is the moment the handoff exists to smooth over.
|
|
766
|
+
*/
|
|
767
|
+
liveShadowFacesPerFrame: 12,
|
|
768
|
+
water: true,
|
|
769
|
+
screenEffects: true,
|
|
770
|
+
sceneSamples: 1,
|
|
771
|
+
planarReflections: false,
|
|
772
|
+
hdrScene: false,
|
|
773
|
+
cameraMotionBlur: 0,
|
|
774
|
+
temporalAa: false,
|
|
775
|
+
orderIndependent: false,
|
|
776
|
+
depthOfField: 0,
|
|
777
|
+
occlusionCulling: 0,
|
|
778
|
+
ambientOcclusion: 0,
|
|
779
|
+
nightEmissive: false,
|
|
780
|
+
bloom: 0,
|
|
781
|
+
/* Brighter than white, which is where a source of light sits and a reflecting surface does
|
|
782
|
+
not. Only consulted once the strength above is non-zero, and positive for the same reason
|
|
783
|
+
the occlusion radius is: a zero left sitting here would look legal and bloom the whole
|
|
784
|
+
frame the moment somebody turned the effect on. */
|
|
785
|
+
bloomThreshold: 1,
|
|
786
|
+
/* Off: a probe only exists once a caller bakes one, so nothing changes by default. */
|
|
787
|
+
reflectionProbeSize: 0,
|
|
788
|
+
/* On, because the cost of the feature is the probe and this only says whether one is allowed:
|
|
789
|
+
with the size at its own default of zero, leaving this true changes nothing at all. */
|
|
790
|
+
environmentReflections: true,
|
|
791
|
+
/* The medium tier. Powers of two only; see PREFILTER_SAMPLE_COUNTS for why. */
|
|
792
|
+
environmentPrefilterSamples: PREFILTER_SAMPLE_COUNTS.medium,
|
|
793
|
+
/* Off: the shipped look is the box chain. See the field for why the default is this way round. */
|
|
794
|
+
environmentPrefilter: false,
|
|
795
|
+
/* Half a metre, which is the scale of the gaps in a room and around a vehicle. Only
|
|
796
|
+
consulted when the strength above is non-zero, so it changes nothing by default. */
|
|
797
|
+
ambientOcclusionRadius: 0.5,
|
|
798
|
+
/* Off, so the medium costs nothing until a consumer asks for it. See the field. */
|
|
799
|
+
globalMediumSteps: 0,
|
|
800
|
+
/* Half, which is the resolution the upsample was designed against. */
|
|
801
|
+
globalMediumHalfResolution: true,
|
|
802
|
+
waterResolution: 128,
|
|
803
|
+
waterReflections: true,
|
|
804
|
+
/*
|
|
805
|
+
* Full, and deliberately not the half the GPU-budget design proposed as a free win.
|
|
806
|
+
*
|
|
807
|
+
* It is not free. The reflection is a second full submission of the scene, but with the
|
|
808
|
+
* GPU timer finally armed it measures **0.50 ms of an 18.00 ms frame** — the same 3%
|
|
809
|
+
* category the 72% shadow claim collapsed into. Trading a visibly softer reflection on
|
|
810
|
+
* every machine for 3% none of them needed is not a win, and it is worse than that in
|
|
811
|
+
* one place: this is construction-time, so a clip export cannot ask for full scale back,
|
|
812
|
+
* and an export is the one frame somebody keeps.
|
|
813
|
+
*
|
|
814
|
+
* The devices that genuinely cannot afford the target get it halved by the capability
|
|
815
|
+
* clamp in `renderer.ts` instead, where the cost is paid by the parts that need it paid.
|
|
816
|
+
*/
|
|
817
|
+
waterReflectionScale: 1,
|
|
818
|
+
waterReflectionFilterTaps: MAX_WATER_REFLECTION_FILTER_TAPS,
|
|
819
|
+
underwaterAtmosphere: true,
|
|
820
|
+
plumeNoiseOctaves: 3,
|
|
821
|
+
capabilityClamp: true,
|
|
822
|
+
/*
|
|
823
|
+
* **Both back ON in 1.1.2, because the black screen they were turned off for was not them.**
|
|
824
|
+
*
|
|
825
|
+
* These are the only two changes in this engine whose correctness an immediate-mode desktop
|
|
826
|
+
* GPU physically cannot express: a discarded attachment costs nothing and changes nothing
|
|
827
|
+
* where the samples have nowhere else to be, and taking the swap chain late is
|
|
828
|
+
* indistinguishable from taking it early until a browser disagrees about when a frame is
|
|
829
|
+
* presented. So when all three consumers came back completely black on an iPhone 16 Pro,
|
|
830
|
+
* these two were the obvious suspects and both were defaulted off.
|
|
831
|
+
*
|
|
832
|
+
* They were not the cause and turning them off never lifted the black screen. It was a
|
|
833
|
+
* uniform array striding by four bytes where WGSL requires sixteen, which WebKit enforces
|
|
834
|
+
* and Dawn does not, so every shader that draws geometry failed to compile on iOS and
|
|
835
|
+
* nowhere else. Fixed in 1.1.1; the iOS black-screen investigation is
|
|
836
|
+
* the investigation, and the retreat here is the clearest thing it cost.
|
|
837
|
+
*
|
|
838
|
+
* **What leaving them off costs, measured on the gilded chamber at a phone viewport with
|
|
839
|
+
* `npm run frame-audit`:** 75.6 MB a frame against 49.7, which is 4.43 GB/s against 2.91 at
|
|
840
|
+
* 60 fps, and thirteen passes against twelve. Nearly all of it is the deferral — off it is
|
|
841
|
+
* 51.2 MB on its own, because opening the frame's pass eagerly forces a load and a store of
|
|
842
|
+
* the attachment for every mirror. The discard adds the last 1.5 MB and takes the frame's
|
|
843
|
+
* unreadable writes to zero. That is the entire mobile bandwidth result of 1.1.0, and it was
|
|
844
|
+
* being paid on exactly the devices it was measured for.
|
|
845
|
+
*
|
|
846
|
+
* **Still unverified on a tiler, and that has not changed.** What changed is that there is no
|
|
847
|
+
* longer an observed failure to attribute to them. `?discard=0` and `?defer=0` turn them off
|
|
848
|
+
* one at a time in all three consumers, so a device that misbehaves still names its own cause
|
|
849
|
+
* in two reloads.
|
|
850
|
+
*/
|
|
851
|
+
discardResolvedAttachments: true,
|
|
852
|
+
deferFramePass: true,
|
|
853
|
+
frameGraph: true,
|
|
854
|
+
clusteredLights: false,
|
|
855
|
+
cullDraws: false,
|
|
856
|
+
/*
|
|
857
|
+
* The profiler stays off, and for its own reason rather than that one: it attaches a
|
|
858
|
+
* timestamp block to every render pass in the frame, which is a cost nobody who did not ask
|
|
859
|
+
* for a measurement should pay. `?gputiming=1` arms it.
|
|
860
|
+
*/
|
|
861
|
+
gpuTiming: false,
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
/** Resolve and validate once at renderer construction, never in a hot path. */
|
|
865
|
+
export function resolveRenderQuality(options: RenderQualityOptions = {}): Readonly<RenderQuality> {
|
|
866
|
+
const quality: RenderQuality = {
|
|
867
|
+
outputTransform: options.outputTransform ?? DEFAULT_RENDER_QUALITY.outputTransform,
|
|
868
|
+
outputExposure: options.outputExposure ?? DEFAULT_RENDER_QUALITY.outputExposure,
|
|
869
|
+
pointLightFalloff: options.pointLightFalloff ?? DEFAULT_RENDER_QUALITY.pointLightFalloff,
|
|
870
|
+
maxDevicePixelRatio: options.maxDevicePixelRatio ?? DEFAULT_RENDER_QUALITY.maxDevicePixelRatio,
|
|
871
|
+
maxDrawingBufferPixels:
|
|
872
|
+
options.maxDrawingBufferPixels ?? DEFAULT_RENDER_QUALITY.maxDrawingBufferPixels,
|
|
873
|
+
directionalShadows: options.directionalShadows ?? DEFAULT_RENDER_QUALITY.directionalShadows,
|
|
874
|
+
pointShadows: options.pointShadows ?? DEFAULT_RENDER_QUALITY.pointShadows,
|
|
875
|
+
/* Whole slots, at least one, never above what the shader is written for: these two are
|
|
876
|
+
interpolated into the source as array sizes, so a fractional or zero one is a shader that
|
|
877
|
+
does not compile and a larger one is arrays the uploads never fill. */
|
|
878
|
+
maxLights: Math.min(
|
|
879
|
+
MAX_POINT_LIGHTS,
|
|
880
|
+
Math.max(1, Math.round(options.maxLights ?? DEFAULT_RENDER_QUALITY.maxLights)),
|
|
881
|
+
),
|
|
882
|
+
maxAreaLights: Math.min(
|
|
883
|
+
MAX_AREA_LIGHTS,
|
|
884
|
+
Math.max(1, Math.round(options.maxAreaLights ?? DEFAULT_RENDER_QUALITY.maxAreaLights)),
|
|
885
|
+
),
|
|
886
|
+
directionalShadowMapSize:
|
|
887
|
+
options.directionalShadowMapSize ?? DEFAULT_RENDER_QUALITY.directionalShadowMapSize,
|
|
888
|
+
pointShadowFaceSize: options.pointShadowFaceSize ?? DEFAULT_RENDER_QUALITY.pointShadowFaceSize,
|
|
889
|
+
shadowFilterTaps: options.shadowFilterTaps ?? DEFAULT_RENDER_QUALITY.shadowFilterTaps,
|
|
890
|
+
lightVolumeSamples: options.lightVolumeSamples ?? DEFAULT_RENDER_QUALITY.lightVolumeSamples,
|
|
891
|
+
directionalShadowDepthLayers:
|
|
892
|
+
options.directionalShadowDepthLayers ?? DEFAULT_RENDER_QUALITY.directionalShadowDepthLayers,
|
|
893
|
+
directionalShadowMaxDistance:
|
|
894
|
+
options.directionalShadowMaxDistance ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxDistance,
|
|
895
|
+
directionalShadowMaxSlope:
|
|
896
|
+
options.directionalShadowMaxSlope ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxSlope,
|
|
897
|
+
pointShadowRebakeDistance:
|
|
898
|
+
options.pointShadowRebakeDistance ?? DEFAULT_RENDER_QUALITY.pointShadowRebakeDistance,
|
|
899
|
+
pointShadowFacesPerFrame:
|
|
900
|
+
options.pointShadowFacesPerFrame ?? DEFAULT_RENDER_QUALITY.pointShadowFacesPerFrame,
|
|
901
|
+
liveShadowFacesPerFrame:
|
|
902
|
+
options.liveShadowFacesPerFrame ?? DEFAULT_RENDER_QUALITY.liveShadowFacesPerFrame,
|
|
903
|
+
water: options.water ?? DEFAULT_RENDER_QUALITY.water,
|
|
904
|
+
screenEffects: options.screenEffects ?? DEFAULT_RENDER_QUALITY.screenEffects,
|
|
905
|
+
sceneSamples: Math.max(
|
|
906
|
+
1,
|
|
907
|
+
Math.round(options.sceneSamples ?? DEFAULT_RENDER_QUALITY.sceneSamples),
|
|
908
|
+
),
|
|
909
|
+
planarReflections: options.planarReflections ?? DEFAULT_RENDER_QUALITY.planarReflections,
|
|
910
|
+
hdrScene: options.hdrScene ?? DEFAULT_RENDER_QUALITY.hdrScene,
|
|
911
|
+
cameraMotionBlur: Math.min(
|
|
912
|
+
1,
|
|
913
|
+
Math.max(0, options.cameraMotionBlur ?? DEFAULT_RENDER_QUALITY.cameraMotionBlur),
|
|
914
|
+
),
|
|
915
|
+
temporalAa: options.temporalAa ?? DEFAULT_RENDER_QUALITY.temporalAa,
|
|
916
|
+
orderIndependent: options.orderIndependent ?? DEFAULT_RENDER_QUALITY.orderIndependent,
|
|
917
|
+
depthOfField: Math.min(
|
|
918
|
+
1,
|
|
919
|
+
Math.max(0, options.depthOfField ?? DEFAULT_RENDER_QUALITY.depthOfField),
|
|
920
|
+
),
|
|
921
|
+
occlusionCulling: Math.max(
|
|
922
|
+
0,
|
|
923
|
+
Math.round(options.occlusionCulling ?? DEFAULT_RENDER_QUALITY.occlusionCulling),
|
|
924
|
+
),
|
|
925
|
+
ambientOcclusion: Math.min(
|
|
926
|
+
1,
|
|
927
|
+
Math.max(0, options.ambientOcclusion ?? DEFAULT_RENDER_QUALITY.ambientOcclusion),
|
|
928
|
+
),
|
|
929
|
+
nightEmissive: options.nightEmissive ?? DEFAULT_RENDER_QUALITY.nightEmissive,
|
|
930
|
+
bloom: Math.min(1, Math.max(0, options.bloom ?? DEFAULT_RENDER_QUALITY.bloom)),
|
|
931
|
+
bloomThreshold: options.bloomThreshold ?? DEFAULT_RENDER_QUALITY.bloomThreshold,
|
|
932
|
+
reflectionProbeSize: Math.max(
|
|
933
|
+
0,
|
|
934
|
+
Math.round(options.reflectionProbeSize ?? DEFAULT_RENDER_QUALITY.reflectionProbeSize),
|
|
935
|
+
),
|
|
936
|
+
environmentReflections:
|
|
937
|
+
options.environmentReflections ?? DEFAULT_RENDER_QUALITY.environmentReflections,
|
|
938
|
+
/* At least one sample: zero would divide by an accumulated weight of zero and answer NaN,
|
|
939
|
+
which a half-float target spreads across every rough level rather than reporting. */
|
|
940
|
+
environmentPrefilterSamples: Math.max(
|
|
941
|
+
1,
|
|
942
|
+
Math.round(
|
|
943
|
+
options.environmentPrefilterSamples ?? DEFAULT_RENDER_QUALITY.environmentPrefilterSamples,
|
|
944
|
+
),
|
|
945
|
+
),
|
|
946
|
+
environmentPrefilter:
|
|
947
|
+
options.environmentPrefilter ?? DEFAULT_RENDER_QUALITY.environmentPrefilter,
|
|
948
|
+
ambientOcclusionRadius:
|
|
949
|
+
options.ambientOcclusionRadius ?? DEFAULT_RENDER_QUALITY.ambientOcclusionRadius,
|
|
950
|
+
/* Whole steps, and never past the shader's own loop bound: a uniform above it would make the
|
|
951
|
+
clamp inside the shader disagree with the step length computed from it, which is a march
|
|
952
|
+
that stops short of where it divided its distance. */
|
|
953
|
+
globalMediumSteps: Math.min(
|
|
954
|
+
MAX_GLOBAL_MEDIUM_STEPS,
|
|
955
|
+
Math.max(
|
|
956
|
+
0,
|
|
957
|
+
Math.round(options.globalMediumSteps ?? DEFAULT_RENDER_QUALITY.globalMediumSteps),
|
|
958
|
+
),
|
|
959
|
+
),
|
|
960
|
+
globalMediumHalfResolution:
|
|
961
|
+
options.globalMediumHalfResolution ?? DEFAULT_RENDER_QUALITY.globalMediumHalfResolution,
|
|
962
|
+
waterResolution: options.waterResolution ?? DEFAULT_RENDER_QUALITY.waterResolution,
|
|
963
|
+
waterReflections: options.waterReflections ?? DEFAULT_RENDER_QUALITY.waterReflections,
|
|
964
|
+
waterReflectionScale:
|
|
965
|
+
options.waterReflectionScale ?? DEFAULT_RENDER_QUALITY.waterReflectionScale,
|
|
966
|
+
capabilityClamp: options.capabilityClamp ?? DEFAULT_RENDER_QUALITY.capabilityClamp,
|
|
967
|
+
gpuTiming: options.gpuTiming ?? DEFAULT_RENDER_QUALITY.gpuTiming,
|
|
968
|
+
discardResolvedAttachments:
|
|
969
|
+
options.discardResolvedAttachments ?? DEFAULT_RENDER_QUALITY.discardResolvedAttachments,
|
|
970
|
+
deferFramePass: options.deferFramePass ?? DEFAULT_RENDER_QUALITY.deferFramePass,
|
|
971
|
+
frameGraph: options.frameGraph ?? DEFAULT_RENDER_QUALITY.frameGraph,
|
|
972
|
+
clusteredLights: options.clusteredLights ?? DEFAULT_RENDER_QUALITY.clusteredLights,
|
|
973
|
+
cullDraws: options.cullDraws ?? DEFAULT_RENDER_QUALITY.cullDraws,
|
|
974
|
+
waterReflectionFilterTaps:
|
|
975
|
+
options.waterReflectionFilterTaps ?? DEFAULT_RENDER_QUALITY.waterReflectionFilterTaps,
|
|
976
|
+
underwaterAtmosphere:
|
|
977
|
+
options.underwaterAtmosphere ?? DEFAULT_RENDER_QUALITY.underwaterAtmosphere,
|
|
978
|
+
plumeNoiseOctaves: options.plumeNoiseOctaves ?? DEFAULT_RENDER_QUALITY.plumeNoiseOctaves,
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
positive('maxDevicePixelRatio', quality.maxDevicePixelRatio);
|
|
982
|
+
// Zero is legal and means uncapped, so this is the non-negative check rather than
|
|
983
|
+
// the positive one.
|
|
984
|
+
nonNegative('maxDrawingBufferPixels', quality.maxDrawingBufferPixels);
|
|
985
|
+
positiveInteger('directionalShadowMapSize', quality.directionalShadowMapSize);
|
|
986
|
+
positiveInteger('pointShadowFaceSize', quality.pointShadowFaceSize);
|
|
987
|
+
positiveInteger('shadowFilterTaps', quality.shadowFilterTaps);
|
|
988
|
+
positiveInteger('lightVolumeSamples', quality.lightVolumeSamples);
|
|
989
|
+
positiveInteger('directionalShadowDepthLayers', quality.directionalShadowDepthLayers);
|
|
990
|
+
positive('directionalShadowMaxDistance', quality.directionalShadowMaxDistance);
|
|
991
|
+
positive('directionalShadowMaxSlope', quality.directionalShadowMaxSlope);
|
|
992
|
+
nonNegative('pointShadowRebakeDistance', quality.pointShadowRebakeDistance);
|
|
993
|
+
positiveInteger('pointShadowFacesPerFrame', quality.pointShadowFacesPerFrame);
|
|
994
|
+
positiveInteger('liveShadowFacesPerFrame', quality.liveShadowFacesPerFrame);
|
|
995
|
+
positiveInteger('waterResolution', quality.waterResolution);
|
|
996
|
+
positive('waterReflectionScale', quality.waterReflectionScale);
|
|
997
|
+
positiveInteger('waterReflectionFilterTaps', quality.waterReflectionFilterTaps);
|
|
998
|
+
positiveInteger('plumeNoiseOctaves', quality.plumeNoiseOctaves);
|
|
999
|
+
/* A radius of zero would ask every tap to land on the pixel it started from, which is not
|
|
1000
|
+
"no occlusion" — it is a division by nothing in the estimator. Off is the strength. */
|
|
1001
|
+
positive('ambientOcclusionRadius', quality.ambientOcclusionRadius);
|
|
1002
|
+
/* Same shape as the radius above: a threshold of zero is not "bloom everything a little",
|
|
1003
|
+
it is every pixel in the frame contributing its whole self. Off is the strength. */
|
|
1004
|
+
positive('bloomThreshold', quality.bloomThreshold);
|
|
1005
|
+
if (
|
|
1006
|
+
quality.shadowFilterTaps !== 4 &&
|
|
1007
|
+
quality.shadowFilterTaps !== 8 &&
|
|
1008
|
+
quality.shadowFilterTaps !== MAX_SHADOW_FILTER_TAPS
|
|
1009
|
+
) {
|
|
1010
|
+
throw new Error(
|
|
1011
|
+
`RenderQuality.shadowFilterTaps must be 4, 8 or ${MAX_SHADOW_FILTER_TAPS}, got ${quality.shadowFilterTaps}`,
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
if (quality.directionalShadowDepthLayers !== 1 && quality.directionalShadowDepthLayers !== 2) {
|
|
1015
|
+
throw new Error(
|
|
1016
|
+
`RenderQuality.directionalShadowDepthLayers must be 1 or 2, got ${quality.directionalShadowDepthLayers}`,
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
if (quality.plumeNoiseOctaves > 3) {
|
|
1020
|
+
throw new Error(
|
|
1021
|
+
`RenderQuality.plumeNoiseOctaves must be <= 3, got ${quality.plumeNoiseOctaves}`,
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
if (
|
|
1025
|
+
quality.waterReflectionFilterTaps !== 1 &&
|
|
1026
|
+
quality.waterReflectionFilterTaps !== 5 &&
|
|
1027
|
+
quality.waterReflectionFilterTaps !== MAX_WATER_REFLECTION_FILTER_TAPS
|
|
1028
|
+
) {
|
|
1029
|
+
throw new Error(
|
|
1030
|
+
`RenderQuality.waterReflectionFilterTaps must be 1, 5 or ${MAX_WATER_REFLECTION_FILTER_TAPS}, got ${quality.waterReflectionFilterTaps}`,
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
return Object.freeze(quality);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
function positive(name: string, value: number): void {
|
|
1037
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
1038
|
+
throw new Error(`RenderQuality.${name} must be a positive finite number, got ${value}`);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/** Zero is meaningful for a tolerance: it asks for the exact comparison. */
|
|
1043
|
+
function nonNegative(name: string, value: number): void {
|
|
1044
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
1045
|
+
throw new Error(`RenderQuality.${name} must be a non-negative finite number, got ${value}`);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
function positiveInteger(name: string, value: number): void {
|
|
1050
|
+
positive(name, value);
|
|
1051
|
+
if (!Number.isInteger(value)) {
|
|
1052
|
+
throw new Error(`RenderQuality.${name} must be an integer, got ${value}`);
|
|
1053
|
+
}
|
|
1054
|
+
}
|