@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,1032 @@
|
|
|
1
|
+
import { glSceneDepthFormat } from './depthConvention.ts';
|
|
2
|
+
import { AmbientOcclusionPass } from './ambientOcclusionPass.ts';
|
|
3
|
+
import { BloomPass } from './bloomPass.ts';
|
|
4
|
+
import {
|
|
5
|
+
type ColourGradeLut,
|
|
6
|
+
GRADE_PLACEHOLDER_SIZE,
|
|
7
|
+
identityGradeLut,
|
|
8
|
+
validateGradeLut,
|
|
9
|
+
} from './colourGrade.ts';
|
|
10
|
+
import { compileProgram, uniformLocations } from './shader.ts';
|
|
11
|
+
import { TemporalPass } from './temporalPass.ts';
|
|
12
|
+
import { FULLSCREEN_VERT } from './shaders/fullscreen.ts';
|
|
13
|
+
import { RUSH_FRAG } from './shaders/rush.ts';
|
|
14
|
+
import type { Vec3 } from '../math/color.ts';
|
|
15
|
+
|
|
16
|
+
/** No veil, so a caller that omits the argument gets exactly the frame it always got. */
|
|
17
|
+
const NO_VEIL: Vec3 = [0, 0, 0];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* An off-screen colour target for the frame, and the pass that resolves it to the canvas.
|
|
21
|
+
*
|
|
22
|
+
* The renderer drew straight to the canvas, which is the right default and is why this is
|
|
23
|
+
* opt-in: with nothing to sample a finished frame from, no screen-space effect can exist at
|
|
24
|
+
* all. A speed blur faked with a compositor filter over the canvas gets the boundary
|
|
25
|
+
* wrong in both directions: it is too strong, and it cannot leave the HUD alone. The
|
|
26
|
+
* effect belongs to the 3D scene, so the scene needs somewhere to land before it is shown.
|
|
27
|
+
*
|
|
28
|
+
* **It resolves to the canvas, always.** Two consumers depend on that and neither is
|
|
29
|
+
* optional: a frame recorder reads the canvas to build a clip, and a still is a canvas
|
|
30
|
+
* copy. Leaving the scene in a framebuffer would produce a black export while the screen
|
|
31
|
+
* looked correct, which is the worst shape a bug can have.
|
|
32
|
+
*
|
|
33
|
+
* Sized from the drawing buffer and rebuilt when that changes, so a resize, a DPR change
|
|
34
|
+
* and an export lock all land on an exactly-sized target rather than a stretched one. The
|
|
35
|
+
* depth buffer lives here too: a scene drawn into a colour attachment with the canvas's
|
|
36
|
+
* depth buffer would have no depth at all.
|
|
37
|
+
*/
|
|
38
|
+
export class SceneTarget {
|
|
39
|
+
private framebuffer: WebGLFramebuffer | null = null;
|
|
40
|
+
private texture: WebGLTexture | null = null;
|
|
41
|
+
/**
|
|
42
|
+
* Depth as a *texture* rather than a renderbuffer, so the composite pass can read it.
|
|
43
|
+
*
|
|
44
|
+
* A renderbuffer is write-only from a shader's point of view, and every screen-space
|
|
45
|
+
* effect worth having needs the depth back: motion blur reconstructs a world position
|
|
46
|
+
* from it to reproject through the previous view, and ambient occlusion is nothing but
|
|
47
|
+
* depth compared against its neighbours. Costing the same memory and being sampleable,
|
|
48
|
+
* there is no reason for it to be anything else.
|
|
49
|
+
*/
|
|
50
|
+
private depth: WebGLTexture | null = null;
|
|
51
|
+
/**
|
|
52
|
+
* A copy of the frame's depth taken mid-pass, for anything that must read it while drawing.
|
|
53
|
+
*
|
|
54
|
+
* **Not `depth` itself, and the distinction is the whole reason this exists.** `depth` is the
|
|
55
|
+
* attachment the frame is testing against, and sampling a texture that is attached to the
|
|
56
|
+
* bound framebuffer is undefined in WebGL2 — it draws something plausible on this driver and
|
|
57
|
+
* something else on the next. So a volume of light, which has to know where the opaque scene
|
|
58
|
+
* is in order to stop marching at it, reads this instead.
|
|
59
|
+
*
|
|
60
|
+
* Filled by `snapshotDepth`, on demand, and only in frames that ask.
|
|
61
|
+
*/
|
|
62
|
+
private depthCopy: WebGLTexture | null = null;
|
|
63
|
+
private depthCopyFramebuffer: WebGLFramebuffer | null = null;
|
|
64
|
+
/** Whether this frame has filled it. One snapshot serves every volume in a frame. */
|
|
65
|
+
private depthCopyFilled = false;
|
|
66
|
+
/**
|
|
67
|
+
* The colour the frame had already drawn when something first asked for it.
|
|
68
|
+
*
|
|
69
|
+
* **A copy and never the attachment**, which is the difference `colorAttachment` documents from
|
|
70
|
+
* the other side: that one returns null while multisampling, because the frame lives in a
|
|
71
|
+
* renderbuffer until `resolve` blits into it. A blit from a multisampled source to a
|
|
72
|
+
* single-sampled destination *is* a resolve, so this answers in exactly the configuration where
|
|
73
|
+
* reading the attachment cannot.
|
|
74
|
+
*
|
|
75
|
+
* Filled by `snapshotColor`, on demand, and only in frames that ask.
|
|
76
|
+
*/
|
|
77
|
+
private colorCopy: WebGLTexture | null = null;
|
|
78
|
+
private colorCopyFramebuffer: WebGLFramebuffer | null = null;
|
|
79
|
+
/** Whether this frame has filled it. One snapshot serves every refracting draw in a frame. */
|
|
80
|
+
private colorCopyFilled = false;
|
|
81
|
+
/**
|
|
82
|
+
* The colour grade, as a 3D texture on unit 4, and the table it was built from.
|
|
83
|
+
*
|
|
84
|
+
* **The source is kept to compare identities, not to read.** A grade is set every frame by a
|
|
85
|
+
* consumer that has one, and re-uploading a 32-lattice table is 131 kilobytes of `texImage3D`
|
|
86
|
+
* sixty times a second for bytes that did not change. Comparing the object is what makes
|
|
87
|
+
* `setColourGrade` free to call from a frame loop — and a consumer crossfading between two
|
|
88
|
+
* grades holds two objects, which compare unequal and upload once each on the swap.
|
|
89
|
+
*/
|
|
90
|
+
private gradeTexture: WebGLTexture | null = null;
|
|
91
|
+
private gradeSource: ColourGradeLut | null = null;
|
|
92
|
+
private gradeSize = GRADE_PLACEHOLDER_SIZE;
|
|
93
|
+
private gradeStrength = 0;
|
|
94
|
+
private width = 0;
|
|
95
|
+
private height = 0;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The multisampled pair, present only when a caller asked for samples.
|
|
99
|
+
*
|
|
100
|
+
* Two framebuffers rather than one, because a multisampled attachment cannot be sampled
|
|
101
|
+
* by a shader: the scene is drawn into `msaaFramebuffer`, blitted down into the ordinary
|
|
102
|
+
* texture, and the post chain reads that exactly as it always has. Everything downstream
|
|
103
|
+
* of the blit is unchanged, which is what keeps this a quality option rather than a
|
|
104
|
+
* second rendering path.
|
|
105
|
+
*/
|
|
106
|
+
private msaaFramebuffer: WebGLFramebuffer | null = null;
|
|
107
|
+
private msaaColor: WebGLRenderbuffer | null = null;
|
|
108
|
+
private msaaDepth: WebGLRenderbuffer | null = null;
|
|
109
|
+
/** What was actually allocated, after clamping to what the driver reports. */
|
|
110
|
+
private samples = 1;
|
|
111
|
+
/** Whether anything actually reads the resolved depth. Nothing is copied if not. */
|
|
112
|
+
private depthWanted = false;
|
|
113
|
+
/** Set once if the driver refuses the depth copy, so it is attempted once and not per frame. */
|
|
114
|
+
private depthBlitRefused = false;
|
|
115
|
+
|
|
116
|
+
private readonly program: WebGLProgram;
|
|
117
|
+
private readonly uniforms: Record<string, WebGLUniformLocation | null>;
|
|
118
|
+
private readonly vao: WebGLVertexArrayObject;
|
|
119
|
+
/**
|
|
120
|
+
* Built the first time a caller asks for occlusion, and never for one that does not.
|
|
121
|
+
*
|
|
122
|
+
* Two programs and two full-frame targets is not a thing to allocate on the chance somebody
|
|
123
|
+
* turns the option on later: the option is construction-time, so a renderer that was not
|
|
124
|
+
* asked for it will never be.
|
|
125
|
+
*/
|
|
126
|
+
private ao: AmbientOcclusionPass | null = null;
|
|
127
|
+
/** Built the first time a caller asks for bloom, on the same terms as the occlusion pass. */
|
|
128
|
+
private bloom: BloomPass | null = null;
|
|
129
|
+
/** Built on the first frame that asks for it, like `bloom` beside it. */
|
|
130
|
+
private temporal: TemporalPass | null = null;
|
|
131
|
+
/** Whether the colour attachments hold half floats. See the constructor. */
|
|
132
|
+
private floatColor = false;
|
|
133
|
+
|
|
134
|
+
constructor(
|
|
135
|
+
private readonly gl: WebGL2RenderingContext,
|
|
136
|
+
requestedSamples = 1,
|
|
137
|
+
wantsRange = false,
|
|
138
|
+
/**
|
|
139
|
+
* Whether the multisampled buffers may be thrown away once blitted down.
|
|
140
|
+
*
|
|
141
|
+
* True is correct and saves a full attachment write per frame on a tiler. It is a switch
|
|
142
|
+
* because, like WebGPU's `storeOp: 'discard'`, it is invisible on an immediate-mode desktop
|
|
143
|
+
* part and therefore cannot be verified by a screenshot: see
|
|
144
|
+
* `RenderQuality.discardResolvedAttachments`.
|
|
145
|
+
*/
|
|
146
|
+
private readonly discardResolved = true,
|
|
147
|
+
) {
|
|
148
|
+
/*
|
|
149
|
+
* Clamped to MAX_SAMPLES rather than trusted. Asking for more than the part supports
|
|
150
|
+
* produces a framebuffer that never completes, and an incomplete framebuffer is a black
|
|
151
|
+
* frame with no GL error attached to explain it.
|
|
152
|
+
*/
|
|
153
|
+
const maximum = gl.getParameter(gl.MAX_SAMPLES) as number;
|
|
154
|
+
this.samples = Math.max(
|
|
155
|
+
1,
|
|
156
|
+
Math.min(Math.round(requestedSamples), Number.isFinite(maximum) ? maximum : 1),
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* A float colour target where the part will render to one, and eight bits where it will not.
|
|
161
|
+
*
|
|
162
|
+
* **The reason it matters is what a composite can still tell apart.** With an eight-bit
|
|
163
|
+
* target the scene has already been squashed into 0 to 1 by the time anything downstream
|
|
164
|
+
* looks at it, so a star at five times white and a sheet of white paper arrive identical and
|
|
165
|
+
* nothing can treat them differently. Half floats keep the difference, which is what makes a
|
|
166
|
+
* bloom threshold mean brightness rather than mean whiteness, and it is why the tone curve
|
|
167
|
+
* moved from the mesh pass to the resolve: a curve applied before the buffer throws away the
|
|
168
|
+
* range the buffer exists to keep.
|
|
169
|
+
*
|
|
170
|
+
* `EXT_color_buffer_float` is required for this in WebGL2 and is absent on some parts, so it
|
|
171
|
+
* is asked for rather than assumed. Without it the target stays eight-bit and everything
|
|
172
|
+
* still draws: values clip where they always clipped.
|
|
173
|
+
*/
|
|
174
|
+
this.floatColor = wantsRange && gl.getExtension('EXT_color_buffer_float') !== null;
|
|
175
|
+
|
|
176
|
+
this.program = compileProgram(gl, FULLSCREEN_VERT, RUSH_FRAG, 'rush');
|
|
177
|
+
this.uniforms = uniformLocations(gl, this.program, 'sceneTarget');
|
|
178
|
+
/*
|
|
179
|
+
* A VAO with no attributes: the fullscreen triangle is built from `gl_VertexID`, so
|
|
180
|
+
* there is nothing to bind. WebGL2 still requires *a* vertex array to be bound for a
|
|
181
|
+
* draw, and binding one with no state is cheaper than leaving whatever the previous
|
|
182
|
+
* pass left attached.
|
|
183
|
+
*/
|
|
184
|
+
const vao = gl.createVertexArray();
|
|
185
|
+
if (vao === null) throw new Error('SceneTarget: createVertexArray failed');
|
|
186
|
+
this.vao = vao;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Match the target to the drawing buffer. Cheap when unchanged. */
|
|
190
|
+
private ensureSize(width: number, height: number): void {
|
|
191
|
+
if (this.width === width && this.height === height && this.framebuffer !== null) return;
|
|
192
|
+
const { gl } = this;
|
|
193
|
+
this.width = width;
|
|
194
|
+
this.height = height;
|
|
195
|
+
|
|
196
|
+
if (this.texture === null) this.texture = gl.createTexture();
|
|
197
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
198
|
+
if (this.floatColor) {
|
|
199
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, width, height, 0, gl.RGBA, gl.HALF_FLOAT, null);
|
|
200
|
+
} else {
|
|
201
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
202
|
+
}
|
|
203
|
+
// Linear, because the blur samples between texels; clamped, because a tap that
|
|
204
|
+
// wrapped would pull the opposite edge of the screen into the corner.
|
|
205
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
206
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
207
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
208
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
209
|
+
|
|
210
|
+
const sceneDepth = glSceneDepthFormat(gl);
|
|
211
|
+
if (this.depth === null) this.depth = gl.createTexture();
|
|
212
|
+
gl.bindTexture(gl.TEXTURE_2D, this.depth);
|
|
213
|
+
gl.texImage2D(
|
|
214
|
+
gl.TEXTURE_2D,
|
|
215
|
+
0,
|
|
216
|
+
sceneDepth.internalFormat,
|
|
217
|
+
width,
|
|
218
|
+
height,
|
|
219
|
+
0,
|
|
220
|
+
gl.DEPTH_COMPONENT,
|
|
221
|
+
sceneDepth.type,
|
|
222
|
+
null,
|
|
223
|
+
);
|
|
224
|
+
/* NEAREST, and not a preference: a depth texture with no compare mode cannot be
|
|
225
|
+
linearly filtered, and asking for it makes the sample come back undefined. */
|
|
226
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
227
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
228
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
229
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
230
|
+
|
|
231
|
+
/* The mid-pass copy, same format as the depth it is blitted from — `blitFramebuffer`
|
|
232
|
+
refuses a depth copy between formats that do not match exactly. See `depthCopy`. */
|
|
233
|
+
if (this.depthCopy === null) this.depthCopy = gl.createTexture();
|
|
234
|
+
gl.bindTexture(gl.TEXTURE_2D, this.depthCopy);
|
|
235
|
+
gl.texImage2D(
|
|
236
|
+
gl.TEXTURE_2D,
|
|
237
|
+
0,
|
|
238
|
+
sceneDepth.internalFormat,
|
|
239
|
+
width,
|
|
240
|
+
height,
|
|
241
|
+
0,
|
|
242
|
+
gl.DEPTH_COMPONENT,
|
|
243
|
+
sceneDepth.type,
|
|
244
|
+
null,
|
|
245
|
+
);
|
|
246
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
247
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
248
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
249
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
250
|
+
|
|
251
|
+
/*
|
|
252
|
+
* The colour copy, and its format follows the scene texture exactly.
|
|
253
|
+
*
|
|
254
|
+
* **`blitFramebuffer` refuses a copy between formats that do not match**, which is the same
|
|
255
|
+
* constraint the depth copy above is built under — so an HDR profile copies `RGBA16F` and an
|
|
256
|
+
* LDR one `RGBA8`, chosen by the flag the scene texture itself reads.
|
|
257
|
+
*
|
|
258
|
+
* `LINEAR` filtering, because a refracting draw samples at an offset that lands between
|
|
259
|
+
* texels; `CLAMP_TO_EDGE`, because a sample that wrapped would pull the opposite edge of the
|
|
260
|
+
* screen into a pane at the frame's border, which reads as a tear.
|
|
261
|
+
*/
|
|
262
|
+
if (this.colorCopy === null) this.colorCopy = gl.createTexture();
|
|
263
|
+
gl.bindTexture(gl.TEXTURE_2D, this.colorCopy);
|
|
264
|
+
if (this.floatColor) {
|
|
265
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, width, height, 0, gl.RGBA, gl.HALF_FLOAT, null);
|
|
266
|
+
} else {
|
|
267
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
268
|
+
}
|
|
269
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
270
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
271
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
272
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
273
|
+
|
|
274
|
+
/*
|
|
275
|
+
* Colour only, and no depth attachment at all — the mirror image of the depth copy below,
|
|
276
|
+
* which attaches depth and switches the colour buffers off by name. **They are kept apart
|
|
277
|
+
* deliberately**: this file records a combined colour-and-depth blit losing the colour
|
|
278
|
+
* because the driver disliked the depth, and the depth-only path losing the depth for a
|
|
279
|
+
* missing colour target. One blit, one buffer bit, each time.
|
|
280
|
+
*/
|
|
281
|
+
if (this.colorCopyFramebuffer === null) this.colorCopyFramebuffer = gl.createFramebuffer();
|
|
282
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.colorCopyFramebuffer);
|
|
283
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.colorCopy, 0);
|
|
284
|
+
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
|
|
285
|
+
/* Loud, once, at allocation. A refracting draw then shades as an ordinary translucent one
|
|
286
|
+
and says why, rather than quietly disagreeing with the other backend. */
|
|
287
|
+
console.warn(
|
|
288
|
+
'SceneTarget: this driver will not give a colour-only framebuffer, so a refracting ' +
|
|
289
|
+
'surface cannot read the scene behind it and will draw as ordinary glass.',
|
|
290
|
+
);
|
|
291
|
+
gl.deleteFramebuffer(this.colorCopyFramebuffer);
|
|
292
|
+
this.colorCopyFramebuffer = null;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (this.depthCopyFramebuffer === null) this.depthCopyFramebuffer = gl.createFramebuffer();
|
|
296
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.depthCopyFramebuffer);
|
|
297
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this.depthCopy, 0);
|
|
298
|
+
/*
|
|
299
|
+
* **Depth only, and the colour buffers have to be switched off by name.**
|
|
300
|
+
*
|
|
301
|
+
* A framebuffer with a depth attachment and no colour one still advertises
|
|
302
|
+
* `COLOR_ATTACHMENT0` as its draw and read buffer, and a `blitFramebuffer` into it is
|
|
303
|
+
* refused for the missing colour target — taking the depth half of the copy with it, since
|
|
304
|
+
* the call fails whole. `resolve` documents the same trap from the other direction, where a
|
|
305
|
+
* combined colour+depth blit lost the colour because the driver disliked the depth.
|
|
306
|
+
*
|
|
307
|
+
* Without these two lines the copy silently never happened: `snapshotDepth` returned null,
|
|
308
|
+
* `uSceneDepthEnabled` stayed 0, and WebGL2 kept marching through the floor while WebGPU
|
|
309
|
+
* clamped. Two backends doing different things with nothing said about it, which is the
|
|
310
|
+
* 2026-08-13 rule exactly — and it was found from a capture pair whose only disagreement
|
|
311
|
+
* was the band of floor the clamp acts on.
|
|
312
|
+
*/
|
|
313
|
+
gl.drawBuffers([gl.NONE]);
|
|
314
|
+
gl.readBuffer(gl.NONE);
|
|
315
|
+
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
|
|
316
|
+
/* Loud, once, at allocation. A volume then draws unclamped on this driver and says why,
|
|
317
|
+
rather than quietly disagreeing with the other backend. */
|
|
318
|
+
console.warn(
|
|
319
|
+
'SceneTarget: this driver will not give a depth-only framebuffer, so light volumes ' +
|
|
320
|
+
'cannot clamp to the scene and will march through it. The frame is unaffected.',
|
|
321
|
+
);
|
|
322
|
+
gl.deleteFramebuffer(this.depthCopyFramebuffer);
|
|
323
|
+
this.depthCopyFramebuffer = null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (this.framebuffer === null) this.framebuffer = gl.createFramebuffer();
|
|
327
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
|
|
328
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0);
|
|
329
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this.depth, 0);
|
|
330
|
+
|
|
331
|
+
if (this.samples > 1) {
|
|
332
|
+
if (this.msaaColor === null) this.msaaColor = gl.createRenderbuffer();
|
|
333
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, this.msaaColor);
|
|
334
|
+
gl.renderbufferStorageMultisample(
|
|
335
|
+
gl.RENDERBUFFER,
|
|
336
|
+
this.samples,
|
|
337
|
+
this.floatColor ? gl.RGBA16F : gl.RGBA8,
|
|
338
|
+
width,
|
|
339
|
+
height,
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
if (this.msaaDepth === null) this.msaaDepth = gl.createRenderbuffer();
|
|
343
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, this.msaaDepth);
|
|
344
|
+
/*
|
|
345
|
+
* **Must match the resolve target's format exactly**, or `blitFramebuffer` refuses the depth
|
|
346
|
+
* half of the copy — so it follows the same convention the depth texture does rather than
|
|
347
|
+
* naming a format of its own. It said 24-bit here for as long as the texture was 24-bit;
|
|
348
|
+
* making the texture float and leaving this behind produced
|
|
349
|
+
* `GL_INVALID_OPERATION: glBlitFramebuffer: Depth/stencil buffer format combination not
|
|
350
|
+
* allowed for blit` on every scene with MSAA, which is what the pixel gate reported first.
|
|
351
|
+
*/
|
|
352
|
+
gl.renderbufferStorageMultisample(
|
|
353
|
+
gl.RENDERBUFFER,
|
|
354
|
+
this.samples,
|
|
355
|
+
glSceneDepthFormat(gl).internalFormat,
|
|
356
|
+
width,
|
|
357
|
+
height,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
if (this.msaaFramebuffer === null) this.msaaFramebuffer = gl.createFramebuffer();
|
|
361
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.msaaFramebuffer);
|
|
362
|
+
gl.framebufferRenderbuffer(
|
|
363
|
+
gl.FRAMEBUFFER,
|
|
364
|
+
gl.COLOR_ATTACHMENT0,
|
|
365
|
+
gl.RENDERBUFFER,
|
|
366
|
+
this.msaaColor,
|
|
367
|
+
);
|
|
368
|
+
gl.framebufferRenderbuffer(
|
|
369
|
+
gl.FRAMEBUFFER,
|
|
370
|
+
gl.DEPTH_ATTACHMENT,
|
|
371
|
+
gl.RENDERBUFFER,
|
|
372
|
+
this.msaaDepth,
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
/*
|
|
376
|
+
* Checked here rather than discovered as a black frame. A multisampled attachment can
|
|
377
|
+
* be refused for a combination the driver does not support even after the sample count
|
|
378
|
+
* was clamped, and the honest response is to fall back to no multisampling and carry
|
|
379
|
+
* on drawing, rather than to render nothing.
|
|
380
|
+
*/
|
|
381
|
+
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
|
|
382
|
+
this.releaseMultisample();
|
|
383
|
+
this.samples = 1;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
388
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
389
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
private releaseMultisample(): void {
|
|
393
|
+
const { gl } = this;
|
|
394
|
+
if (this.msaaFramebuffer !== null) gl.deleteFramebuffer(this.msaaFramebuffer);
|
|
395
|
+
if (this.msaaColor !== null) gl.deleteRenderbuffer(this.msaaColor);
|
|
396
|
+
if (this.msaaDepth !== null) gl.deleteRenderbuffer(this.msaaDepth);
|
|
397
|
+
this.msaaFramebuffer = null;
|
|
398
|
+
this.msaaColor = null;
|
|
399
|
+
this.msaaDepth = null;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** Bind the off-screen target for a frame. The caller clears as it normally would. */
|
|
403
|
+
begin(width: number, height: number): void {
|
|
404
|
+
this.ensureSize(width, height);
|
|
405
|
+
/* Last frame's snapshot is last frame's scene. See `snapshotDepth`. */
|
|
406
|
+
this.depthCopyFilled = false;
|
|
407
|
+
this.colorCopyFilled = false;
|
|
408
|
+
this.bind();
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Point drawing back at this target, at its own size.
|
|
413
|
+
*
|
|
414
|
+
* Needed because every borrowing pass — the shadow maps, the planar reflection — hands
|
|
415
|
+
* the framebuffer back by binding `null`, which is the *canvas*, not the frame's target.
|
|
416
|
+
* Without somewhere to come back to, everything drawn after a reflection would land on
|
|
417
|
+
* the canvas and then be overwritten by the resolve of a half-empty target: a black
|
|
418
|
+
* frame from a renderer that looked correct in isolation.
|
|
419
|
+
*/
|
|
420
|
+
bind(): void {
|
|
421
|
+
const { gl } = this;
|
|
422
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.msaaFramebuffer ?? this.framebuffer);
|
|
423
|
+
gl.viewport(0, 0, this.width, this.height);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Whether this target keeps values above 1, which decides where the tone curve belongs.
|
|
428
|
+
*
|
|
429
|
+
* False on a part without `EXT_color_buffer_float`, where the scene is squashed into 0 to 1 on
|
|
430
|
+
* the way in exactly as it always was.
|
|
431
|
+
*/
|
|
432
|
+
get keepsRange(): boolean {
|
|
433
|
+
return this.floatColor;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** How many samples the scene is actually being drawn with. 1 means no multisampling. */
|
|
437
|
+
get sampleCount(): number {
|
|
438
|
+
return this.samples;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** The frame's depth, resolved and sampleable, for screen-space effects that need it. */
|
|
442
|
+
get depthTexture(): WebGLTexture | null {
|
|
443
|
+
return this.depth;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Copy the depth drawn so far, so something still drawing can read it. Returns what to bind.
|
|
448
|
+
*
|
|
449
|
+
* **Once per frame however many callers ask**, because they all want the same thing: where
|
|
450
|
+
* the opaque scene is. `begin` clears the latch.
|
|
451
|
+
*
|
|
452
|
+
* The blit is from whichever framebuffer the frame is actually rendering into — the
|
|
453
|
+
* multisampled one where there is one — and it restores that binding afterwards, because the
|
|
454
|
+
* caller is in the middle of a pass and expects to carry on drawing into it. Forgetting that
|
|
455
|
+
* is a frame that finishes into the wrong target and comes out empty.
|
|
456
|
+
*
|
|
457
|
+
* Null where the copy could not be made, and the caller must read that as "no clamp" rather
|
|
458
|
+
* than as a texture full of zeros — a depth of zero is the near plane, which would clamp every
|
|
459
|
+
* march to nothing and delete every beam in the scene.
|
|
460
|
+
*/
|
|
461
|
+
/**
|
|
462
|
+
* The depth the frame is testing against, for a pass that must test against it too.
|
|
463
|
+
*
|
|
464
|
+
* **Not `snapshotDepth`, and the difference matters.** That returns a *copy*, for a pass that
|
|
465
|
+
* samples depth while the attachment is bound; this is the attachment itself, for a pass that
|
|
466
|
+
* attaches it and depth-tests against it without writing. Order-independent transparency needs
|
|
467
|
+
* the second: its two passes reject a pane behind a wall exactly where the wall is, and both
|
|
468
|
+
* must reject it in the same place or the accumulation and the revealage cover different
|
|
469
|
+
* fragments.
|
|
470
|
+
*/
|
|
471
|
+
depthAttachment(): WebGLTexture | null {
|
|
472
|
+
return this.depth;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* The colour the frame has drawn so far, for a pass that reads the picture rather than the depth.
|
|
477
|
+
*
|
|
478
|
+
* **Null while multisampling, and that is the honest answer rather than a missing feature.** With
|
|
479
|
+
* samples above one the frame is drawn into a renderbuffer and this texture holds nothing until
|
|
480
|
+
* `resolve` blits into it — so a pass running mid-frame would read the frame before last. A
|
|
481
|
+
* caller that needs the finished picture in the middle of the frame is asking for something a
|
|
482
|
+
* multisampled attachment cannot give without a resolve of its own.
|
|
483
|
+
*/
|
|
484
|
+
colorAttachment(): WebGLTexture | null {
|
|
485
|
+
return this.msaaFramebuffer === null ? this.texture : null;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* The colour the frame has drawn so far, copied so a draw can sample it while still drawing.
|
|
490
|
+
*
|
|
491
|
+
* **A copy and never the attachment.** Sampling a texture attached to the bound framebuffer is
|
|
492
|
+
* undefined in WebGL2 — it draws something plausible on this driver and something else on the
|
|
493
|
+
* next — and `colorAttachment` returns null under multisampling anyway. A blit answers both:
|
|
494
|
+
* it detaches the read, and from a multisampled source it resolves.
|
|
495
|
+
*
|
|
496
|
+
* **Latched, and the latch is the same trap `snapshotDepth` documents.** One copy serves every
|
|
497
|
+
* refracting draw in a frame, so glass does not refract other glass — which is correct, a pane
|
|
498
|
+
* behind a pane should show the room. What it also means is that opaque geometry drawn *after*
|
|
499
|
+
* the first refracting draw is missing from what a pane shows. Draw the world, then the glass;
|
|
500
|
+
* a caller that must have the later geometry asks `afresh` and pays another blit.
|
|
501
|
+
*
|
|
502
|
+
* Null where the copy could not be made, and a caller must read that as "do not refract" rather
|
|
503
|
+
* than as a black texture — refracting against black paints every pane the colour of a hole.
|
|
504
|
+
*/
|
|
505
|
+
snapshotColor(afresh = false): WebGLTexture | null {
|
|
506
|
+
if (this.colorCopy === null || this.colorCopyFramebuffer === null) return null;
|
|
507
|
+
if (this.colorCopyFilled && !afresh) return this.colorCopy;
|
|
508
|
+
const { gl } = this;
|
|
509
|
+
const source = this.msaaFramebuffer ?? this.framebuffer;
|
|
510
|
+
if (source === null) return null;
|
|
511
|
+
|
|
512
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, source);
|
|
513
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.colorCopyFramebuffer);
|
|
514
|
+
/* Drained first, for the reason `resolve` gives at length: `getError` reports whatever is
|
|
515
|
+
pending from anywhere, so a check that does not start clean blames this call for somebody
|
|
516
|
+
else's mistake — and did, once, permanently disabling an effect. */
|
|
517
|
+
while (gl.getError() !== gl.NO_ERROR) {
|
|
518
|
+
/* discard whatever was already pending */
|
|
519
|
+
}
|
|
520
|
+
/* `NEAREST` because the rectangles are the same size, so there is nothing to filter and the
|
|
521
|
+
choice only decides which refusals are possible. */
|
|
522
|
+
gl.blitFramebuffer(
|
|
523
|
+
0,
|
|
524
|
+
0,
|
|
525
|
+
this.width,
|
|
526
|
+
this.height,
|
|
527
|
+
0,
|
|
528
|
+
0,
|
|
529
|
+
this.width,
|
|
530
|
+
this.height,
|
|
531
|
+
gl.COLOR_BUFFER_BIT,
|
|
532
|
+
gl.NEAREST,
|
|
533
|
+
);
|
|
534
|
+
const refused = gl.getError() !== gl.NO_ERROR;
|
|
535
|
+
/* Back to what the caller was drawing into, whichever that was. */
|
|
536
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, source);
|
|
537
|
+
if (refused) return null;
|
|
538
|
+
this.colorCopyFilled = true;
|
|
539
|
+
return this.colorCopy;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
snapshotDepth(
|
|
543
|
+
/**
|
|
544
|
+
* Take the copy again even though one has already been taken this frame.
|
|
545
|
+
*
|
|
546
|
+
* **The latch that makes this cheap is also the trap in it.** A beam asks for the depth in
|
|
547
|
+
* the middle of the frame, so the copy holds the world *as it stood then* — and a pass that
|
|
548
|
+
* runs once every draw is in and reuses that copy marks a scene missing everything drawn
|
|
549
|
+
* after the beam. The symptom is a decal landing on a wall that is no longer the nearest
|
|
550
|
+
* thing, which reads as a depth-test bug rather than as a stale texture.
|
|
551
|
+
*
|
|
552
|
+
* So a caller at the end of the frame asks for it afresh, and pays one more blit on the
|
|
553
|
+
* frames where something had already asked. `begin` clears the latch either way.
|
|
554
|
+
*/
|
|
555
|
+
afresh = false,
|
|
556
|
+
): WebGLTexture | null {
|
|
557
|
+
if (this.depthCopy === null || this.depthCopyFramebuffer === null) return null;
|
|
558
|
+
if (this.depthCopyFilled && !afresh) return this.depthCopy;
|
|
559
|
+
const { gl } = this;
|
|
560
|
+
const source = this.msaaFramebuffer ?? this.framebuffer;
|
|
561
|
+
if (source === null) return null;
|
|
562
|
+
|
|
563
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, source);
|
|
564
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.depthCopyFramebuffer);
|
|
565
|
+
/* Drained first, for the reason `resolve` gives at length: `getError` reports whatever is
|
|
566
|
+
pending from anywhere, so a check that does not start clean blames this call for
|
|
567
|
+
somebody else's mistake — and did, once, permanently disabling an effect. */
|
|
568
|
+
while (gl.getError() !== gl.NO_ERROR) {
|
|
569
|
+
/* discard whatever was already pending */
|
|
570
|
+
}
|
|
571
|
+
gl.blitFramebuffer(
|
|
572
|
+
0,
|
|
573
|
+
0,
|
|
574
|
+
this.width,
|
|
575
|
+
this.height,
|
|
576
|
+
0,
|
|
577
|
+
0,
|
|
578
|
+
this.width,
|
|
579
|
+
this.height,
|
|
580
|
+
gl.DEPTH_BUFFER_BIT,
|
|
581
|
+
gl.NEAREST,
|
|
582
|
+
);
|
|
583
|
+
const refused = gl.getError() !== gl.NO_ERROR;
|
|
584
|
+
/* Back to what the caller was drawing into, whichever that was. */
|
|
585
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, source);
|
|
586
|
+
if (refused) return null;
|
|
587
|
+
this.depthCopyFilled = true;
|
|
588
|
+
return this.depthCopy;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Resolve the scene to the canvas, blurred by `strength`.
|
|
593
|
+
*
|
|
594
|
+
* Depth and blending are explicitly off for the pass: it is one opaque triangle over the
|
|
595
|
+
* whole viewport, and inheriting a depth test from the last scene draw would let it fail
|
|
596
|
+
* against nothing.
|
|
597
|
+
*/
|
|
598
|
+
/**
|
|
599
|
+
* The colour grade this and every later frame applies, until it is set again.
|
|
600
|
+
*
|
|
601
|
+
* **Held rather than passed to `resolve`**, because a lookup table is a *texture* and every
|
|
602
|
+
* other texture this pass reads is owned here. The alternative is a ninth parameter on a call
|
|
603
|
+
* that already takes eight, carrying an object the caller would then have to keep stable
|
|
604
|
+
* anyway.
|
|
605
|
+
*
|
|
606
|
+
* `null`, or a strength at or below zero, is exactly the frame that existed before the effect
|
|
607
|
+
* did: the shader's branch is on a uniform, so no fetch happens at all.
|
|
608
|
+
*/
|
|
609
|
+
setColourGrade(lut: ColourGradeLut | null, strength: number): void {
|
|
610
|
+
this.gradeStrength = lut === null ? 0 : Math.max(0, Math.min(1, strength));
|
|
611
|
+
if (lut === null || lut === this.gradeSource) return;
|
|
612
|
+
validateGradeLut(lut);
|
|
613
|
+
this.uploadGrade(lut);
|
|
614
|
+
this.gradeSource = lut;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Put a table on the device, replacing whatever was there.
|
|
619
|
+
*
|
|
620
|
+
* `RGBA8` with `LINEAR` in every direction and `CLAMP_TO_EDGE` on all three axes. The filtering
|
|
621
|
+
* is the whole point — an unfiltered 32-lattice table bands, which is the one artefact a grade
|
|
622
|
+
* must never introduce — and the clamp is what makes the texel-centre coordinate safe at the
|
|
623
|
+
* ends of the range rather than wrapping black round to white.
|
|
624
|
+
*/
|
|
625
|
+
private uploadGrade(lut: ColourGradeLut): void {
|
|
626
|
+
const { gl } = this;
|
|
627
|
+
this.gradeTexture ??= gl.createTexture();
|
|
628
|
+
gl.activeTexture(gl.TEXTURE4);
|
|
629
|
+
gl.bindTexture(gl.TEXTURE_3D, this.gradeTexture);
|
|
630
|
+
gl.texImage3D(
|
|
631
|
+
gl.TEXTURE_3D,
|
|
632
|
+
0,
|
|
633
|
+
gl.RGBA8,
|
|
634
|
+
lut.size,
|
|
635
|
+
lut.size,
|
|
636
|
+
lut.size,
|
|
637
|
+
0,
|
|
638
|
+
gl.RGBA,
|
|
639
|
+
gl.UNSIGNED_BYTE,
|
|
640
|
+
lut.data,
|
|
641
|
+
);
|
|
642
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
643
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
644
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
645
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
646
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
|
|
647
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
648
|
+
this.gradeSize = lut.size;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
resolve(
|
|
652
|
+
strength: number,
|
|
653
|
+
reachUv: number,
|
|
654
|
+
/* The grade, applied here because this is the last pass. See RUSH_FRAG's own note. */
|
|
655
|
+
grade: { readonly transform: number; readonly exposure: number } = {
|
|
656
|
+
transform: 0,
|
|
657
|
+
exposure: 1,
|
|
658
|
+
},
|
|
659
|
+
motion?: {
|
|
660
|
+
readonly reprojection: Float32Array;
|
|
661
|
+
readonly strength: number;
|
|
662
|
+
readonly max: number;
|
|
663
|
+
},
|
|
664
|
+
ao?: {
|
|
665
|
+
readonly strength: number;
|
|
666
|
+
readonly radius: number;
|
|
667
|
+
/** The projection's x and y scales, which turn a world radius into a screen one. */
|
|
668
|
+
readonly projScale: Float32Array;
|
|
669
|
+
readonly invProjection: Float32Array;
|
|
670
|
+
},
|
|
671
|
+
bloom?: {
|
|
672
|
+
readonly strength: number;
|
|
673
|
+
/** In scene units, which is why this wants `keepsRange`. See `BloomPass`. */
|
|
674
|
+
readonly threshold: number;
|
|
675
|
+
},
|
|
676
|
+
/*
|
|
677
|
+
* Depth of field, between the camera smear and the occlusion in the shader's own order. Like
|
|
678
|
+
* `motion` and `ao` it needs the depth, and like them it is absent rather than zeroed when the
|
|
679
|
+
* frame has not asked — so a renderer nobody asked for it never resolves a depth buffer to
|
|
680
|
+
* feed it.
|
|
681
|
+
*/
|
|
682
|
+
dof?: {
|
|
683
|
+
/** Where the lens is focused, in metres. */
|
|
684
|
+
readonly distance: number;
|
|
685
|
+
/** How many metres either side of that stay sharp. */
|
|
686
|
+
readonly range: number;
|
|
687
|
+
/** How far the blur may reach, as a fraction of the frame's height. */
|
|
688
|
+
readonly strength: number;
|
|
689
|
+
/** `(m[10], m[14], m[11], m[15])` of the inverse projection. See `uDepthToView`. */
|
|
690
|
+
readonly depthToView: Float32Array;
|
|
691
|
+
},
|
|
692
|
+
/*
|
|
693
|
+
* The frame veil, composited last of everything this pass does. See
|
|
694
|
+
* `Renderer.setFrameVeil` for why it sits here rather than upstream or downstream of the
|
|
695
|
+
* grade. Defaulted rather than optional: the shader always reads both uniforms, so a
|
|
696
|
+
* caller that never veils anything uploads the same two numbers it always would have.
|
|
697
|
+
*/
|
|
698
|
+
veilColor: Vec3 = NO_VEIL,
|
|
699
|
+
veilAlpha = 0,
|
|
700
|
+
/*
|
|
701
|
+
* The temporal resolve, appended rather than placed beside the other effects because
|
|
702
|
+
* `veilColor` and `veilAlpha` are positional defaults and every existing caller passes them
|
|
703
|
+
* by position.
|
|
704
|
+
*/
|
|
705
|
+
temporal?: { readonly reprojection: Float32Array; readonly blend: number },
|
|
706
|
+
): void {
|
|
707
|
+
const { gl } = this;
|
|
708
|
+
this.depthWanted =
|
|
709
|
+
motion !== undefined || ao !== undefined || dof !== undefined || temporal !== undefined;
|
|
710
|
+
/*
|
|
711
|
+
* Down from the multisampled buffer into the texture first, because a shader cannot
|
|
712
|
+
* sample a multisampled attachment. NEAREST is the only filter `blitFramebuffer` accepts
|
|
713
|
+
* for a same-size resolve, and the two are the same size by construction.
|
|
714
|
+
*/
|
|
715
|
+
if (this.msaaFramebuffer !== null) {
|
|
716
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.msaaFramebuffer);
|
|
717
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.framebuffer);
|
|
718
|
+
/*
|
|
719
|
+
* **Colour on its own, always, and depth as a separate call that is allowed to fail.**
|
|
720
|
+
*
|
|
721
|
+
* These were one blit with both bits set, and that shipped a black game. A driver may
|
|
722
|
+
* refuse a depth copy for a format combination it does not like, and `blitFramebuffer`
|
|
723
|
+
* refuses the *whole* call when it does — so a disagreement about depth took the
|
|
724
|
+
* colour with it and the frame resolved to nothing. The symptom is total and the cause
|
|
725
|
+
* is a flag in a bitmask.
|
|
726
|
+
*
|
|
727
|
+
* Split, the worst case is losing the effect that wanted depth. The frame is never at
|
|
728
|
+
* risk, which is the only acceptable ordering: this method's contract is that the scene
|
|
729
|
+
* reaches the canvas.
|
|
730
|
+
*/
|
|
731
|
+
gl.blitFramebuffer(
|
|
732
|
+
0,
|
|
733
|
+
0,
|
|
734
|
+
this.width,
|
|
735
|
+
this.height,
|
|
736
|
+
0,
|
|
737
|
+
0,
|
|
738
|
+
this.width,
|
|
739
|
+
this.height,
|
|
740
|
+
gl.COLOR_BUFFER_BIT,
|
|
741
|
+
gl.NEAREST,
|
|
742
|
+
);
|
|
743
|
+
if (this.depthWanted && !this.depthBlitRefused) {
|
|
744
|
+
/*
|
|
745
|
+
* Drained first, and this is not defensive tidiness. `getError` returns whatever
|
|
746
|
+
* error is *pending*, from anywhere, and clears it — so a check that does not start
|
|
747
|
+
* from a clean queue attributes somebody else's mistake to this call. That happened
|
|
748
|
+
* here immediately: an unrelated error elsewhere in the frame was read as the driver
|
|
749
|
+
* refusing depth, which switched motion blur off permanently and silently.
|
|
750
|
+
*/
|
|
751
|
+
while (gl.getError() !== gl.NO_ERROR) {
|
|
752
|
+
/* discard whatever was already pending */
|
|
753
|
+
}
|
|
754
|
+
gl.blitFramebuffer(
|
|
755
|
+
0,
|
|
756
|
+
0,
|
|
757
|
+
this.width,
|
|
758
|
+
this.height,
|
|
759
|
+
0,
|
|
760
|
+
0,
|
|
761
|
+
this.width,
|
|
762
|
+
this.height,
|
|
763
|
+
gl.DEPTH_BUFFER_BIT,
|
|
764
|
+
gl.NEAREST,
|
|
765
|
+
);
|
|
766
|
+
/*
|
|
767
|
+
* Asked once rather than every frame: `getError` is a synchronisation point, and a
|
|
768
|
+
* format combination that was refused on the first frame will be refused on every
|
|
769
|
+
* one. After that the effect that wanted depth simply does not run.
|
|
770
|
+
*/
|
|
771
|
+
if (gl.getError() !== gl.NO_ERROR) {
|
|
772
|
+
this.depthBlitRefused = true;
|
|
773
|
+
console.warn(
|
|
774
|
+
'SceneTarget: this driver will not resolve multisampled depth, so effects that ' +
|
|
775
|
+
'read it are off. The frame itself is unaffected.',
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/*
|
|
780
|
+
* **Thrown away the moment they have been blitted down, which is WebGL2's half of the
|
|
781
|
+
* same statement `storeOp: 'discard'` makes on the other backend.**
|
|
782
|
+
*
|
|
783
|
+
* The blit above is the resolve, and on its own it is only half of one: the multisampled
|
|
784
|
+
* renderbuffers still hold contents the driver has no reason to believe are finished
|
|
785
|
+
* with, so a tile-based GPU dutifully writes all four samples out to memory at the end of
|
|
786
|
+
* the pass. Nothing can ever read them — a multisampled renderbuffer cannot be sampled by
|
|
787
|
+
* a shader at all, which is the entire reason this blit exists — so the write buys
|
|
788
|
+
* nothing and costs a full attachment.
|
|
789
|
+
*
|
|
790
|
+
* Measured on the WebGPU side of the same frame at 824x1830 with four samples: 23 MB per
|
|
791
|
+
* attachment, and the game keeps two of them. On a desktop part it is invisible, which is
|
|
792
|
+
* why it survived; on a phone it is a share of the memory bandwidth the frame has.
|
|
793
|
+
*
|
|
794
|
+
* **Before the unbind, deliberately.** `invalidateFramebuffer` acts on whatever is bound
|
|
795
|
+
* to the target it is given, so moving these two lines below the ones that follow would
|
|
796
|
+
* discard the default framebuffer instead — which is the frame.
|
|
797
|
+
*/
|
|
798
|
+
if (this.discardResolved) {
|
|
799
|
+
gl.invalidateFramebuffer(gl.READ_FRAMEBUFFER, [gl.COLOR_ATTACHMENT0, gl.DEPTH_ATTACHMENT]);
|
|
800
|
+
}
|
|
801
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
|
|
802
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
|
|
803
|
+
}
|
|
804
|
+
/*
|
|
805
|
+
* Occlusion before the composite, because the composite consumes it, and after the
|
|
806
|
+
* resolve above, because it reads the depth that resolve produced. It leaves the
|
|
807
|
+
* framebuffer unbound and the viewport its own, both of which the composite sets again
|
|
808
|
+
* below.
|
|
809
|
+
*/
|
|
810
|
+
let aoTexture: WebGLTexture | null = null;
|
|
811
|
+
if (ao !== undefined && !this.depthBlitRefused && this.depth !== null) {
|
|
812
|
+
this.ao ??= new AmbientOcclusionPass(gl);
|
|
813
|
+
aoTexture = this.ao.run(
|
|
814
|
+
this.depth,
|
|
815
|
+
this.width,
|
|
816
|
+
this.height,
|
|
817
|
+
ao.radius,
|
|
818
|
+
ao.projScale,
|
|
819
|
+
ao.invProjection,
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/*
|
|
824
|
+
* Bloom beside occlusion rather than after the composite, because the composite is what
|
|
825
|
+
* consumes it. It reads the resolved colour rather than the depth, so it is independent of
|
|
826
|
+
* the blit above having produced anything, and it leaves the framebuffer unbound and the
|
|
827
|
+
* viewport its own — both of which the composite sets again below.
|
|
828
|
+
*/
|
|
829
|
+
/*
|
|
830
|
+
* **The temporal resolve happens before all of it**, and what it returns is what everything
|
|
831
|
+
* below must treat as the scene. Bloom, occlusion and the grade each read the scene texture,
|
|
832
|
+
* and reading the unresolved one would put the crawl the resolve just removed back on screen
|
|
833
|
+
* through the bloom — a stable picture lit by an unstable one.
|
|
834
|
+
*/
|
|
835
|
+
let scene = this.texture;
|
|
836
|
+
if (temporal !== undefined && this.texture !== null && this.depth !== null) {
|
|
837
|
+
this.temporal ??= new TemporalPass(gl, this.floatColor);
|
|
838
|
+
scene = this.temporal.temporalResolve(
|
|
839
|
+
this.texture,
|
|
840
|
+
this.depth,
|
|
841
|
+
temporal.reprojection,
|
|
842
|
+
this.width,
|
|
843
|
+
this.height,
|
|
844
|
+
temporal.blend,
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
let bloomTexture: WebGLTexture | null = null;
|
|
849
|
+
if (bloom !== undefined && scene !== null) {
|
|
850
|
+
this.bloom ??= new BloomPass(gl);
|
|
851
|
+
bloomTexture = this.bloom.run(scene, this.width, this.height, bloom.threshold);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
855
|
+
gl.viewport(0, 0, this.width, this.height);
|
|
856
|
+
gl.disable(gl.DEPTH_TEST);
|
|
857
|
+
gl.disable(gl.BLEND);
|
|
858
|
+
gl.disable(gl.CULL_FACE);
|
|
859
|
+
gl.depthMask(false);
|
|
860
|
+
|
|
861
|
+
gl.useProgram(this.program);
|
|
862
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
863
|
+
gl.bindTexture(gl.TEXTURE_2D, scene);
|
|
864
|
+
gl.uniform1i(this.uniforms['uScene'] ?? null, 0);
|
|
865
|
+
gl.uniform1f(this.uniforms['uStrength'] ?? null, strength);
|
|
866
|
+
gl.uniform1f(this.uniforms['uReach'] ?? null, reachUv);
|
|
867
|
+
gl.uniform1i(this.uniforms['uOutputTransform'] ?? null, grade.transform);
|
|
868
|
+
gl.uniform1f(this.uniforms['uOutputExposure'] ?? null, grade.exposure);
|
|
869
|
+
|
|
870
|
+
/*
|
|
871
|
+
* Depth on its own unit, and the reprojection with it. Bound every frame rather than
|
|
872
|
+
* once, because a texture unit is context state and any pass between two frames is free
|
|
873
|
+
* to have left something else there.
|
|
874
|
+
*/
|
|
875
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
876
|
+
gl.bindTexture(gl.TEXTURE_2D, this.depth);
|
|
877
|
+
gl.uniform1i(this.uniforms['uDepth'] ?? null, 1);
|
|
878
|
+
/* Off if the driver would not give the depth back, so the shader never samples a
|
|
879
|
+
texture that holds whatever was in it before. */
|
|
880
|
+
const motionUsable = motion !== undefined && !this.depthBlitRefused;
|
|
881
|
+
gl.uniform1f(this.uniforms['uMotionStrength'] ?? null, motionUsable ? motion.strength : 0);
|
|
882
|
+
gl.uniform1f(this.uniforms['uMotionMax'] ?? null, motion?.max ?? 0);
|
|
883
|
+
if (motionUsable) {
|
|
884
|
+
gl.uniformMatrix4fv(this.uniforms['uReprojection'] ?? null, false, motion.reprojection);
|
|
885
|
+
}
|
|
886
|
+
/*
|
|
887
|
+
* Depth of field, on the depth unit bound just above and gated on the same refusal: a driver
|
|
888
|
+
* that would not give the depth back leaves that texture holding a previous frame, and a
|
|
889
|
+
* circle of confusion computed from it defocuses the wrong half of the picture.
|
|
890
|
+
*/
|
|
891
|
+
const dofUsable = dof !== undefined && !this.depthBlitRefused;
|
|
892
|
+
gl.uniform1f(this.uniforms['uDofStrength'] ?? null, dofUsable ? dof.strength : 0);
|
|
893
|
+
if (dofUsable) {
|
|
894
|
+
gl.uniform1f(this.uniforms['uFocusDistance'] ?? null, dof.distance);
|
|
895
|
+
gl.uniform1f(this.uniforms['uFocusRange'] ?? null, dof.range);
|
|
896
|
+
/* Height over width, so a radius in fractions of the height is a circle on screen. */
|
|
897
|
+
gl.uniform2f(this.uniforms['uDofAspect'] ?? null, this.height / this.width, 1);
|
|
898
|
+
gl.uniform4fv(this.uniforms['uDepthToView'] ?? null, dof.depthToView);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/*
|
|
902
|
+
* Ambient occlusion on its own unit, gated on the same fact as the blur and for the same
|
|
903
|
+
* reason: a refused depth resolve leaves that texture holding whatever a previous frame
|
|
904
|
+
* put there, and occlusion measured from it is not a degraded picture but a pattern of
|
|
905
|
+
* dirt with no relationship to the scene. The pass may also decline for itself, which
|
|
906
|
+
* arrives here as a null texture. Either way the strength goes to zero, which is exactly
|
|
907
|
+
* the frame that existed before the effect did.
|
|
908
|
+
*
|
|
909
|
+
* The placeholder rather than an unbound unit when it is off: an incomplete texture is
|
|
910
|
+
* something a driver may fetch the descriptor for before it evaluates the branch that
|
|
911
|
+
* would have skipped the read.
|
|
912
|
+
*/
|
|
913
|
+
gl.activeTexture(gl.TEXTURE2);
|
|
914
|
+
gl.bindTexture(gl.TEXTURE_2D, aoTexture ?? scene);
|
|
915
|
+
gl.uniform1i(this.uniforms['uAo'] ?? null, 2);
|
|
916
|
+
gl.uniform1f(
|
|
917
|
+
this.uniforms['uAoStrength'] ?? null,
|
|
918
|
+
aoTexture === null ? 0 : (ao?.strength ?? 0),
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
/* Bloom on its own unit, and the placeholder for the same reason as the one above: a
|
|
922
|
+
driver may fetch a texture's descriptor before it evaluates the branch that skips the
|
|
923
|
+
read, and an incomplete texture is not a thing to hand it. */
|
|
924
|
+
gl.activeTexture(gl.TEXTURE3);
|
|
925
|
+
gl.bindTexture(gl.TEXTURE_2D, bloomTexture ?? scene);
|
|
926
|
+
gl.uniform1i(this.uniforms['uBloom'] ?? null, 3);
|
|
927
|
+
gl.uniform1f(
|
|
928
|
+
this.uniforms['uBloomStrength'] ?? null,
|
|
929
|
+
bloomTexture === null ? 0 : (bloom?.strength ?? 0),
|
|
930
|
+
);
|
|
931
|
+
|
|
932
|
+
/*
|
|
933
|
+
* The grade on unit 4, and the placeholder built here rather than at construction: a frame
|
|
934
|
+
* that never grades anything should not carry a texture, and a sampler declared in the
|
|
935
|
+
* program must still have a complete one bound whether or not the branch reads it — the
|
|
936
|
+
* argument the occlusion and bloom placeholders above make, one dimension up.
|
|
937
|
+
*
|
|
938
|
+
* The placeholder is an **identity** table at two lattice points, which is exact: identity
|
|
939
|
+
* is linear and a trilinear fetch through corners holding their own coordinates reproduces a
|
|
940
|
+
* linear function precisely. So it is the right answer if anything ever samples it rather
|
|
941
|
+
* than an inert stand-in that happens not to be read.
|
|
942
|
+
*/
|
|
943
|
+
if (this.gradeTexture === null) this.uploadGrade(identityGradeLut(GRADE_PLACEHOLDER_SIZE));
|
|
944
|
+
gl.activeTexture(gl.TEXTURE4);
|
|
945
|
+
gl.bindTexture(gl.TEXTURE_3D, this.gradeTexture);
|
|
946
|
+
gl.uniform1i(this.uniforms['uGradeLut'] ?? null, 4);
|
|
947
|
+
gl.uniform1f(this.uniforms['uGradeStrength'] ?? null, this.gradeStrength);
|
|
948
|
+
gl.uniform1f(this.uniforms['uGradeSize'] ?? null, this.gradeSize);
|
|
949
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
950
|
+
|
|
951
|
+
/* No unit and no texture: a flat colour, not a sample. Uploaded unconditionally — two
|
|
952
|
+
floats and a triplet cost nothing next to the triangle this pass already draws — and it
|
|
953
|
+
is `withVeil` in the shader, not a branch here, that keeps a veil-less frame free of the
|
|
954
|
+
mix it does not need. */
|
|
955
|
+
gl.uniform3fv(this.uniforms['uVeilColor'] ?? null, veilColor);
|
|
956
|
+
gl.uniform1f(this.uniforms['uVeilAlpha'] ?? null, veilAlpha);
|
|
957
|
+
|
|
958
|
+
gl.bindVertexArray(this.vao);
|
|
959
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
960
|
+
gl.bindVertexArray(null);
|
|
961
|
+
|
|
962
|
+
/*
|
|
963
|
+
* **The units this pass used are released, and that is not tidiness.**
|
|
964
|
+
*
|
|
965
|
+
* Unit 1 holds `depth` — an attachment of this very target — and a binding survives the frame
|
|
966
|
+
* it was made in. Anything that later *attaches* that texture while it is still bound to a
|
|
967
|
+
* sampler the active program declares forms a feedback loop, which WebGL2 reports as
|
|
968
|
+
* `GL_INVALID_OPERATION: Feedback loop formed between Framebuffer and active Texture` and then
|
|
969
|
+
* draws something undefined. Order-independent transparency attaches exactly this depth to its
|
|
970
|
+
* own framebuffers on the next frame, and that is how this was found: 120 pixels of a frame
|
|
971
|
+
* that should have been identical, and a warning per draw explaining why.
|
|
972
|
+
*/
|
|
973
|
+
for (let unit = 0; unit <= 4; unit++) {
|
|
974
|
+
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
975
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
976
|
+
}
|
|
977
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
978
|
+
|
|
979
|
+
// Handed back the way the rest of the renderer expects to find it.
|
|
980
|
+
gl.depthMask(true);
|
|
981
|
+
gl.enable(gl.DEPTH_TEST);
|
|
982
|
+
/*
|
|
983
|
+
* **And culling, which this pass switched off and the next frame's world is drawn with.**
|
|
984
|
+
*
|
|
985
|
+
* It was the one borrowed state never returned. `resolve` runs at `endFrame`, so from the
|
|
986
|
+
* second frame onwards every `drawMesh` in every scene ran with `CULL_FACE` disabled — the
|
|
987
|
+
* world drawn double-sided on the backend this engine is most often looked at, against a
|
|
988
|
+
* renderer that enables culling once at setup and documents it as "on for the life of the
|
|
989
|
+
* renderer because the world is solid".
|
|
990
|
+
*
|
|
991
|
+
* Invisible wherever geometry is wound correctly, which is every scene here, so nothing
|
|
992
|
+
* caught it. What caught it was a scene whose geometry was wound *backwards*: it looked
|
|
993
|
+
* perfect on WebGL2 and lost its entire ground on WebGPU, where culling is pipeline state
|
|
994
|
+
* that no pass can leak. The defect read as a WebGPU bug for a fortnight and was this line.
|
|
995
|
+
*/
|
|
996
|
+
gl.enable(gl.CULL_FACE);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
dispose(): void {
|
|
1000
|
+
const { gl } = this;
|
|
1001
|
+
this.ao?.dispose();
|
|
1002
|
+
this.ao = null;
|
|
1003
|
+
this.bloom?.dispose();
|
|
1004
|
+
this.bloom = null;
|
|
1005
|
+
if (this.framebuffer !== null) gl.deleteFramebuffer(this.framebuffer);
|
|
1006
|
+
if (this.texture !== null) gl.deleteTexture(this.texture);
|
|
1007
|
+
if (this.depth !== null) gl.deleteTexture(this.depth);
|
|
1008
|
+
/*
|
|
1009
|
+
* The two snapshots and their framebuffers, which this method did not release before the
|
|
1010
|
+
* colour one was added. **The depth pair is the same leak and is freed here for the same
|
|
1011
|
+
* reason**: they are allocated in `ensureSize` beside everything above, so releasing some of
|
|
1012
|
+
* what that allocates and not the rest is a distinction nothing here intends.
|
|
1013
|
+
*/
|
|
1014
|
+
if (this.colorCopy !== null) gl.deleteTexture(this.colorCopy);
|
|
1015
|
+
if (this.colorCopyFramebuffer !== null) gl.deleteFramebuffer(this.colorCopyFramebuffer);
|
|
1016
|
+
if (this.depthCopy !== null) gl.deleteTexture(this.depthCopy);
|
|
1017
|
+
if (this.depthCopyFramebuffer !== null) gl.deleteFramebuffer(this.depthCopyFramebuffer);
|
|
1018
|
+
if (this.gradeTexture !== null) gl.deleteTexture(this.gradeTexture);
|
|
1019
|
+
this.gradeTexture = null;
|
|
1020
|
+
this.gradeSource = null;
|
|
1021
|
+
this.releaseMultisample();
|
|
1022
|
+
gl.deleteProgram(this.program);
|
|
1023
|
+
gl.deleteVertexArray(this.vao);
|
|
1024
|
+
this.framebuffer = null;
|
|
1025
|
+
this.texture = null;
|
|
1026
|
+
this.depth = null;
|
|
1027
|
+
this.colorCopy = null;
|
|
1028
|
+
this.colorCopyFramebuffer = null;
|
|
1029
|
+
this.depthCopy = null;
|
|
1030
|
+
this.depthCopyFramebuffer = null;
|
|
1031
|
+
}
|
|
1032
|
+
}
|