@driftengine/core 4.8.7 → 4.10.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/CHANGELOG.json +123 -11
- package/README.md +43 -38
- package/dist/index.d.ts +8 -1
- package/dist/index.js +11 -3
- package/dist/render/ambientHarmonics.d.ts +1 -1
- package/dist/render/ambientHarmonics.js +1 -1
- package/dist/render/areaLights.d.ts +4 -4
- package/dist/render/areaLights.js +1 -1
- package/dist/render/atmosphere.d.ts +13 -0
- package/dist/render/atmosphere.js +9 -1
- package/dist/render/backend/api.d.ts +19 -4
- package/dist/render/backend/createRenderer.d.ts +6 -0
- package/dist/render/backend/createRenderer.js +4 -1
- package/dist/render/backend/select.js +11 -5
- package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
- package/dist/render/backend/webgl2/boneAnimations.js +80 -0
- package/dist/render/backend/webgl2/instanced.d.ts +5 -1
- package/dist/render/backend/webgl2/instanced.js +13 -1
- package/dist/render/backend/webgl2/renderer.d.ts +180 -4
- package/dist/render/backend/webgl2/renderer.js +550 -40
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
- package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
- package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
- package/dist/render/backend/webgpu/boneAnimations.js +76 -0
- package/dist/render/backend/webgpu/buffers.d.ts +19 -4
- package/dist/render/backend/webgpu/buffers.js +18 -11
- package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
- package/dist/render/backend/webgpu/compressedUpload.js +53 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
- package/dist/render/backend/webgpu/depthPass.js +49 -14
- package/dist/render/backend/webgpu/device.d.ts +7 -1
- package/dist/render/backend/webgpu/device.js +31 -3
- package/dist/render/backend/webgpu/drawCommand.d.ts +18 -4
- package/dist/render/backend/webgpu/drawCommand.js +10 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +100 -42
- package/dist/render/backend/webgpu/flatPass.js +191 -43
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +6 -0
- package/dist/render/backend/webgpu/pipelineCache.js +7 -0
- package/dist/render/backend/webgpu/postPass.d.ts +51 -9
- package/dist/render/backend/webgpu/postPass.js +16 -2
- package/dist/render/backend/webgpu/reflectionSurfacePass.d.ts +30 -0
- package/dist/render/backend/webgpu/reflectionSurfacePass.js +100 -0
- package/dist/render/backend/webgpu/renderer.d.ts +283 -37
- package/dist/render/backend/webgpu/renderer.js +1363 -202
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
- package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
- package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
- package/dist/render/backend/webgpu/staticBundles.js +241 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
- package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
- package/dist/render/backend/webgpu/uniformRing.js +9 -1
- package/dist/render/bloomChain.d.ts +3 -3
- package/dist/render/boneAnimation.d.ts +92 -0
- package/dist/render/boneAnimation.js +133 -0
- package/dist/render/compressedSource.d.ts +33 -13
- package/dist/render/compressedSource.js +70 -25
- package/dist/render/displayRange.d.ts +31 -0
- package/dist/render/displayRange.js +47 -0
- package/dist/render/filmicCurve.d.ts +74 -0
- package/dist/render/filmicCurve.js +203 -0
- package/dist/render/fog.d.ts +4 -1
- package/dist/render/fog.js +12 -2
- package/dist/render/frame/resources.d.ts +2 -2
- package/dist/render/frame/resources.js +6 -0
- package/dist/render/frameReflections.d.ts +40 -0
- package/dist/render/frameReflections.js +48 -0
- package/dist/render/glCompressed.js +83 -0
- package/dist/render/instances.d.ts +26 -0
- package/dist/render/lightBudget.d.ts +10 -0
- package/dist/render/lightBudget.js +10 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +5 -0
- package/dist/render/mesh.js +6 -0
- package/dist/render/pass.d.ts +49 -0
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/reflectionSurfaceTargets.d.ts +28 -0
- package/dist/render/reflectionSurfaceTargets.js +99 -0
- package/dist/render/renderQuality.d.ts +39 -8
- package/dist/render/renderQuality.js +4 -0
- package/dist/render/sceneTarget.d.ts +5 -0
- package/dist/render/sceneTarget.js +24 -1
- package/dist/render/screenSpaceReflection.d.ts +7 -1
- package/dist/render/screenSpaceReflection.js +5 -0
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/filmLook.js +2 -1
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +2 -0
- package/dist/render/shaders/flat/index.d.ts +16 -0
- package/dist/render/shaders/flat/index.js +33 -5
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +43 -5
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/overlay.d.ts +16 -0
- package/dist/render/shaders/flat/overlay.js +117 -0
- package/dist/render/shaders/flat/pointShadow.js +3 -3
- package/dist/render/shaders/flat/preamble.js +38 -24
- package/dist/render/shaders/flat/reflectionSurface.d.ts +21 -0
- package/dist/render/shaders/flat/reflectionSurface.js +61 -0
- package/dist/render/shaders/fog.d.ts +1 -1
- package/dist/render/shaders/fog.js +9 -2
- package/dist/render/shaders/fringe.d.ts +29 -0
- package/dist/render/shaders/fringe.js +55 -0
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.js +1 -1
- package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
- package/dist/render/shaders/generated/depth.wgsl.js +93 -0
- package/dist/render/shaders/generated/film.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/film.wgsl.js +1 -1
- package/dist/render/shaders/generated/fire.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/fire.wgsl.js +1 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3254 -2920
- package/dist/render/shaders/generated/flat.wgsl.js +3292 -2957
- package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/line.wgsl.js +1 -1
- package/dist/render/shaders/generated/particle.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/particle.wgsl.js +4 -4
- package/dist/render/shaders/generated/rush.wgsl.d.ts +56 -26
- package/dist/render/shaders/generated/rush.wgsl.js +56 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/scatter.wgsl.js +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +1 -1
- package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +22 -2
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +22 -2
- package/dist/render/shaders/generated/water.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/water.wgsl.js +1 -1
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +2 -2
- package/dist/render/shaders/gpudriven/fog.wgsl.js +11 -3
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/rush.js +54 -11
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/ssrResolve.d.ts +17 -0
- package/dist/render/shaders/ssrResolve.js +51 -0
- package/dist/render/shaders/ssrTrace.js +26 -0
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/ssrPass.d.ts +16 -0
- package/dist/render/ssrPass.js +106 -1
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceOverlay.d.ts +132 -0
- package/dist/render/surfaceOverlay.js +85 -0
- package/dist/render/surfaceTexture.d.ts +57 -7
- package/dist/render/surfaceTexture.js +125 -17
- package/dist/render/temporalAa.d.ts +14 -0
- package/dist/render/temporalAa.js +20 -0
- package/dist/render/vertexDefaults.d.ts +17 -0
- package/dist/render/vertexDefaults.js +24 -0
- package/package.json +6 -6
- package/src/index.ts +24 -2
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/atmosphere.ts +22 -1
- package/src/render/backend/api.ts +22 -3
- package/src/render/backend/createRenderer.ts +18 -1
- package/src/render/backend/select.ts +10 -5
- package/src/render/backend/webgl2/boneAnimations.ts +105 -0
- package/src/render/backend/webgl2/instanced.ts +20 -1
- package/src/render/backend/webgl2/renderer.ts +672 -37
- package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
- package/src/render/backend/webgpu/boneAnimations.ts +97 -0
- package/src/render/backend/webgpu/buffers.ts +42 -16
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/device.ts +42 -3
- package/src/render/backend/webgpu/drawCommand.ts +22 -4
- package/src/render/backend/webgpu/flatPass.ts +250 -40
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/pipelineCache.ts +7 -0
- package/src/render/backend/webgpu/postPass.ts +18 -0
- package/src/render/backend/webgpu/reflectionSurfacePass.ts +114 -0
- package/src/render/backend/webgpu/renderer.ts +1655 -230
- package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
- package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
- package/src/render/backend/webgpu/staticBundles.ts +363 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/displayRange.ts +61 -0
- package/src/render/filmicCurve.ts +229 -0
- package/src/render/fog.ts +19 -3
- package/src/render/frame/resources.ts +6 -0
- package/src/render/frameReflections.ts +72 -0
- package/src/render/glCompressed.ts +83 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +6 -0
- package/src/render/pass.ts +53 -1
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/reflectionSurfaceTargets.ts +105 -0
- package/src/render/renderQuality.ts +44 -8
- package/src/render/sceneTarget.ts +30 -2
- package/src/render/screenSpaceReflection.ts +7 -1
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/filmLook.ts +2 -1
- package/src/render/shaders/flat/glassTint.ts +5 -1
- package/src/render/shaders/flat/index.ts +49 -5
- package/src/render/shaders/flat/main.ts +43 -5
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/overlay.ts +117 -0
- package/src/render/shaders/flat/pointShadow.ts +3 -3
- package/src/render/shaders/flat/preamble.ts +38 -24
- package/src/render/shaders/flat/reflectionSurface.ts +61 -0
- package/src/render/shaders/fog.ts +9 -2
- package/src/render/shaders/fringe.ts +59 -0
- package/src/render/shaders/generated/arcane.wgsl.ts +1 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/caustics.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/film.wgsl.ts +1 -1
- package/src/render/shaders/generated/fire.wgsl.ts +1 -1
- package/src/render/shaders/generated/flat.wgsl.ts +3292 -2957
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +4 -4
- package/src/render/shaders/generated/rush.wgsl.ts +56 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +1 -1
- package/src/render/shaders/generated/smoke.wgsl.ts +1 -1
- package/src/render/shaders/generated/ssrResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +22 -2
- package/src/render/shaders/generated/water.wgsl.ts +1 -1
- package/src/render/shaders/gpudriven/fog.wgsl.ts +11 -3
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/rush.ts +54 -11
- package/src/render/shaders/ssrResolve.ts +52 -0
- package/src/render/shaders/ssrTrace.ts +26 -0
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/ssrPass.ts +138 -1
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceOverlay.ts +195 -0
- package/src/render/surfaceTexture.ts +161 -27
- package/src/render/temporalAa.ts +20 -0
- package/src/render/vertexDefaults.ts +28 -0
package/CHANGELOG.json
CHANGED
|
@@ -1,4 +1,116 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "4.10.0",
|
|
4
|
+
"date": "2026-10-07",
|
|
5
|
+
"entries": [
|
|
6
|
+
{
|
|
7
|
+
"kind": "added",
|
|
8
|
+
"short": "`createStaticDraws` keeps a world's still draws and `drawStaticDraws` replays them: on WebGPU one render bundle a view, recorded once, where a frame encoded every draw.",
|
|
9
|
+
"text": "`renderer.createStaticDraws(casters)` takes the enumeration `drawSceneCasters` takes — rigid meshes and instanced batches, each with its material — once, and keeps it; `drawStaticDraws(list)` draws it into the open mesh pass under whatever camera, lights and fog `bindMeshPass` set, the frame's, a mirror's or a capture's, and `disposeStaticDraws` releases it. On WebGPU a list is recorded into a render bundle for each view and replayed with one call, and recorded again only when something it was recorded against changes; WebGL2 has no bundles and replays the entries every frame, drawing the same picture. A skinned mesh or a scatter batch is refused by name, since both change every frame, and a list draws whole in every view, so a world split into lists by region culls by list. On `demo/dev/staticDraws.html`, 412 draws cost the main thread 0.650 ms a frame drawn one by one and 0.127 ms as a list — 1.646 and 0.202 with a scene capture beside the frame — and the two pictures are the same to the pixel on both backends."
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"kind": "added",
|
|
13
|
+
"short": "`createBoneAnimation` plays a crowd in the instanced vertex stage: each vertex follows the bone its second coordinates name, each instance on its own clock, shadows included.",
|
|
14
|
+
"text": "`renderer.createBoneAnimation(clip)` takes a clip as a turn and a place for each bone at each of its frames, and `InstancedOptions.animation` plays it on every instance of a batch: each vertex follows the one bone its second coordinates' u names, at the instance's own moment of the clip. `MeshInstances.clocks` holds a phase and a rate an instance, and `setAnimationTime(seconds)` the clock they share, set once a frame before the shadows. Every instance moves at the frame's rate and out of step with the next, in the colour pass and in every shadow, with nothing done on the processor once the clip is made; `disposeBoneAnimation` releases it. Both backends run the same arithmetic: on `demo/dev/boneCrowd.html` twenty-five instances played by the vertex stage and posed on the processor by that arithmetic differ by 0 pixels on WebGPU and 2 on WebGL2, shadows included. What it gives up: a vertex follows one bone; an animated batch is culled whole, never instance by instance; and under reconstruction or the temporal resolve a crowd's own movement is not in the frame's motion."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"kind": "added",
|
|
18
|
+
"short": "Surface textures take ETC2, EAC and ASTC blocks beside BC, uploaded as they are wherever `compressedFormats` says the device samples them, on both backends.",
|
|
19
|
+
"text": "`createSurfaceTexture` takes ETC2 (`etc2-rgb8`, `etc2-rgb8a1`, `etc2-rgba8`), EAC (`eac-r11`, `eac-rg11`) and every LDR ASTC block size from 4x4 to 12x12, each with its sRGB twin where it has one, beside the BC formats it already took. WebGPU asks for `texture-compression-etc2` and `texture-compression-astc` wherever the adapter offers them, WebGL2 reads `WEBGL_compressed_texture_etc` and `WEBGL_compressed_texture_astc`, and `compressedFormats` lists what the device samples — so a phone's textures go up at a byte a texel or less, where RGBA takes four. `updateSurfaceTexture` takes blocks too: they replace an image behind the handle every draw already holds, read in the colour space the texture was made in and refused where the device does not take them, while an image in place of blocks is still refused. `levelBytes` gives the bytes a level of any block format holds. On `demo/dev/phoneTextures.html` an ETC2 chain, an EAC normal map and an ASTC block draw exactly the texels they decode to, on both backends."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"kind": "added",
|
|
23
|
+
"short": "On a device that samples ETC2 and not BC, `DrftLoader` re-encodes BC textures as ETC2 in a worker and swaps them in; `readKtx2` takes a KTX2 file as its blocks.",
|
|
24
|
+
"text": "A `DrftLoader` given `bcWorker` re-encodes each BC texture as ETC2 or EAC where the device samples those and not BC, which is a phone. The texture is shown decoded first, exactly as before, and its chain then replaces it behind the handle it was drawn with, from a second worker of the same factory, one texture at a time: `etc2-rgb8`, or `etc2-rgba8` where the decoded alpha is less than opaque, `eac-r11` for BC4 and `eac-rg11` for BC5, every level averaged in light where the slot reads colour. Nothing arrives later for it, and the texture ends at half a byte a texel, or a byte with alpha, where it held four; the encode costs about 0.7 s for a 2048² image on a desktop processor, on a core of its own. Without a worker nothing is encoded. `readKtx2` reads an uncompressed KTX2 file of ASTC, ETC2, EAC or BC as the blocks it carries, refusing a supercompressed file, a cube or an array by name, and `encodeEtc2` and `encodeEtc2Chain` encode pixels a caller holds. On `demo/dev/phoneLoad.html` the loader's swapped texture and the same chain uploaded directly draw the same picture on both backends."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"kind": "added",
|
|
28
|
+
"short": "`SurfaceMaterial.reflectivity` and `environmentGain` state a material's own reflection for its draws, so a static list keeps each batch's reflectivity and gain.",
|
|
29
|
+
"text": "A `SurfaceMaterial` may state `reflectivity`, 0 to 1, and `environmentGain`, held non-negative: the numbers `setSurfaceReflectivity` and `setEnvironmentGain` set for every draw, stated by the material for its own. A draw under a material that states one wears it whatever the setters say, and a material stating neither leaves its draws to the setters, as every material did before; each falls back on its own. They are what lets a static list carry a stage whose batches each mirror their own share of a baked reflection at their own brightness, since a list keeps each entry's material and none of the renderer's state between draws. On both backends."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"kind": "changed",
|
|
33
|
+
"short": "WebGPU keeps a draw's material across frames: the lit block is a pass's and a material's, and a material seen before is bound again rather than uploaded again.",
|
|
34
|
+
"text": "The lit stage's uniforms on WebGPU are three blocks where they were one: the pass's, written once a pass; the material's, kept in a store by its contents and bound by offset, so a material a frame has drawn before costs no upload; and, for the vertex stage, the camera, light matrix and wind, so a draw's own slot no longer changes when the camera does. A frame that draws what the one before it drew uploads no material bytes, where the dev pages measured 14 to 29 KB a frame, and every published scene draws the same to the pixel on both backends. The cutout dither's frame moved into the pass's block with it, since a number that changes every frame made every cutout material new every frame. The frame's statistics still count material changes, as WebGL2's do."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"kind": "changed",
|
|
38
|
+
"short": "A skinned draw keeps its bind group per material, and a skin palette slot keeps its largest texture, so mixed rigs no longer make textures and bind groups every frame.",
|
|
39
|
+
"text": "On WebGPU a skin palette slot keeps the largest texture it has needed rather than replacing it whenever a rig of another joint count takes the slot, and a skinned or morphed draw's bind group is kept per slot and per material rather than built again; WebGL2's palette only grows as well. A frame whose skinned meshes and characters are culled differently from the frame before no longer creates and destroys textures and bind groups to draw them."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"kind": "changed",
|
|
43
|
+
"short": "`updateMesh` under reconstruction records the previous positions' copy into the frame's own work rather than submitting a command buffer of its own each time.",
|
|
44
|
+
"text": "On WebGPU, rewriting a mesh's positions while DriftTR keeps its previous positions for motion copied the old ones in a command buffer submitted on the spot, one submit a rewrite. The copy is recorded into the frame's own work now, so a mesh rewritten every frame costs its upload and nothing more, and every submit the renderer makes goes through one place."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"kind": "fixed",
|
|
48
|
+
"short": "Refraction bends by the surface's normal as the eye sees it, so a card facing the camera shimmers by its normal map instead of bending as one lens.",
|
|
49
|
+
"text": "A refracting draw bent the frame behind it by the world x and y of its normal, which on a quad facing the camera is the quad's lean against the world's axes: one offset across the whole quad, a lens, with a normal map's tilt a small change on top. It bends by the normal in view space now, the map's tilt included, so a distortion card shimmers by its map and a pane bends by how it leans toward the eye wherever the eye stands, the same on both backends."
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"version": "4.9.0",
|
|
55
|
+
"date": "2026-10-07",
|
|
56
|
+
"entries": [
|
|
57
|
+
{
|
|
58
|
+
"kind": "added",
|
|
59
|
+
"short": "`screenSpaceReflections`: every opaque lit surface reflects the frame by its own material, the probe's share swapped for what a ray finds, softened by roughness and left to the probes past a ceiling.",
|
|
60
|
+
"text": "A renderer built with `screenSpaceReflections` reflects the frame in every opaque lit surface by that surface's own material, where `ReflectiveSurface` reflects it by a box's. The lit stage leaves, per pixel, how much of the environment it showed and the tint a reflection lands with; the screen-space trace gains a material mode that marches every such pixel against the frame's depth and swaps the probe's share for what it finds. The swap is exact because the lit stage's blend is a mix: the frame holds the environment times the tint times the weight, and a found reflection belongs there with the same tint and weight, so nothing else in the pixel moves. A rougher surface shows a softer reflection, blurred by its roughness, and past `maxRoughness` it keeps the probes' reflection alone. One floor mesh with one ORM map therefore mirrors the figures standing on its glossy panels and barely shows them on its matte ones. What a surface reflects is what the lit stage already reflected: a metal by its metalness, a dielectric where `setSurfaceReflectivity` or its material asks. `true` takes `DEFAULT_FRAME_REFLECTIONS`; a `FrameReflections` sets the ceiling, the march and the blur. WebGPU writes the two maps by replaying the opaque lit draws without their lamps, since a second attachment on the frame's pass would bind every pipeline in it; WebGL2 writes them beside the colour, enabled around the opaque lit draws alone and behind a lit switch, so a renderer without the option carries nothing for it. It needs `screenEffects`, `hdrScene` and one sample, and says so once where it has none. On `demo/dev/frameReflections.html` the trace moves 30,138 floor pixels and none above them, a ceiling below every stripe matches the frame without the trace to the pixel, and the two backends differ by 41 pixels."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"kind": "added",
|
|
64
|
+
"short": "`setSurfaceOverlay` lays a rim of light, a dissolve with a glowing edge and wrinkle normals by six region weights over a draw's materials, its images regions of one atlas.",
|
|
65
|
+
"text": "`renderer.setSurfaceOverlay(overlay)` lays something over the surfaces of the draws that follow, beyond their materials, so one character's whole set of materials changes together while another's does not; per draw, reset by `bindMeshPass`. A `rim` glows along the silhouette: an edge `(1 - N·V)^falloff` leaning toward normals that face up, raised to a contrast, times a noise laid in screen space and scrolled on the environment's `surfaceTime`, a slow pulse and a mask in the mesh's uv, added to emission and not gated on the night. A `dissolve` cuts the surface away where a noise in its uv falls under a threshold, with a glowing band at the edge and a colour laid through the same noise. A `wrinkle` blends a second normal map into the surface's by six region weights read through two masks. Every image is a region of one atlas (`OverlayRegion`), read in the slot the frame's refraction copy takes, which an opaque surface never reads; a draw that refracts keeps its refraction and reads none of the overlay's images, and says so once. A lit switch, off until an overlay is set. WebGL2 carries the overlay's fifteen uniform vectors where its device has room and refuses it in words where it does not, as on a 256-vector part at the eight-light budget, and reads a compressed atlas as none. On `demo/dev/surfaceOverlay.html` every control moves only the object it names, and the two backends agree to the pixel."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"kind": "added",
|
|
69
|
+
"short": "`outputTransform: 'filmic'` and `setFilmicCurve`: a film curve shaped by five numbers that holds mid grey at mid grey, applied by the composite.",
|
|
70
|
+
"text": "`outputTransform: 'filmic'` is a film curve in the ACEScg working space: a straight segment through mid grey meeting a soft toe below and a shoulder above, shaped by a slope, a toe, a shoulder and two clips, with the ACES reference's glow and red modifier around it. `setFilmicCurve` sets the numbers and a renderer starts with `DEFAULT_FILMIC_CURVE`; a curve that runs backwards or divides by zero is clamped and said once rather than refused. 0.18 of scene light comes out at 0.18, where `'aces'` gives about 0.11: 118 of 255 on both backends, and every one of sixteen grey and colour patches agrees with a consumer's own transcription of the reference. It is the composite's, so it needs `screenEffects` and `hdrScene`; without them every pass grades with `'aces'` and the renderer says so once. Bound to DriftScript as `drift/render.filmic`."
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"kind": "added",
|
|
74
|
+
"short": "`highDynamicRange` draws to a display's own range on WebGPU, `displayRange` says which range the frame went out in, and `setDisplayLuminance` lets highlights reach the display's peak.",
|
|
75
|
+
"text": "`highDynamicRange: true` asks for a canvas whose highlights run past paper white as far as the display can show. It is had where the renderer is on WebGPU, the frame keeps its light past white (`screenEffects` and `hdrScene`) and the display reports a high range: the canvas is configured `rgba16float` with extended tone mapping and read back to confirm it. `renderer.displayRange` says which range the frame goes out in, `'high'` or `'standard'`, and `displayRangeReason` says why; WebGL2 draws into an eight-bit canvas and always answers `'standard'`. `setDisplayLuminance(paperWhite, peak)` gives the ratio highlights may reach: paper white stays where it was and so does everything below it, the filmic shoulder rolls off toward the peak, and a colour grade colours a highlight without clipping it back to white. On a standard display it changes nothing. A host without a browser display query answers it with `createRenderer`'s `highDynamicRangeDisplay`."
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"kind": "added",
|
|
79
|
+
"short": "`setCameraMotionBlur(scale, maxShare)` blurs each drawn object by its own motion under DriftTR on WebGPU: a mover smears while the still stage behind it stays sharp.",
|
|
80
|
+
"text": "Camera motion blur now reads each pixel's motion from the reconstruction's motion target, so a mover with a previous placement or pose smears along its own path while the stage standing still behind it does not, and `setCameraMotionBlur` takes a maximum as a share of the frame. On `demo/dev/objectBlur.html` a box crossing a still camera's view smears 8 pixels, 1 with the blur off, 5 capped. It is WebGPU's under DriftTR alone, since that is where per-object motion is kept; WebGL2, and WebGPU without reconstruction, blur by the camera's motion alone and say so once when given a mover."
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"kind": "added",
|
|
84
|
+
"short": "`setChromaticAberration(intensity, start)` pulls the colour channels apart toward the frame's edges past a start radius, at three wavelengths, on both backends.",
|
|
85
|
+
"text": "`setChromaticAberration(intensity, start)` is a lens fringe in the composite: the three channels sampled apart toward the frame's edges, scaled by their wavelengths, from a start radius outward, so the middle of the frame is untouched. Held until changed; 0 is none. On `demo/dev/toneCurve.html?fringe=` it moves 13,480 pixels, none inside the start, and the two backends agree. It needs `screenEffects`, and says so once."
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"kind": "added",
|
|
89
|
+
"short": "`Atmosphere.fogStart` keeps the exponential fog's first metres clear, integrated along each ray's own path in the lit stage and the GPU-driven pipeline alike.",
|
|
90
|
+
"text": "`Atmosphere.fogStart` holds the exponential height fog off for its first metres: the medium begins where the ray has travelled that far, integrated along the ray's own path, so a stage reads clear up close and hazes with distance as a fog start does in a scene authored elsewhere. 0, or absent, is the fog as before. On `demo/dev/fogStart.html` the measured columns match values worked by hand on both backends, and the GPU-driven pipeline's fog takes it too."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"kind": "added",
|
|
94
|
+
"short": "A registered pass reads the frame: `reads: ['colorSnapshot']` hands it the colour drawn so far as `sceneColor`, beside the depth's `sceneDepth`, on both backends.",
|
|
95
|
+
"text": "A pass that declares `reads: ['depthSnapshot']` is handed the frame's depth as `sceneDepth` — in the `PrepareContext` on WebGPU, an `r32float` texture, and in the `PassContext` on WebGL2 — and one that declares `reads: ['colorSnapshot']` the colour with everything drawn before it as `sceneColor`, copied afresh at each such pass's draw. A distortion samples the scene behind it with it; a full-screen pass drawn last reads the whole frame and writes over it in scene light, before the tone curve. Under DriftTR the pass runs after the upscale over a copy of the reconstructed frame. On `demo/dev/framePass.html` a pass inverting the frame reads the same values on both backends, with multisampling too."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"kind": "changed",
|
|
99
|
+
"short": "The worker factories are at declared subpaths, `@driftengine/assets/bcWorkers` and `@driftengine/physics/workers`, where a bundler and Node can both find them.",
|
|
100
|
+
"text": "`spawnBcWorker` and the physics island pool's `createIslandPool` were reached by a path into a package's `src`, which a published package's `exports` does not have to allow and a strict resolver refuses. Each now has a subpath of its own in its package's `exports`, `@driftengine/assets/bcWorkers` and `@driftengine/physics/workers`, built to `dist` like the barrels, and the messages that name them say so. The barrels still do not reach them, which is what keeps a worker out of a game that never names one."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"kind": "fixed",
|
|
104
|
+
"short": "A scene capture or a probe bake inside a frame no longer turns that frame black on WebGPU, nor switches off its skin spread, nor steps the temporal jitter twice.",
|
|
105
|
+
"text": "Three defects at the boundary a capture or a probe bake opens in the middle of a frame. On WebGPU, `captureScene` and `bakeProbe` saved the open pass before flushing the frame graph, which opens the frame's pass, so a capture after any draw restored the wrong pass and the frame came out black. On both backends, the latch that spreads skin once a frame was set before the check that refuses a mirror, a probe or a capture, so a blended draw inside a capture switched the frame's skin spread off. And the temporal history stepped its jitter each time the camera was bound rather than once a frame, so a frame that bound it twice drew two frames' jitter. Each has a test, and `scripts/capture-check.mjs` captures at the start of a frame, among its draws and at its end, against controls taken the same way."
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"kind": "fixed",
|
|
109
|
+
"short": "WebGPU asks a device for the textures and samplers the environment probe's widest lit variant really binds, sixteen and twelve, counted from the generated bindings.",
|
|
110
|
+
"text": "The check that decides whether a device can build the environment probe's permutation compared its limits against seven sampled textures and four samplers, typed when the probe was added. The widest lit variant had since grown to sixteen and twelve with the material maps, glass, the fixture atlas and DriftLight, so a device under those would have been admitted to a permutation it cannot bind. The counts now come from the generated bindings, a shared sampler counted once."
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
},
|
|
2
114
|
{
|
|
3
115
|
"version": "4.8.7",
|
|
4
116
|
"date": "2026-10-06",
|
|
@@ -15,18 +127,18 @@
|
|
|
15
127
|
},
|
|
16
128
|
{
|
|
17
129
|
"kind": "added",
|
|
18
|
-
"short": "`PointLightSource.falloffExponent` lights by `(1 - (d/R)^2)^n` with no distance term,
|
|
19
|
-
"text": "A point or spot light may name its own falloff: `(1 - (d/R)^2)^n` with `R` its radius and `n` the exponent, and no inverse square, which is how
|
|
130
|
+
"short": "`PointLightSource.falloffExponent` lights by `(1 - (d/R)^2)^n` with no distance term, the usual falloff for a light without inverse square, in both arms and on water, DriftLight and DriftRay.",
|
|
131
|
+
"text": "A point or spot light may name its own falloff: `(1 - (d/R)^2)^n` with `R` its radius and `n` the exponent, and no inverse square, which is how lighting tools commonly light a light that does not use inverse-square falloff. A rig authored that way keeps its shape: a fill meant to light a whole hall across a hundred metres does, where the frame's falloff had it gone a few metres out. 0, or absent, is the frame's falloff as before. The selection carries it in `PointLightBuffer.falloffExponents` and the environment in `lightFalloffExponents`; the fixed arm reads it in the third lane of the cone uniform, which a two-float array already paid a whole row for, so the eight-light build spends no uniform row on it, and the froxel table's record grows to six texels. Water, DriftLight's volume and DriftRay's bounce fall off by it too, so a light lands the same way on every surface it reaches. On `demo/dev/clustered.html` one light drawn by the fixed arm and by the table is 0 pixels apart on both backends, and an exponent of 8 moves 42,123 pixels against none."
|
|
20
132
|
},
|
|
21
133
|
{
|
|
22
134
|
"kind": "added",
|
|
23
135
|
"short": "`AreaLightSource.barnDoorAngle` and `barnDoorLength` hang barn doors on a rectangle: each fragment is lit by the part the doors leave in view, its highlight included, in both arms.",
|
|
24
|
-
"text": "A rectangle may carry barn doors, a flap hinged at each edge standing `barnDoorAngle` degrees from its normal and `barnDoorLength` metres long, 20 cm when absent,
|
|
136
|
+
"text": "A rectangle may carry barn doors, a flap hinged at each edge standing `barnDoorAngle` degrees from its normal and `barnDoorLength` metres long, 20 cm when absent, the usual default for a rectangle light. At 90 they fold flat and hide nothing; smaller narrows the light to the opening they leave. Each fragment shades the part of the rectangle no door's tip hides, one axis at a time, so the form factor and the integrated highlight both come from that smaller rectangle, in the fixed arm, which reads the doors in the size uniform's two spare lanes, and in the froxel table's record. Each door is taken as endless along its hinge, so where two meet the corner they hide is square rather than mitred, and a shadowed rectangle's map is still baked from its whole face. Measured from straight above a 1.2 by 0.5 m panel 1.2 m over a floor with 20 degree, 30 cm doors: nothing changes within the 1.04 by 0.69 m box the door tips leave whole, nothing is lit past 4.94 and 2.32 m where they hide all of it, the fixed and clustered arms are 0 pixels apart, and doors at 90 degrees are 0 pixels from none, on both backends."
|
|
25
137
|
},
|
|
26
138
|
{
|
|
27
139
|
"kind": "added",
|
|
28
140
|
"short": "`SurfaceMaterial.physicalSpecular` shades a lamp's and the sun's highlight as GGX's own `pi D Vis F N.L` with the specular attribute as F0, on the standard, lightmap and anisotropic models.",
|
|
29
|
-
"text": "The engine's highlight is a look control: it peaks at the specular attribute times one however rough the surface, so strength and width are set apart. A material with `physicalSpecular: true` takes GGX's own term instead, `pi * D * Vis * F * N.L` with Smith's height-correlated masking, as
|
|
141
|
+
"text": "The engine's highlight is a look control: it peaks at the specular attribute times one however rough the surface, so strength and width are set apart. A material with `physicalSpecular: true` takes GGX's own term instead, `pi * D * Vis * F * N.L` with Smith's height-correlated masking, as this engine's skin and eye already did. Its peak is `1 / (4 alpha^2)` of the light head-on, so a polished surface's highlight is several times the look's and a rough one's lower and wider; the specular attribute is read as the reflectance at normal incidence, `0.08 * Specular`, and Fresnel brightens every surface toward grazing rather than a metal alone. Lamps, widened by their size as before, and the sun take it, on the standard, lightmap and anisotropic models; a rectangle's highlight was already the lobe integrated over it with that F0. The code is a lit switch, compiled into the lit programs the first time a material asks, so a scene that never does carries none of it. Measured with a lamp and an eye mirrored about a floor at roughness 0.5, where the term works out by hand to 4.4376: the physical highlight at 1/4.4377 of the light reads the look's middle pixel to within a level on both backends, from a lamp and from the sun, and the anisotropic model's physical lobe at strength 0 is the standard one to within a level everywhere."
|
|
30
142
|
},
|
|
31
143
|
{
|
|
32
144
|
"kind": "added",
|
|
@@ -77,7 +189,7 @@
|
|
|
77
189
|
{
|
|
78
190
|
"kind": "added",
|
|
79
191
|
"short": "Baked lightmaps: `createLightmap` uploads a page of irradiance and direction, and a `lightmapModel` material reads its region of it at a mesh's `lightmapUvs`, or an instance's region in a batch.",
|
|
80
|
-
"text": "`createLightmap(page)` uploads a baked page, linear irradiance as three floats a texel and the direction it arrives from as a first-order spherical harmonic in four bytes, as two half-float layers, and returns a texture that a material made with `lightmapModel({ region })` takes as its `modelMap`. A surface adds `albedo * (1 - metal) * irradiance * max(0, dot(d.xyz, n) + d.w)` to its diffuse,
|
|
192
|
+
"text": "`createLightmap(page)` uploads a baked page, linear irradiance as three floats a texel and the direction it arrives from as a first-order spherical harmonic in four bytes, as two half-float layers, and returns a texture that a material made with `lightmapModel({ region })` takes as its `modelMap`. A surface adds `albedo * (1 - metal) * irradiance * max(0, dot(d.xyz, n) + d.w)` to its diffuse, a directional lightmap read, with `n` the shading normal and the page read at the mesh's second coordinates, `MeshData.lightmapUvs`, scaled and offset by the region. An instanced batch carries a region an instance in `MeshInstances.lightmapRegions`, applied before the material's, so instances of one mesh sit in different parts of one page. The lightmap is a shading model, a pipeline constant of its own, so nothing that does not use one pays for it, and every published scene moves 0 pixels on WebGPU. What it takes is spent elsewhere: the coordinates ride the grain and relief attributes, stored below zero so that the same mesh drawn without its page has neither, and an instance's region rides its tint and opacity. A mesh naming lightmap coordinates beside grain or relief that is not zero is refused, and a batch and a material that disagree about regions are said once on the console. Checked on a room baked on the CPU with a box's shadow in it (`demo/dev/lightmap.html`): a page of one value adds exactly what the same ambient raised by `setAmbientSH` adds, 0 pixels apart on both backends, sixteen instanced tiles are within one level of the same tiles drawn one at a time, and the two backends are within one level of each other. The GPU-driven pipeline reads no page."
|
|
81
193
|
},
|
|
82
194
|
{
|
|
83
195
|
"kind": "added",
|
|
@@ -87,17 +199,17 @@
|
|
|
87
199
|
{
|
|
88
200
|
"kind": "added",
|
|
89
201
|
"short": "`setAmbientSH(coefficients)` gives the draws that follow their own ambient, nine RGB spherical-harmonic coefficients in place of the frame's and the probes', and `null` gives the frame's back.",
|
|
90
|
-
"text": "`setAmbientSH(coefficients)` takes the 27 numbers of a second-order spherical harmonic, nine coefficients of radiance in three channels, and lights the draws that follow by its cosine-convolved irradiance in place of the frame's ambient and the probe grid's, until `null` or the next `bindMeshPass` gives the frame's back. A character moving through a baked irradiance volume samples it where it stands each frame and sets it around its own draws,
|
|
202
|
+
"text": "`setAmbientSH(coefficients)` takes the 27 numbers of a second-order spherical harmonic, nine coefficients of radiance in three channels, and lights the draws that follow by its cosine-convolved irradiance in place of the frame's ambient and the probe grid's, until `null` or the next `bindMeshPass` gives the frame's back. A character moving through a baked irradiance volume samples it where it stands each frame and sets it around its own draws, a per-object volumetric lightmap. It is material state, so on WebGPU a change takes a material slot. The lit shader had no uniform row to spare on a 256-row phone, so scalar uniforms were packed into vectors they now share, and the eight-light build fits the 256 rows it fitted before. Checked on both backends: the frame's own sky-and-ground gradient handed back as coefficients draws 0 pixels from the frame without them."
|
|
91
203
|
},
|
|
92
204
|
{
|
|
93
205
|
"kind": "added",
|
|
94
206
|
"short": "Lighting channels: a point or spot light shades only surfaces whose `SurfaceMaterial.lightChannels` mask shares a bit with its own, so a character's key and rim lights leave the stage alone.",
|
|
95
|
-
"text": "Each point or spot light carries a channel mask, `Environment.lightChannels` beside `lightColors` (and `PointLightSet.lightChannels` where a consumer fills the set itself), and each material one, `SurfaceMaterial.lightChannels`, both whole masks from 1 to 255 and 1 by default, so a scene that names none is lit exactly as it was. A light shades a surface only where the two share a bit
|
|
207
|
+
"text": "Each point or spot light carries a channel mask, `Environment.lightChannels` beside `lightColors` (and `PointLightSet.lightChannels` where a consumer fills the set itself), and each material one, `SurfaceMaterial.lightChannels`, both whole masks from 1 to 255 and 1 by default, so a scene that names none is lit exactly as it was. A light shades a surface only where the two share a bit: a game lights its characters with key and rim lights that the stage never sees. The fixed loop and the froxel table both honour it on both backends, the mask riding a spare lane of a light's profile axis in the one and the light's record in the other. The sun, the sky, the probes, area lights, DriftLight and the GPU-driven pipeline light every surface whatever its mask."
|
|
96
208
|
},
|
|
97
209
|
{
|
|
98
210
|
"kind": "added",
|
|
99
|
-
"short": "`setBloom` takes a response: a ramp in place of subtracting the threshold, and a tint for each of the six levels, so a stage authored against
|
|
100
|
-
"text": "`setBloom(scale, threshold, response)` takes a `BloomResponse`: `ramp`, the scene units over which a colour comes in from none of it at the threshold to all of it,
|
|
211
|
+
"short": "`setBloom` takes a response: a ramp in place of subtracting the threshold, and a tint for each of the six levels, so a stage authored against a ramped bloom blooms as it was lit.",
|
|
212
|
+
"text": "`setBloom(scale, threshold, response)` takes a `BloomResponse`: `ramp`, the scene units over which a colour comes in from none of it at the threshold to all of it, `saturate((L - threshold) / 2)` where the old subtraction stays the default; and `tints`, a colour for each of the six levels from the finest halo to a twentieth of the frame, white by default and not clamped, so a tint carries a strength. One band over the colour less a low threshold washed a stage authored with a threshold of 0.1 white. Both backends weigh each level by a blend constant as it is added back, so the response costs no pass and no texture, and a frame that names none draws what it drew: the published scenes move 0 pixels on WebGPU. `BLOOM_LEVELS` is exported."
|
|
101
213
|
},
|
|
102
214
|
{
|
|
103
215
|
"kind": "added",
|
|
@@ -112,7 +224,7 @@
|
|
|
112
224
|
{
|
|
113
225
|
"kind": "added",
|
|
114
226
|
"short": "With `clusteredLights` on, rectangle lights past `maxAreaLights` are shaded through the froxel table, unshadowed and windowed by a `range`, so a stage's strips and panels all light it.",
|
|
115
|
-
"text": "Rectangles past the fixed `maxAreaLights` are binned into the froxel table beside the point lights and shaded by the same function the fixed loop uses, integrated specular and all, so one rectangle drawn either way is 0 pixels apart on both backends. They take no shadow, and are windowed to zero at `AreaLightSource.range`,
|
|
227
|
+
"text": "Rectangles past the fixed `maxAreaLights` are binned into the froxel table beside the point lights and shaded by the same function the fixed loop uses, integrated specular and all, so one rectangle drawn either way is 0 pixels apart on both backends. They take no shadow, and are windowed to zero at `AreaLightSource.range`, an attenuation radius in metres, which a rectangle that names none derives from where its light on its own axis falls to a thousandth of a scene unit. A stage with 163 rectangle lights had been drawing them as spots. Without the table, rectangles past the fixed ones are said once on the console rather than dropped quietly."
|
|
116
228
|
},
|
|
117
229
|
{
|
|
118
230
|
"kind": "changed",
|
|
@@ -127,7 +239,7 @@
|
|
|
127
239
|
{
|
|
128
240
|
"kind": "fixed",
|
|
129
241
|
"short": "On WebGPU a crowd of skinned characters no longer stands in its bind pose past the 128th palette of a frame: the ring holds one a draw, and a rig drawn by five passes spends one slot.",
|
|
130
|
-
"text": "The WebGPU joint-palette ring was capped at 128 palettes a frame and declined every skinned draw past it, and a rig drawn in five passes (the main pass, a reflection and three shadow layers) uploaded the same matrices five times, so three dozen idling extras beside two
|
|
242
|
+
"text": "The WebGPU joint-palette ring was capped at 128 palettes a frame and declined every skinned draw past it, and a rig drawn in five passes (the main pass, a reflection and three shadow layers) uploaded the same matrices five times, so three dozen idling extras beside two characters filled it in one frame and the consumer stood its crowd in the bind pose. The ring holds as many palettes as a frame holds draws, `RenderQuality.drawsPerFrame`, and a palette set again with the same numbers is the slot it already has, compared by value, since a caller may pose every rig into one scratch array. A slot still allocates its texture only when a frame first reaches it. WebGL2 never had the limit."
|
|
131
243
|
},
|
|
132
244
|
{
|
|
133
245
|
"kind": "fixed",
|
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# @driftengine/core
|
|
2
2
|
|
|
3
|
-
The runtime of DriftEngine, a
|
|
4
|
-
WebGPU where the browser has a device and through
|
|
5
|
-
|
|
6
|
-
and the whole of
|
|
7
|
-
|
|
3
|
+
The runtime of [DriftEngine](https://github.com/drftrun/driftengine), a 3D game engine for the web
|
|
4
|
+
and for installed applications. It draws through WebGPU where the browser has a device and through
|
|
5
|
+
WebGL2 everywhere else, behind one API, and carries the fixed-step loop, the renderer, cameras,
|
|
6
|
+
input, the scene graph, geometry, text and the whole of `@driftengine/physics`, which it re-exports.
|
|
7
|
+
Everything else is a separate package a game adds when it reaches for it.
|
|
8
8
|
|
|
9
|
-
**Cost:
|
|
9
|
+
**Cost: 873.3 KB gzipped, importing `createRenderer`.** Measured by `scripts/size-gate.test.mjs`,
|
|
10
10
|
which fails the build if the figure drifts by more than 3%.
|
|
11
11
|
|
|
12
12
|
The manual is at **[driftengine.dev/docs](https://driftengine.dev/docs)**, with an example running
|
|
13
|
-
beside every chapter, and
|
|
14
|
-
[
|
|
13
|
+
beside every chapter, and every export is in the
|
|
14
|
+
[reference](https://driftengine.dev/docs/api).
|
|
15
15
|
|
|
16
16
|
## Install
|
|
17
17
|
|
|
@@ -19,7 +19,8 @@ beside every chapter, and the reference for every export at
|
|
|
19
19
|
npm install @driftengine/core
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
It
|
|
22
|
+
It resolves to compiled JavaScript, so any ES module bundler takes it as it is; Vite is what the
|
|
23
|
+
examples use. A browser needs WebGL2 at least, which every current one has.
|
|
23
24
|
[Installation](https://driftengine.dev/docs/start/installation) covers the page, TypeScript and the
|
|
24
25
|
backends.
|
|
25
26
|
|
|
@@ -170,42 +171,46 @@ This is the engine's `examples/starter`, and a test keeps the two the same.
|
|
|
170
171
|
|
|
171
172
|
## What is in it
|
|
172
173
|
|
|
173
|
-
|
|
|
174
|
-
|
|
|
175
|
-
| The frame
|
|
176
|
-
| Drawing
|
|
177
|
-
| Light at scale
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
|
|
|
174
|
+
| | |
|
|
175
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
176
|
+
| The frame | A fixed-step [loop](https://driftengine.dev/docs/start/the-loop) with interpolation, [two backends](https://driftengine.dev/docs/concepts/backends) behind one API, construction-time [quality profiles](https://driftengine.dev/docs/concepts/quality), and a [frame](https://driftengine.dev/docs/concepts/the-frame) whose order you can read. |
|
|
177
|
+
| Drawing | [Meshes](https://driftengine.dev/docs/rendering/meshes), [materials](https://driftengine.dev/docs/rendering/materials), [instancing](https://driftengine.dev/docs/rendering/instancing), [lights](https://driftengine.dev/docs/rendering/lights) and [shadows](https://driftengine.dev/docs/rendering/shadows), [the sky](https://driftengine.dev/docs/rendering/sky-and-atmosphere), [fog and weather](https://driftengine.dev/docs/rendering/fog-and-weather), [water](https://driftengine.dev/docs/rendering/water), [reflections](https://driftengine.dev/docs/rendering/reflections), [post-processing](https://driftengine.dev/docs/rendering/post-processing), [particles](https://driftengine.dev/docs/rendering/particles), [text](https://driftengine.dev/docs/rendering/text-and-overlays) and [passes of your own](https://driftengine.dev/docs/rendering/custom-passes). |
|
|
178
|
+
| Light at scale | [DriftLight](https://driftengine.dev/docs/rendering/driftlight) for thousands of fixed lights, [DriftRay](https://driftengine.dev/docs/rendering/driftray) for bounced light traced every frame, [DriftTR](https://driftengine.dev/docs/rendering/drifttr) for temporal reconstruction, and the [GPU-driven pipeline](https://driftengine.dev/docs/rendering/gpu-driven). |
|
|
179
|
+
| Many things | Instanced batches that cull, crowds animated from bone textures in the vertex stage (`createBoneAnimation`), and static draws recorded once and replayed every frame (`createStaticDraws`). |
|
|
180
|
+
| Textures | Images and compressed blocks through one call: BC for desktops, ETC2, EAC and ASTC for phones, each uploaded as it is where `compressedFormats` says the device samples it. `updateSurfaceTexture` can replace an image with blocks behind the handle a draw already holds. |
|
|
181
|
+
| Worlds | [Worlds bigger than a float](https://driftengine.dev/docs/worlds/large-worlds), streamed in cells, with [hierarchical detail](https://driftengine.dev/docs/worlds/hierarchical-detail) and [worlds built from a kit](https://driftengine.dev/docs/worlds/worlds-from-a-kit). |
|
|
182
|
+
| Physics | Deterministic [rigid bodies](https://driftengine.dev/docs/simulation/rigid-bodies), [joints](https://driftengine.dev/docs/simulation/joints), [queries](https://driftengine.dev/docs/simulation/queries), [characters](https://driftengine.dev/docs/simulation/characters), [vehicles](https://driftengine.dev/docs/simulation/vehicles), and [ragdolls and cloth](https://driftengine.dev/docs/simulation/ragdolls-and-cloth). |
|
|
183
|
+
| Play | [Input](https://driftengine.dev/docs/interface/input) from every device through one action map, [cameras that cut](https://driftengine.dev/docs/interface/cameras), [picking](https://driftengine.dev/docs/rendering/picking) and the [scene graph](https://driftengine.dev/docs/concepts/scene-graph). |
|
|
184
|
+
| Around the game | Saves and preferences through a store the game supplies, a host seam for windows, displays and files, and the visual-gate scripts — `@driftengine/core/scripts/browser.mjs` and its siblings — that photograph a page on the hardware GPU. |
|
|
181
185
|
|
|
182
186
|
## The other packages
|
|
183
187
|
|
|
184
188
|
Each is added when a game reaches for it, and a game that never imports one carries none of it.
|
|
185
189
|
|
|
186
|
-
| Package | What it adds
|
|
187
|
-
| ----------------------------------------------------- |
|
|
188
|
-
| `@driftengine/animation` | Skeletons, clips, blend trees and IK. [Guide](https://driftengine.dev/docs/simulation/animation)
|
|
189
|
-
| `@driftengine/nav` | Navigation meshes and routes. [Guide](https://driftengine.dev/docs/simulation/navigation)
|
|
190
|
-
| `@driftengine/entities` |
|
|
191
|
-
| `@driftengine/chemistry` | Heat, burning, phase changes and smoke. [Guide](https://driftengine.dev/docs/simulation/chemistry)
|
|
192
|
-
| `@driftengine/ai` | Behaviour trees and agents. [Guide](https://driftengine.dev/docs/simulation/agents)
|
|
193
|
-
| `@driftengine/audio` | A mix of buses, placed sounds, rooms and rhythm. [Guide](https://driftengine.dev/docs/content/audio)
|
|
194
|
-
| `@driftengine/assets` and `@driftengine/drft` | Model importers and the streaming `.drft` container. [Guide](https://driftengine.dev/docs/content/importing-models)
|
|
195
|
-
| `@driftengine/terrain` | Terrain drawn as a clipmap. [Guide](https://driftengine.dev/docs/worlds/terrain)
|
|
196
|
-
| `@driftengine/splats` | Gaussian splat captures among meshes. [Guide](https://driftengine.dev/docs/worlds/splats)
|
|
197
|
-
| `@driftengine/texture` | Materials as programs decoded on the device. [Guide](https://driftengine.dev/docs/worlds/drifttexture)
|
|
198
|
-
| `@driftengine/capture` | A video clip turned into a surface, a collider and entities. [Guide](https://driftengine.dev/docs/worlds/driftcapture)
|
|
199
|
-
| `@driftengine/ui2d` | Sprites, tilemaps and interfaces. [Guide](https://driftengine.dev/docs/interface/sprites)
|
|
200
|
-
| `@driftengine/script` | DriftScript, the engine's scripting language, with hot reload. [Reference](https://driftengine.dev/docs/api/script)
|
|
201
|
-
| `@driftengine/network` |
|
|
202
|
-
| `@driftengine/xr` | WebXR sessions. [Reference](https://driftengine.dev/docs/api/xr)
|
|
203
|
-
| `@driftengine/media` | Recording and exporting clips. [Reference](https://driftengine.dev/docs/api/media)
|
|
204
|
-
| `@driftengine/editor` and `@driftengine/tools` | The editor and in-game tools. [Reference](https://driftengine.dev/docs/api/editor)
|
|
205
|
-
| `@driftengine/package` and `@driftengine/native-host` | Installable apps built from the same game. [Reference](https://driftengine.dev/docs/api/package)
|
|
190
|
+
| Package | What it adds |
|
|
191
|
+
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
192
|
+
| `@driftengine/animation` | Skeletons, clips, blend trees and IK. [Guide](https://driftengine.dev/docs/simulation/animation) |
|
|
193
|
+
| `@driftengine/nav` | Navigation meshes and routes. [Guide](https://driftengine.dev/docs/simulation/navigation) |
|
|
194
|
+
| `@driftengine/entities` | Entities, components, systems and prefabs, with rewind. [Guide](https://driftengine.dev/docs/simulation/entities) |
|
|
195
|
+
| `@driftengine/chemistry` | Heat, burning, phase changes and smoke. [Guide](https://driftengine.dev/docs/simulation/chemistry) |
|
|
196
|
+
| `@driftengine/ai` | Behaviour trees and agents. [Guide](https://driftengine.dev/docs/simulation/agents) |
|
|
197
|
+
| `@driftengine/audio` | A mix of buses, placed sounds, rooms and rhythm. [Guide](https://driftengine.dev/docs/content/audio) |
|
|
198
|
+
| `@driftengine/assets` and `@driftengine/drft` | Model importers, KTX2, and the streaming `.drft` container. [Guide](https://driftengine.dev/docs/content/importing-models) |
|
|
199
|
+
| `@driftengine/terrain` | Terrain drawn as a clipmap. [Guide](https://driftengine.dev/docs/worlds/terrain) |
|
|
200
|
+
| `@driftengine/splats` | Gaussian splat captures among meshes. [Guide](https://driftengine.dev/docs/worlds/splats) |
|
|
201
|
+
| `@driftengine/texture` | Materials as programs decoded on the device. [Guide](https://driftengine.dev/docs/worlds/drifttexture) |
|
|
202
|
+
| `@driftengine/capture` | A video clip turned into a surface, a collider and entities. [Guide](https://driftengine.dev/docs/worlds/driftcapture) |
|
|
203
|
+
| `@driftengine/ui2d` | Sprites, tilemaps and interfaces. [Guide](https://driftengine.dev/docs/interface/sprites) |
|
|
204
|
+
| `@driftengine/script` | DriftScript, the engine's scripting language, with hot reload. [Reference](https://driftengine.dev/docs/api/script) |
|
|
205
|
+
| `@driftengine/network` | Lockstep and rollback netcode. [Reference](https://driftengine.dev/docs/api/network) |
|
|
206
|
+
| `@driftengine/xr` | WebXR sessions. [Reference](https://driftengine.dev/docs/api/xr) |
|
|
207
|
+
| `@driftengine/media` | Recording and exporting clips. [Reference](https://driftengine.dev/docs/api/media) |
|
|
208
|
+
| `@driftengine/editor` and `@driftengine/tools` | The editor and in-game tools. [Reference](https://driftengine.dev/docs/api/editor) |
|
|
209
|
+
| `@driftengine/package` and `@driftengine/native-host` | Installable apps built from the same game. [Reference](https://driftengine.dev/docs/api/package) |
|
|
206
210
|
|
|
207
211
|
## Licence
|
|
208
212
|
|
|
209
|
-
Apache-2.0.
|
|
213
|
+
Apache-2.0. Distributing it means reproducing its `NOTICE`, which every bundle of it already
|
|
214
|
+
carries. Part of [DriftEngine](https://github.com/drftrun/driftengine); see
|
|
210
215
|
[`docs/ARCHITECTURE.md`](https://github.com/drftrun/driftengine/blob/main/docs/ARCHITECTURE.md) for
|
|
211
216
|
how the packages divide.
|
package/dist/index.d.ts
CHANGED
|
@@ -145,6 +145,8 @@ export { placeCascade } from './render/gi/globalField.ts';
|
|
|
145
145
|
export type { ReflectionOptions, ReflectiveSample } from './render/gi/reflection.ts';
|
|
146
146
|
export { GRADE_PLACEHOLDER_SIZE, MAX_GRADE_SIZE, identityGradeLut } from './render/colourGrade.ts';
|
|
147
147
|
export type { ColourGradeLut } from './render/colourGrade.ts';
|
|
148
|
+
export { DEFAULT_FILMIC_CURVE } from './render/filmicCurve.ts';
|
|
149
|
+
export type { FilmicCurve } from './render/filmicCurve.ts';
|
|
148
150
|
/**
|
|
149
151
|
* How bloom answers past its threshold — a ramp in place of the subtraction, and a tint for each
|
|
150
152
|
* of the pyramid's `BLOOM_LEVELS` octaves — the third argument of `setBloom`.
|
|
@@ -157,6 +159,9 @@ export type { BoltHandle, CausticsHandle, ClothBindingHandle, ClothParticlesHand
|
|
|
157
159
|
export type { ClothBindingData } from './render/clothBindingData.ts';
|
|
158
160
|
export { anisotropicModel, eyeModel, hairModel, lightmapModel, skinModel, } from './render/surfaceModel.ts';
|
|
159
161
|
export type { AnisotropicModel, EyeModel, HairModel, LightmapModel, SkinModel, SurfaceModel, SurfaceModelKind, } from './render/surfaceModel.ts';
|
|
162
|
+
export { DEFAULT_FRAME_REFLECTIONS } from './render/frameReflections.ts';
|
|
163
|
+
export type { FrameReflections } from './render/frameReflections.ts';
|
|
164
|
+
export type { OverlayRegion, SurfaceDissolve, SurfaceOverlay, SurfaceRim, SurfaceWrinkle, } from './render/surfaceOverlay.ts';
|
|
160
165
|
export { WHOLE_PAGE } from './render/lightmap.ts';
|
|
161
166
|
export type { LightmapPage, LightmapRegion } from './render/lightmap.ts';
|
|
162
167
|
export { createSkinnedCloth } from './render/skinnedClothRun.ts';
|
|
@@ -170,6 +175,8 @@ export type { SkinnedClothSolver } from './render/skinnedClothRun.ts';
|
|
|
170
175
|
export type { BudgetLine, FrameBudget } from './render/backend/budget.ts';
|
|
171
176
|
export type { FrameTimer } from './render/backend/timer.ts';
|
|
172
177
|
export type { SceneCasterMaterial, SceneCasters, ShadowCasterCloth, ShadowCasterSink, ShadowCasters, } from './render/shadowCasters.ts';
|
|
178
|
+
export type { StaticDrawsHandle } from './render/staticDraws.ts';
|
|
179
|
+
export type { BoneAnimationClip, BoneAnimationHandle } from './render/boneAnimation.ts';
|
|
173
180
|
export type { Atmosphere, UnderwaterAtmosphere } from './render/atmosphere.ts';
|
|
174
181
|
export { createImageTexelDecoder } from './render/imageTexels.ts';
|
|
175
182
|
export type { ImageTexelDecoder, ImageTexels } from './render/imageTexels.ts';
|
|
@@ -221,7 +228,7 @@ export { MAX_POINT_LIGHTS, SURFACE_TEXTURE_UNIT } from './render/lightBudget.ts'
|
|
|
221
228
|
export { MAX_CLUSTERED_LIGHTS } from './render/clusteredLights.ts';
|
|
222
229
|
export { SurfaceTexture } from './render/surfaceTexture.ts';
|
|
223
230
|
export type { SurfaceMaterial, SurfaceTextureOptions } from './render/surfaceTexture.ts';
|
|
224
|
-
export { compressedFormatName, isCompressedSource, uploadsCompressed, } from './render/compressedSource.ts';
|
|
231
|
+
export { compressedFormatName, isCompressedSource, levelBytes, uploadsCompressed, } from './render/compressedSource.ts';
|
|
225
232
|
export type { BlockFormat, CompressedTextureFormat, CompressedTextureSource, SurfaceSource, } from './render/compressedSource.ts';
|
|
226
233
|
export { DEFAULT_GOVERNOR_LIMITS, ResolutionGovernor } from './render/resolutionGovernor.ts';
|
|
227
234
|
export type { GovernorLimits } from './render/resolutionGovernor.ts';
|
package/dist/index.js
CHANGED
|
@@ -209,6 +209,7 @@ export { placeCascade } from './render/gi/globalField.js';
|
|
|
209
209
|
* take the identity, bend it, hand it back — and because it is what the placeholder is.
|
|
210
210
|
*/
|
|
211
211
|
export { GRADE_PLACEHOLDER_SIZE, MAX_GRADE_SIZE, identityGradeLut } from './render/colourGrade.js';
|
|
212
|
+
export { DEFAULT_FILMIC_CURVE } from './render/filmicCurve.js';
|
|
212
213
|
/**
|
|
213
214
|
* How bloom answers past its threshold — a ramp in place of the subtraction, and a tint for each
|
|
214
215
|
* of the pyramid's `BLOOM_LEVELS` octaves — the third argument of `setBloom`.
|
|
@@ -221,6 +222,12 @@ export { probeDevice } from './render/backend/probe.js';
|
|
|
221
222
|
* its own, compiled the first time a draw asks.
|
|
222
223
|
*/
|
|
223
224
|
export { anisotropicModel, eyeModel, hairModel, lightmapModel, skinModel, } from './render/surfaceModel.js';
|
|
225
|
+
/*
|
|
226
|
+
* What a draw lays over its surface beyond its material — a rim of light, a dissolve, wrinkle
|
|
227
|
+
* normals by region — set per draw with `setSurfaceOverlay`, its images regions of one atlas.
|
|
228
|
+
*/
|
|
229
|
+
/* Every opaque lit surface reflecting the frame by its own material: `screenSpaceReflections`. */
|
|
230
|
+
export { DEFAULT_FRAME_REFLECTIONS } from './render/frameReflections.js';
|
|
224
231
|
/*
|
|
225
232
|
* A baked lightmap: the page a consumer decoded, which `createLightmap` uploads as a lightmapped
|
|
226
233
|
* material's `modelMap`, and the region of it a material or an instance reads.
|
|
@@ -281,10 +288,11 @@ export { MAX_POINT_LIGHTS, SURFACE_TEXTURE_UNIT } from './render/lightBudget.js'
|
|
|
281
288
|
export { MAX_CLUSTERED_LIGHTS } from './render/clusteredLights.js';
|
|
282
289
|
export { SurfaceTexture } from './render/surfaceTexture.js';
|
|
283
290
|
/*
|
|
284
|
-
* BC
|
|
285
|
-
* ask before handing one over — whether this device takes its format
|
|
291
|
+
* Compressed textures — BC, ETC2 and EAC, ASTC: the source `createSurfaceTexture` takes as blocks,
|
|
292
|
+
* the one question to ask before handing one over — whether this device takes its format
|
|
293
|
+
* (`renderer.compressedFormats`) — and the bytes a level of it holds, for a reader checking a file.
|
|
286
294
|
*/
|
|
287
|
-
export { compressedFormatName, isCompressedSource, uploadsCompressed, } from './render/compressedSource.js';
|
|
295
|
+
export { compressedFormatName, isCompressedSource, levelBytes, uploadsCompressed, } from './render/compressedSource.js';
|
|
288
296
|
export { DEFAULT_GOVERNOR_LIMITS, ResolutionGovernor } from './render/resolutionGovernor.js';
|
|
289
297
|
export { isWeakGpuFamily } from './render/gpuCapability.js';
|
|
290
298
|
/**
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* **Why a draw needs its own.** The engine's diffuse ambient is one answer for a whole frame — the
|
|
6
6
|
* sky-and-ground gradient, or the probe grid's irradiance — so everything standing in one place is
|
|
7
|
-
* lit alike. A stage with a baked volume of indirect light (
|
|
7
|
+
* lit alike. A stage with a baked volume of indirect light (a volumetric lightmap) lights a
|
|
8
8
|
* character by sampling that volume where the character stands; a consumer that samples it each
|
|
9
9
|
* frame hands the result here, around that character's draws, and the character takes the light of
|
|
10
10
|
* the spot it is in rather than the frame's average.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* **Why a draw needs its own.** The engine's diffuse ambient is one answer for a whole frame — the
|
|
6
6
|
* sky-and-ground gradient, or the probe grid's irradiance — so everything standing in one place is
|
|
7
|
-
* lit alike. A stage with a baked volume of indirect light (
|
|
7
|
+
* lit alike. A stage with a baked volume of indirect light (a volumetric lightmap) lights a
|
|
8
8
|
* character by sampling that volume where the character stands; a consumer that samples it each
|
|
9
9
|
* frame hands the result here, around that character's draws, and the character takes the light of
|
|
10
10
|
* the spot it is in rather than the frame's average.
|
|
@@ -92,14 +92,14 @@ export interface AreaLightSource {
|
|
|
92
92
|
* others. **Read only where the rectangle is shaded through the froxel table** — the ones past
|
|
93
93
|
* `maxAreaLights` with `clusteredLights` on; the fixed four light everything they face, as they
|
|
94
94
|
* always have. Absent, it is where the rectangle's irradiance on its axis falls to a thousandth
|
|
95
|
-
* of a scene unit, and never inside the rectangle itself.
|
|
95
|
+
* of a scene unit, and never inside the rectangle itself. An attenuation radius, in metres.
|
|
96
96
|
*/
|
|
97
97
|
range?: number;
|
|
98
98
|
/**
|
|
99
99
|
* Barn doors: a flap hinged at each of the rectangle's four edges, standing this many degrees from
|
|
100
100
|
* its normal. 90, or absent, folds them flat and they hide nothing; smaller closes them, so the
|
|
101
101
|
* light narrows to the opening they leave — a rectangle at 50° throws a beam rather than filling
|
|
102
|
-
* its hemisphere.
|
|
102
|
+
* its hemisphere. 88° is the usual default, nearly flat.
|
|
103
103
|
*
|
|
104
104
|
* What a fragment sees past the doors is the part of the rectangle no door's tip hides, one axis
|
|
105
105
|
* at a time, and the rectangle then shades as that smaller rectangle, its highlight included.
|
|
@@ -109,7 +109,7 @@ export interface AreaLightSource {
|
|
|
109
109
|
* rectangle's back face has none.
|
|
110
110
|
*/
|
|
111
111
|
barnDoorAngle?: number;
|
|
112
|
-
/** The barn doors' length in metres. Absent, 0.2:
|
|
112
|
+
/** The barn doors' length in metres. Absent, 0.2: the usual default of 20 cm. */
|
|
113
113
|
barnDoorLength?: number;
|
|
114
114
|
}
|
|
115
115
|
/** The irradiance a derived `range` ends at, in scene units. See `AreaLightSource.range`. */
|
|
@@ -132,7 +132,7 @@ export interface AreaLightBuffer {
|
|
|
132
132
|
readonly barnDoors?: Float32Array;
|
|
133
133
|
}
|
|
134
134
|
export declare function createAreaLightBuffer(capacity?: number): AreaLightBuffer;
|
|
135
|
-
/**
|
|
135
|
+
/** The usual default barn door length, in metres. See `AreaLightSource.barnDoorLength`. */
|
|
136
136
|
export declare const DEFAULT_BARN_DOOR_LENGTH = 0.2;
|
|
137
137
|
/**
|
|
138
138
|
* A rectangle's barn doors as the shader reads them, into `out[at]` and `out[at + 1]`: the cosine of
|
|
@@ -23,7 +23,7 @@ export function createAreaLightBuffer(capacity = MAX_AREA_LIGHTS) {
|
|
|
23
23
|
barnDoors: new Float32Array(capacity * 2),
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
26
|
+
/** The usual default barn door length, in metres. See `AreaLightSource.barnDoorLength`. */
|
|
27
27
|
export const DEFAULT_BARN_DOOR_LENGTH = 0.2;
|
|
28
28
|
/**
|
|
29
29
|
* A rectangle's barn doors as the shader reads them, into `out[at]` and `out[at + 1]`: the cosine of
|
|
@@ -45,6 +45,19 @@ export interface Atmosphere {
|
|
|
45
45
|
/** Linear mode only: where haze begins, and where it is total. */
|
|
46
46
|
fogNear?: number;
|
|
47
47
|
fogFar?: number;
|
|
48
|
+
/**
|
|
49
|
+
* The medium only: how far along the view ray it begins, in metres. Absent or 0 is at the
|
|
50
|
+
* camera, as every world before it was drawn.
|
|
51
|
+
*
|
|
52
|
+
* The air nearer than this is perfectly clear, and what lies beyond is fogged by the air past
|
|
53
|
+
* this point alone — so a faint, bright haze can lie over a distant crowd while the figures a
|
|
54
|
+
* few metres from the camera stay sharp, which no density can do when the medium starts at the
|
|
55
|
+
* eye: there it veils the whole frame, lifting the shadows and draining the colour before it
|
|
56
|
+
* reaches anything far enough to want it. Unlike `linear`'s `fogNear`, nothing past it is a
|
|
57
|
+
* ramp: it is the same extinction, integrated from further out. **What it gives up** is the air
|
|
58
|
+
* between the camera and the start, which a real medium has; that is the point of it.
|
|
59
|
+
*/
|
|
60
|
+
fogStart?: number;
|
|
48
61
|
underwater: UnderwaterAtmosphere | null;
|
|
49
62
|
}
|
|
50
63
|
/**
|
|
@@ -46,7 +46,15 @@ export function resolveAtmosphere(atmosphere, cameraY, underwaterEnabled, out) {
|
|
|
46
46
|
out.fogHeightFalloff = atmosphere.fogHeightFalloff;
|
|
47
47
|
out.fogEyeY = cameraY;
|
|
48
48
|
out.fogMode = atmosphere.fogMode === 'linear' ? 1 : 0;
|
|
49
|
-
|
|
49
|
+
/*
|
|
50
|
+
* **One slot, two meanings, and never both**: the ramp's near distance in linear mode, and in
|
|
51
|
+
* the medium where it begins (`fogStart`), which the medium never read before — so a world that
|
|
52
|
+
* left a `fogNear` on an exponential fog starts nothing, and draws exactly as it did.
|
|
53
|
+
*/
|
|
54
|
+
out.fogNear =
|
|
55
|
+
atmosphere.fogMode === 'linear'
|
|
56
|
+
? (atmosphere.fogNear ?? 0)
|
|
57
|
+
: Math.max(0, Number.isFinite(atmosphere.fogStart) ? (atmosphere.fogStart ?? 0) : 0);
|
|
50
58
|
out.fogFar = atmosphere.fogFar ?? 1;
|
|
51
59
|
/*
|
|
52
60
|
* The air medium stands in when nothing is submerged. The shaders multiply by the factor
|