@driftengine/core 4.8.6 → 4.8.7
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 +71 -0
- package/README.md +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/render/anisotropicLobe.d.ts +10 -0
- package/dist/render/anisotropicLobe.js +19 -0
- package/dist/render/areaLights.d.ts +35 -0
- package/dist/render/areaLights.js +35 -0
- package/dist/render/backend/api.d.ts +33 -3
- package/dist/render/backend/webgl2/renderer.d.ts +50 -14
- package/dist/render/backend/webgl2/renderer.js +141 -30
- package/dist/render/backend/webgl2/sceneCaptureTarget.d.ts +29 -0
- package/dist/render/backend/webgl2/sceneCaptureTarget.js +96 -0
- package/dist/render/backend/webgpu/particlePass.js +2 -1
- package/dist/render/backend/webgpu/renderer.d.ts +35 -1
- package/dist/render/backend/webgpu/renderer.js +155 -16
- package/dist/render/backend/webgpu/sceneCaptureTarget.d.ts +24 -0
- package/dist/render/backend/webgpu/sceneCaptureTarget.js +59 -0
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +4 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.js +34 -8
- package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
- package/dist/render/clusteredLights.d.ts +23 -5
- package/dist/render/clusteredLights.js +35 -8
- package/dist/render/driftLight/bake.d.ts +2 -0
- package/dist/render/driftLight/bake.js +1 -1
- package/dist/render/driftLight/falloff.d.ts +4 -2
- package/dist/render/driftLight/falloff.js +8 -2
- package/dist/render/gi/bounceLights.d.ts +3 -2
- package/dist/render/gi/bounceLights.js +8 -3
- package/dist/render/instanceCull.js +5 -0
- package/dist/render/instances.d.ts +19 -5
- package/dist/render/instances.js +9 -3
- package/dist/render/lightBudget.d.ts +12 -1
- package/dist/render/lightBudget.js +23 -3
- package/dist/render/lightmap.d.ts +23 -9
- package/dist/render/lightmap.js +40 -18
- package/dist/render/particlePool.d.ts +21 -0
- package/dist/render/particlePool.js +7 -0
- package/dist/render/pointLightSelection.d.ts +13 -0
- package/dist/render/pointLightSelection.js +3 -1
- package/dist/render/renderQuality.d.ts +8 -7
- package/dist/render/rendererHarness.js +3 -0
- package/dist/render/rgb9e5.d.ts +22 -0
- package/dist/render/rgb9e5.js +47 -0
- package/dist/render/sceneCapture.d.ts +29 -0
- package/dist/render/sceneCapture.js +36 -0
- package/dist/render/screenSpaceReflection.d.ts +27 -1
- package/dist/render/screenSpaceReflection.js +9 -0
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/bolt.js +7 -1
- package/dist/render/shaders/depth.js +11 -0
- package/dist/render/shaders/flat/anisotropic.d.ts +1 -1
- package/dist/render/shaders/flat/anisotropic.js +37 -3
- package/dist/render/shaders/flat/areaLight.d.ts +1 -1
- package/dist/render/shaders/flat/areaLight.js +46 -0
- package/dist/render/shaders/flat/glassTint.d.ts +3 -2
- package/dist/render/shaders/flat/glassTint.js +3 -1
- package/dist/render/shaders/flat/index.d.ts +5 -0
- package/dist/render/shaders/flat/index.js +16 -2
- package/dist/render/shaders/flat/lobes.d.ts +6 -0
- package/dist/render/shaders/flat/lobes.js +49 -43
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +57 -22
- package/dist/render/shaders/flat/models.d.ts +5 -2
- package/dist/render/shaders/flat/models.js +100 -16
- package/dist/render/shaders/flat/preamble.js +10 -3
- 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/depth.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/depth.wgsl.js +4 -4
- package/dist/render/shaders/generated/flat.wgsl.d.ts +16 -0
- package/dist/render/shaders/generated/flat.wgsl.js +54 -38
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +11 -6
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +11 -6
- package/dist/render/shaders/generated/water.wgsl.d.ts +23 -16
- package/dist/render/shaders/generated/water.wgsl.js +23 -16
- package/dist/render/shaders/gi/probeBake.wgsl.js +9 -5
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +13 -2
- package/dist/render/shaders/ssrTrace.js +20 -1
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/shaders/water.js +12 -3
- package/dist/render/skinScatter.d.ts +3 -1
- package/dist/render/skinScatter.js +3 -1
- package/dist/render/ssrPass.js +1 -0
- package/dist/render/surfaceModel.d.ts +29 -8
- package/dist/render/surfaceModel.js +33 -9
- package/dist/render/surfaceTexture.d.ts +25 -1
- package/dist/render/surfaceTexture.js +27 -5
- package/package.json +6 -6
- package/src/index.ts +6 -2
- package/src/render/anisotropicLobe.ts +29 -0
- package/src/render/areaLights.ts +58 -0
- package/src/render/backend/api.ts +49 -2
- package/src/render/backend/webgl2/renderer.ts +192 -38
- package/src/render/backend/webgl2/sceneCaptureTarget.ts +130 -0
- package/src/render/backend/webgpu/particlePass.ts +2 -1
- package/src/render/backend/webgpu/renderer.ts +194 -19
- package/src/render/backend/webgpu/sceneCaptureTarget.ts +63 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +44 -14
- package/src/render/clusteredLights.ts +41 -8
- package/src/render/driftLight/bake.ts +3 -1
- package/src/render/driftLight/falloff.ts +13 -2
- package/src/render/gi/bounceLights.ts +12 -3
- package/src/render/instanceCull.ts +4 -0
- package/src/render/instances.ts +26 -6
- package/src/render/lightBudget.ts +40 -2
- package/src/render/lightmap.ts +64 -23
- package/src/render/particlePool.ts +23 -0
- package/src/render/pointLightSelection.ts +20 -1
- package/src/render/renderQuality.ts +8 -7
- package/src/render/rendererHarness.ts +3 -0
- package/src/render/rgb9e5.ts +52 -0
- package/src/render/sceneCapture.ts +56 -0
- package/src/render/screenSpaceReflection.ts +33 -1
- package/src/render/shaders/bolt.ts +7 -1
- package/src/render/shaders/depth.ts +11 -0
- package/src/render/shaders/flat/anisotropic.ts +37 -3
- package/src/render/shaders/flat/areaLight.ts +46 -0
- package/src/render/shaders/flat/glassTint.ts +9 -2
- package/src/render/shaders/flat/index.ts +21 -2
- package/src/render/shaders/flat/lobes.ts +50 -43
- package/src/render/shaders/flat/main.ts +57 -22
- package/src/render/shaders/flat/models.ts +100 -16
- package/src/render/shaders/flat/preamble.ts +10 -3
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +4 -4
- package/src/render/shaders/generated/flat.wgsl.ts +54 -38
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +11 -6
- package/src/render/shaders/generated/water.wgsl.ts +23 -16
- package/src/render/shaders/gi/probeBake.wgsl.ts +9 -5
- package/src/render/shaders/recon/motion.wgsl.ts +13 -2
- package/src/render/shaders/ssrTrace.ts +20 -1
- package/src/render/shaders/water.ts +12 -3
- package/src/render/skinScatter.ts +3 -1
- package/src/render/ssrPass.ts +1 -0
- package/src/render/surfaceModel.ts +47 -10
- package/src/render/surfaceTexture.ts +69 -9
package/CHANGELOG.json
CHANGED
|
@@ -1,4 +1,75 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "4.8.7",
|
|
4
|
+
"date": "2026-10-06",
|
|
5
|
+
"entries": [
|
|
6
|
+
{
|
|
7
|
+
"kind": "changed",
|
|
8
|
+
"short": "A lightmap page is 8 bytes a texel, half what it was: the irradiance is an rgb9e5 word the lit stage decodes and filters, and a bake that arrives packed uploads where it lies.",
|
|
9
|
+
"text": "`createLightmap` stored a page as two half-float layers, 16 bytes a texel, so a stage of 49 pages and 21.8 million texels took 348 MB on the device. The irradiance is now one rgb9e5 word a texel, three 9-bit mantissas over a shared 5-bit exponent in the layout of `EXT_texture_shared_exponent` and WebGPU's `rgb9e5ufloat`, beside the direction's four bytes, in two `rgba8` layers that the lit stage decodes and filters itself: 8 bytes a texel, 174 MB for the same stage. `LightmapPage.irradiance` takes a `Uint32Array` of packed words as a bake hands them over, uploaded where they lie with no float array in between, as well as floats, which are packed once at upload. What it gives up is precision in a texel's smaller channels, which share the largest one's exponent, and anything past 65,408; light has neither to lose. On `demo/dev/lightmap.html` a page of one value is still 0 pixels from the same ambient raised by `setAmbientSH`, and the room is within one level of 4.8.6's on both backends."
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"kind": "changed",
|
|
13
|
+
"short": "The BC decode worker is behind its own specifier, so a game importing `@driftengine/assets` no longer has it in its build: name `spawnBcWorker` as `DrftLoader`'s `bcWorker` to decode in it.",
|
|
14
|
+
"text": "`DrftLoader` decoded a BC texture the device cannot take as blocks in a worker it built with `new Worker(new URL('./bcWorker.ts', import.meta.url))` inside the package's barrel, and a bundler writes that worker out at transform time, before tree-shaking, so every game importing anything from `@driftengine/assets` carried the BC decoder's chunk from 4.8.4 on, whether or not it loaded a BC texture. The gate that asserts no barrel names a worker bundled each barrel against the built packages and skipped one that would not bundle, so it saw this one only when another test's `npm pack` had built them first, which is how it passed three releases. The factory is now `spawnBcWorker` at `@driftengine/assets/src/bcWorkers.ts`, as the physics island pool is, and a loader takes it as `bcWorker`; without it BC textures decode on the main thread and the loader says so once, naming the option. The gate bundles from source now. Every scene and page in this repository that loads a model names the worker."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"kind": "added",
|
|
18
|
+
"short": "`PointLightSource.falloffExponent` lights by `(1 - (d/R)^2)^n` with no distance term, Unreal's falloff for a light without inverse square, in both arms and on water, DriftLight and DriftRay.",
|
|
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 Unreal lights a light that does not use inverse-square falloff. A rig authored there 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
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"kind": "added",
|
|
23
|
+
"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, as Unreal's rect lights do. 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
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"kind": "added",
|
|
28
|
+
"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 Unreal shades and 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, Unreal's `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
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"kind": "added",
|
|
33
|
+
"short": "`ReflectiveSurface.fresnel` reads `strength` as the surface's reflectance head-on and weighs each pixel by the split-sum BRDF at its view and `roughness`, so a reflection follows the camera.",
|
|
34
|
+
"text": "A screen-space reflection's `strength` was one share over its box, so a floor reflected as much underfoot as toward the horizon and a consumer re-matched the share to its camera's angle each frame. With `fresnel: true` the strength is the surface's reflectance head-on and each pixel returns `F0 * A + B` of what its ray finds, the split-sum environment BRDF at its own view and the box's `roughness`: Karis's fit, now one GLSL text that the lit stage and the reflection pass both include. The pass reads no material, so the reflectance and roughness are the box's, and nothing occludes the reflection where the lit stage's ambient occlusion would. Off by default, the one share as before. Measured on `demo/dev/ssr.html`: at a reflectance of 1 and roughness 0 it is 0 pixels from a strength of 1, as the fit says, and at a pixel whose view works out by hand to N.V 0.344, reflectance 0.04 matches the constant strength the fit gives there, 0.153, to within a level on both backends."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"kind": "added",
|
|
38
|
+
"short": "`MeshInstances.uvRegions` gives each instance its own cell of its texture, so mesh particles on different flipbook frames, or props on different tiles of an atlas, are one draw.",
|
|
39
|
+
"text": "Four floats an instance, `[scaleU, scaleV, offsetU, offsetV]`, applied to the mesh's texture coordinates before the material's own scale and offset, in the lit, depth and motion stages alike, so a cutout instance's shadow is cut by its own cell. They ride the bottom row of the instance's matrix, which a placement made of a turn, a scale and a move leaves at `[0, 0, 0, 1]` and which every stage drawing an instance now rebuilds as that, so they cost no attribute and no byte; an instanced placement must be affine, as every placement of a solid object is. Absent, every instance wears the whole texture, and a culled copy carries the cells into a target that has the array. On `demo/dev/instanceCells.html` eight cards each on their own cell of a strip, in one instanced draw, are 0 pixels from eight single draws with the cell in their materials, opaque and blended, on both backends; the published scenes and the instanced shadow, cull and opacity pages are 0 pixels from 4.8.6 on WebGPU."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"kind": "added",
|
|
43
|
+
"short": "`createSceneCapture` and `captureScene` draw the world from a camera of your own into a texture any material shows, a stadium screen's emissive or a monitor's, on both backends.",
|
|
44
|
+
"text": "`createSceneCapture(width, height)` makes a texture the scene can be drawn into, and `captureScene(capture, camera, clearColor, draw)` draws it: the callback is handed the camera, its matrices shaped to the capture, and submits the world exactly as it would to the screen. The texture then goes wherever an image goes, as a material's `emissive` for a screen in the world showing what another camera sees, a monitor or a security feed. It holds radiance, as a reflection probe does: the output transform and exposure are held off for the pass, at the world's colour format and sample count, half floats under `hdrScene`, so the frame grades the screen once with everything around it. It is the probe bake's arrangement and the mesh pass alone: the sky, water and particles are in it only if the callback draws them, nothing after the world runs on it, it has no mip chain, and the frame's camera, jitter, motion, refraction copy and skin spread are left alone while it draws. WebGL2 draws a capture's rows flipped, as it does a probe face's, so it reads as an image does. A second camera's view shown on a quad filling the frame is 0 pixels from that view drawn directly, single-sampled on both backends and at four samples on WebGPU, where WebGL2's multisampled capture is WebGPU's to the pixel; and a frame with a capture in it is 0 pixels from the frame without one outside the screen."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"kind": "added",
|
|
48
|
+
"short": "`drawDeviceParticles` draws a particle pool's material from a buffer your own compute shader wrote, where it lies, with nothing read back. WebGPU only; WebGL2 says so once.",
|
|
49
|
+
"text": "A simulation can run entirely on the device: a compute shader of the consumer's own, registered with `registerCompute`, writes its particles into a buffer of its own, and `drawDeviceParticles(batch, { buffer, count }, camera, env, time)` draws the pool's material, blend, flipbook, fades and fog from that buffer in place of the one the pool uploads into. Each particle is `DEVICE_PARTICLE_FLOATS`, sixteen floats in a `ParticleInstances`' order, and the buffer needs `VERTEX` usage beside `STORAGE`; a slot of half-width 0 draws nothing, so a fixed-size buffer can hold fewer live particles than it has room for, and a count past what the buffer holds is cut to it. The particles are not sorted. WebGL2 has no compute stage, so there it says so once and draws nothing. On `demo/dev/spriteParticles.html` sixteen sprites written by a compute shader are 0 pixels from the same sixteen uploaded, soft edges included."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"kind": "fixed",
|
|
53
|
+
"short": "A skin's `radius` is how far its light travels, as documented: the profile is at two fifths of it, so screen-space skin no longer smears a face seen up close over tens of pixels.",
|
|
54
|
+
"text": "`skinModel`'s `radius` was documented as how far light travels beneath the surface before it leaves, and was handed to Burley's profile as its distance `d` itself. That profile carries light 2.5 `d` on average and the blur's taps reach 9 `d`, so light travelled two and a half times as far as the model said, and `skinScattering: 'screen-space'` spread a face at arm's length over sixty pixels: a nose, lips and brows washed into one blur. The profile is now at `radius / 2.5` in both paths, the screen-space blur and the lit stage's pre-integrated fit, transmission and penumbra, so the two still agree. Measured first rather than assumed: on a step of light at 0.75 m and 800 by 600, the blur matched the profile's own masses at the old distance exactly, edges at the predicted taps, so the kernel was right and the distance was not; it now reaches 26 pixels where it reached 65, on both backends. A skin authored against the old meaning and looking right keeps its look with its `radius` raised by 2.5."
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"kind": "fixed",
|
|
58
|
+
"short": "The anisotropic model on a mesh with neither tangents nor texture coordinates drew black, a direction normalised from zero; it takes a direction in the surface now.",
|
|
59
|
+
"text": "A brushed surface takes its direction from the tangent frame, and a mesh carrying neither tangents nor coordinates gives a frame of zeros, which normalised to a NaN and drew the whole surface black. It takes a direction in the surface's plane instead, across the world's up, so the highlight is stretched somewhere. Measured on a floor with no coordinates: the anisotropic model at strength 0 draws the standard highlight to within a level on both backends, where it drew nothing."
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"kind": "fixed",
|
|
63
|
+
"short": "Arcs stay finite under multisampling: an edge pixel shaded off the quad took the filament's side coordinate past one and its powers to NaN, which bloom spread into a white disc.",
|
|
64
|
+
"text": "A multisampled target shades a pixel on a quad's edge at its centre, which can lie outside the quad. There an arc's side coordinate ran past one, the filament's `across` went negative, and `pow` of a negative number is NaN on both backends: one dark speck, which bloom then spread into a white disc the size of its blur around every arc. `across` is clamped before its powers. Found by a scene drawing short arcs at four samples."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"kind": "note",
|
|
68
|
+
"short": "The lit stage carries the falloff exponent and barn doors in every permutation: 2.8 to 6.4% more instructions on RADV at a phone's viewport, and the same registers.",
|
|
69
|
+
"text": "What every lit pipeline now compiles was measured on RADV with a phone's viewport, against 4.8.6: the fixed-arm lit pixel shader is 5,778 instructions where it was 5,618 on WebGPU and 5,171 where it was 4,989 on WebGL2, both still 96 registers; the clustered one is 6,831 where it was 6,507 and 6,313 where it was 5,934, still 120 and 108. Registers set how many fragments a phone's GPU keeps in flight, and they did not move. The physical highlight is a lit switch and costs nothing until a material asks for it. Core's gzipped size is 828.1 KB, 29.0 KB over 4.8.6, almost all of it the generated WGSL, whose sixteen lit permutations each carry the new light loop."
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
2
73
|
{
|
|
3
74
|
"version": "4.8.6",
|
|
4
75
|
"date": "2026-10-05",
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ carries the loop, the renderer, cameras, input, the scene graph, geometry, text
|
|
|
6
6
|
and the whole of [`@driftengine/physics`](https://driftengine.dev/docs/simulation/rigid-bodies),
|
|
7
7
|
which it re-exports. The rest of the engine is separate packages you add when you need them.
|
|
8
8
|
|
|
9
|
-
**Cost:
|
|
9
|
+
**Cost: 828.1 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
|
package/dist/index.d.ts
CHANGED
|
@@ -367,8 +367,8 @@ export { seaStateForAgitation, seaStateForWind } from './render/seaState.ts';
|
|
|
367
367
|
export type { SeaState } from './render/seaState.ts';
|
|
368
368
|
export { InstancedMesh, createInstanceData, writeInstance } from './render/instancedMesh.ts';
|
|
369
369
|
export { createMeshInstances, packInstances, INSTANCE_FLOATS, INSTANCE_STRIDE, } from './render/instances.ts';
|
|
370
|
-
export { ParticlePool } from './render/particlePool.ts';
|
|
371
|
-
export type { ParticlePoolOptions, ParticleInstances } from './render/particlePool.ts';
|
|
370
|
+
export { ParticlePool, DEVICE_PARTICLE_FLOATS } from './render/particlePool.ts';
|
|
371
|
+
export type { DeviceParticles, ParticlePoolOptions, ParticleInstances, } from './render/particlePool.ts';
|
|
372
372
|
export { ParticleBatch } from './render/particleBatch.ts';
|
|
373
373
|
export type { ParticleBatchOptions, ParticleBlend, ParticleFacing, } from './render/particleBatch.ts';
|
|
374
374
|
export { PARTICLE_MOTE_FRAG, PARTICLE_SMOKE_FRAG, PARTICLE_SPARK_FRAG, PARTICLE_VERT, } from './render/shaders/particle.ts';
|
package/dist/index.js
CHANGED
|
@@ -474,7 +474,7 @@ export { InstancedMesh, createInstanceData, writeInstance } from './render/insta
|
|
|
474
474
|
* pitches and rolls and a yaw cannot say so.
|
|
475
475
|
*/
|
|
476
476
|
export { createMeshInstances, packInstances, INSTANCE_FLOATS, INSTANCE_STRIDE, } from './render/instances.js';
|
|
477
|
-
export { ParticlePool } from './render/particlePool.js';
|
|
477
|
+
export { ParticlePool, DEVICE_PARTICLE_FLOATS } from './render/particlePool.js';
|
|
478
478
|
export { ParticleBatch } from './render/particleBatch.js';
|
|
479
479
|
export { PARTICLE_MOTE_FRAG, PARTICLE_SMOKE_FRAG, PARTICLE_SPARK_FRAG, PARTICLE_VERT, } from './render/shaders/particle.js';
|
|
480
480
|
export { BoltPool } from './render/boltPool.js';
|
|
@@ -5,3 +5,13 @@ export declare function anisotropicAlphas(roughness: number, strength: number, o
|
|
|
5
5
|
* are `th`, `bh` and `nh`. 1 at the mirror direction.
|
|
6
6
|
*/
|
|
7
7
|
export declare function anisotropicLobe(th: number, bh: number, nh: number, alphaT: number, alphaB: number): number;
|
|
8
|
+
/** Three components in the lobe's frame: along the direction, across it, along the normal. */
|
|
9
|
+
export type FrameVector = readonly [number, number, number];
|
|
10
|
+
/**
|
|
11
|
+
* The physical form of the same lobe, `π · D · Vis · N·L`, for a surface whose highlight is GGX's
|
|
12
|
+
* own (`SurfaceMaterial.physicalSpecular`): the stretched distribution normalised as a BRDF's, and
|
|
13
|
+
* Smith's height-correlated masking stretched with it (Heitz 2014, as Filament writes it), Fresnel
|
|
14
|
+
* left to the caller. The half vector, the light and the view are each in the lobe's frame. At
|
|
15
|
+
* strength 0 it is isotropic GGX, the term skin's and the eye's highlights are.
|
|
16
|
+
*/
|
|
17
|
+
export declare function anisotropicPhysicalLobe(half: FrameVector, light: FrameVector, view: FrameVector, alphaT: number, alphaB: number): number;
|
|
@@ -31,3 +31,22 @@ export function anisotropicLobe(th, bh, nh, alphaT, alphaB) {
|
|
|
31
31
|
const d = x * x + y * y + nh * nh;
|
|
32
32
|
return 1 / Math.max(d * d, 1e-8);
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* The physical form of the same lobe, `π · D · Vis · N·L`, for a surface whose highlight is GGX's
|
|
36
|
+
* own (`SurfaceMaterial.physicalSpecular`): the stretched distribution normalised as a BRDF's, and
|
|
37
|
+
* Smith's height-correlated masking stretched with it (Heitz 2014, as Filament writes it), Fresnel
|
|
38
|
+
* left to the caller. The half vector, the light and the view are each in the lobe's frame. At
|
|
39
|
+
* strength 0 it is isotropic GGX, the term skin's and the eye's highlights are.
|
|
40
|
+
*/
|
|
41
|
+
export function anisotropicPhysicalLobe(half, light, view, alphaT, alphaB) {
|
|
42
|
+
const x = half[0] / alphaT;
|
|
43
|
+
const y = half[1] / alphaB;
|
|
44
|
+
const d = x * x + y * y + half[2] * half[2];
|
|
45
|
+
const distribution = 1 / (Math.PI * alphaT * alphaB * d * d);
|
|
46
|
+
const ndl = light[2];
|
|
47
|
+
const ndv = view[2];
|
|
48
|
+
const lambdaView = ndl * Math.hypot(alphaT * view[0], alphaB * view[1], ndv);
|
|
49
|
+
const lambdaLight = ndv * Math.hypot(alphaT * light[0], alphaB * light[1], ndl);
|
|
50
|
+
const visibility = 0.5 / Math.max(lambdaView + lambdaLight, 1e-5);
|
|
51
|
+
return Math.PI * distribution * visibility * ndl;
|
|
52
|
+
}
|
|
@@ -95,6 +95,22 @@ export interface AreaLightSource {
|
|
|
95
95
|
* of a scene unit, and never inside the rectangle itself. Unreal's `AttenuationRadius`, in metres.
|
|
96
96
|
*/
|
|
97
97
|
range?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Barn doors: a flap hinged at each of the rectangle's four edges, standing this many degrees from
|
|
100
|
+
* its normal. 90, or absent, folds them flat and they hide nothing; smaller closes them, so the
|
|
101
|
+
* light narrows to the opening they leave — a rectangle at 50° throws a beam rather than filling
|
|
102
|
+
* its hemisphere. Unreal's `BarnDoorAngle`, whose default of 88° is nearly flat.
|
|
103
|
+
*
|
|
104
|
+
* What a fragment sees past the doors is the part of the rectangle no door's tip hides, one axis
|
|
105
|
+
* at a time, and the rectangle then shades as that smaller rectangle, its highlight included.
|
|
106
|
+
* Its shadow map is still baked from the whole rectangle's centre. **What it gives up**: each
|
|
107
|
+
* door is taken as endless along its hinge, so the two axes clip apart and the corner where two
|
|
108
|
+
* doors meet hides a square rather than the mitre two real flaps make. One-sided: a two-sided
|
|
109
|
+
* rectangle's back face has none.
|
|
110
|
+
*/
|
|
111
|
+
barnDoorAngle?: number;
|
|
112
|
+
/** The barn doors' length in metres. Absent, 0.2: Unreal's default of 20 cm. */
|
|
113
|
+
barnDoorLength?: number;
|
|
98
114
|
}
|
|
99
115
|
/** The irradiance a derived `range` ends at, in scene units. See `AreaLightSource.range`. */
|
|
100
116
|
export declare const AREA_RANGE_CUTOFF = 0.001;
|
|
@@ -109,8 +125,27 @@ export interface AreaLightBuffer {
|
|
|
109
125
|
readonly twoSided: Float32Array;
|
|
110
126
|
/** One a rectangle: how far its light reaches. See `AreaLightSource.range`. */
|
|
111
127
|
readonly ranges?: Float32Array;
|
|
128
|
+
/**
|
|
129
|
+
* Two a rectangle: the cosine of its barn doors' angle from its normal, then their length in
|
|
130
|
+
* metres — 0 and 0 for none. See `AreaLightSource.barnDoorAngle`.
|
|
131
|
+
*/
|
|
132
|
+
readonly barnDoors?: Float32Array;
|
|
112
133
|
}
|
|
113
134
|
export declare function createAreaLightBuffer(capacity?: number): AreaLightBuffer;
|
|
135
|
+
/** Unreal's default barn door length, in metres. See `AreaLightSource.barnDoorLength`. */
|
|
136
|
+
export declare const DEFAULT_BARN_DOOR_LENGTH = 0.2;
|
|
137
|
+
/**
|
|
138
|
+
* A rectangle's barn doors as the shader reads them, into `out[at]` and `out[at + 1]`: the cosine of
|
|
139
|
+
* their angle and their length. An angle not between 0 and 90 degrees, or a length not above zero,
|
|
140
|
+
* is no doors at all, written as 0 and 0 — which the shader reads as "nothing hidden".
|
|
141
|
+
*/
|
|
142
|
+
export declare function barnDoorsOf(light: AreaLightSource, out: Float32Array, at: number): void;
|
|
143
|
+
/**
|
|
144
|
+
* The fixed arm's half extents and barn doors, four a rectangle as `uAreaLightSize` holds them: the
|
|
145
|
+
* two half extents, then the doors' cosine and length. Into a target the binder owns, for the first
|
|
146
|
+
* `MAX_AREA_LIGHTS` alone, which are all the fixed arm reads.
|
|
147
|
+
*/
|
|
148
|
+
export declare function packAreaSizesAndDoors(lights: AreaLightBuffer, out: Float32Array): void;
|
|
114
149
|
/**
|
|
115
150
|
* How far a rectangle's light reaches when it names no range: where its irradiance on its own axis,
|
|
116
151
|
* `L · A / d²` for a rectangle of radiance `L` and area `A` seen from far, falls to
|
|
@@ -20,8 +20,41 @@ export function createAreaLightBuffer(capacity = MAX_AREA_LIGHTS) {
|
|
|
20
20
|
sizes: new Float32Array(capacity * 2),
|
|
21
21
|
twoSided: new Float32Array(capacity),
|
|
22
22
|
ranges: new Float32Array(capacity),
|
|
23
|
+
barnDoors: new Float32Array(capacity * 2),
|
|
23
24
|
};
|
|
24
25
|
}
|
|
26
|
+
/** Unreal's default barn door length, in metres. See `AreaLightSource.barnDoorLength`. */
|
|
27
|
+
export const DEFAULT_BARN_DOOR_LENGTH = 0.2;
|
|
28
|
+
/**
|
|
29
|
+
* A rectangle's barn doors as the shader reads them, into `out[at]` and `out[at + 1]`: the cosine of
|
|
30
|
+
* their angle and their length. An angle not between 0 and 90 degrees, or a length not above zero,
|
|
31
|
+
* is no doors at all, written as 0 and 0 — which the shader reads as "nothing hidden".
|
|
32
|
+
*/
|
|
33
|
+
export function barnDoorsOf(light, out, at) {
|
|
34
|
+
const angle = light.barnDoorAngle;
|
|
35
|
+
const length = light.barnDoorLength ?? DEFAULT_BARN_DOOR_LENGTH;
|
|
36
|
+
if (angle === undefined || !(angle >= 0 && angle < 90) || !(length > 0)) {
|
|
37
|
+
out[at] = 0;
|
|
38
|
+
out[at + 1] = 0;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
out[at] = Math.cos((angle * Math.PI) / 180);
|
|
42
|
+
out[at + 1] = length;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The fixed arm's half extents and barn doors, four a rectangle as `uAreaLightSize` holds them: the
|
|
46
|
+
* two half extents, then the doors' cosine and length. Into a target the binder owns, for the first
|
|
47
|
+
* `MAX_AREA_LIGHTS` alone, which are all the fixed arm reads.
|
|
48
|
+
*/
|
|
49
|
+
export function packAreaSizesAndDoors(lights, out) {
|
|
50
|
+
const doors = lights.barnDoors;
|
|
51
|
+
for (let a = 0; a < MAX_AREA_LIGHTS; a++) {
|
|
52
|
+
out[a * 4] = lights.sizes[a * 2] ?? 0;
|
|
53
|
+
out[a * 4 + 1] = lights.sizes[a * 2 + 1] ?? 0;
|
|
54
|
+
out[a * 4 + 2] = doors?.[a * 2] ?? 0;
|
|
55
|
+
out[a * 4 + 3] = doors?.[a * 2 + 1] ?? 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
25
58
|
/**
|
|
26
59
|
* How far a rectangle's light reaches when it names no range: where its irradiance on its own axis,
|
|
27
60
|
* `L · A / d²` for a rectangle of radiance `L` and area `A` seen from far, falls to
|
|
@@ -106,6 +139,8 @@ export function selectAreaLights(lights, out) {
|
|
|
106
139
|
? light.range
|
|
107
140
|
: areaRange(light.r, light.g, light.b, light.halfWidth, light.halfHeight);
|
|
108
141
|
}
|
|
142
|
+
if (out.barnDoors !== undefined)
|
|
143
|
+
barnDoorsOf(light, out.barnDoors, slot * 2);
|
|
109
144
|
}
|
|
110
145
|
return out;
|
|
111
146
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Bounds } from '../../math/bounds.ts';
|
|
2
2
|
import type { Vec3 } from '../../math/color.ts';
|
|
3
|
+
import type { Camera } from '../camera.ts';
|
|
3
4
|
import type { ReadonlyMat4 } from 'gl-matrix';
|
|
4
5
|
import type { MeshData } from '../mesh.ts';
|
|
5
6
|
import type { ProbeBakeOptions } from '../reflectionProbe.ts';
|
|
@@ -8,6 +9,7 @@ import type { InstancedOptions, MeshInstances } from '../instances.ts';
|
|
|
8
9
|
import type { SurfaceMaterial } from '../surfaceTexture.ts';
|
|
9
10
|
import type { SurfaceSource } from '../compressedSource.ts';
|
|
10
11
|
import type { LightmapPage } from '../lightmap.ts';
|
|
12
|
+
import type { DeviceParticles } from '../particlePool.ts';
|
|
11
13
|
import type { ClothBindingData } from '../clothBindingData.ts';
|
|
12
14
|
import type { TextStyle } from '../textLayout.ts';
|
|
13
15
|
import type { SdfFont } from '../sdfFont.ts';
|
|
@@ -187,7 +189,7 @@ export interface MeshOptions {
|
|
|
187
189
|
}
|
|
188
190
|
export type RendererApi = Omit<{
|
|
189
191
|
[K in keyof Renderer]: Renderer[K];
|
|
190
|
-
}, 'gpuTimer' | 'createMesh' | 'createMeshIncremental' | 'updateMesh' | 'drawMesh' | 'disposeMesh' | 'drawTranslucentMesh' | 'drawLightVolume' | 'drawFilm' | 'createScatter' | 'drawScatter' | 'uploadScatter' | 'disposeScatter' | 'createInstanced' | 'uploadInstanced' | 'drawInstanced' | 'drawTranslucentInstanced' | 'disposeInstanced' | 'createWater' | 'drawWater' | 'disposeWater' | 'createPlumes' | 'drawPlumes' | 'disposePlumes' | 'setPlumeScale' | 'createCaustics' | 'drawCaustics' | 'disposeCaustics' | 'createParticles' | 'drawParticles' | 'disposeParticles' | 'createWindStreaks' | 'drawWindStreaks' | 'disposeWindStreaks' | 'createFlock' | 'drawFlock' | 'disposeFlock' | 'createBolts' | 'drawBolts' | 'disposeBolts' | 'createLines' | 'drawLines' | 'disposeLines' | 'createText' | 'setText' | 'setPlate' | 'drawText' | 'textWidth' | 'disposeText' | 'createSdfText' | 'setSdfText' | 'drawSdfText' | 'disposeSdfText' | 'createSurfaceTexture' | 'createSurfaceTextureArray' | 'createLightmap' | 'updateSurfaceTexture' | 'disposeSurfaceTexture' | 'setSurfaceTexture' | 'setMaterial' | 'createClothBinding' | 'createClothParticles' | 'updateClothParticles' | 'setCloth' | 'disposeClothBinding' | 'disposeClothParticles'> & {
|
|
192
|
+
}, 'gpuTimer' | 'createMesh' | 'createMeshIncremental' | 'updateMesh' | 'drawMesh' | 'disposeMesh' | 'drawTranslucentMesh' | 'drawLightVolume' | 'drawFilm' | 'createScatter' | 'drawScatter' | 'uploadScatter' | 'disposeScatter' | 'createInstanced' | 'uploadInstanced' | 'drawInstanced' | 'drawTranslucentInstanced' | 'disposeInstanced' | 'createWater' | 'drawWater' | 'disposeWater' | 'createPlumes' | 'drawPlumes' | 'disposePlumes' | 'setPlumeScale' | 'createCaustics' | 'drawCaustics' | 'disposeCaustics' | 'createParticles' | 'drawParticles' | 'drawDeviceParticles' | 'disposeParticles' | 'createWindStreaks' | 'drawWindStreaks' | 'disposeWindStreaks' | 'createFlock' | 'drawFlock' | 'disposeFlock' | 'createBolts' | 'drawBolts' | 'disposeBolts' | 'createLines' | 'drawLines' | 'disposeLines' | 'createText' | 'setText' | 'setPlate' | 'drawText' | 'textWidth' | 'disposeText' | 'createSdfText' | 'setSdfText' | 'drawSdfText' | 'disposeSdfText' | 'createSurfaceTexture' | 'createSurfaceTextureArray' | 'createLightmap' | 'createSceneCapture' | 'captureScene' | 'updateSurfaceTexture' | 'disposeSurfaceTexture' | 'setSurfaceTexture' | 'setMaterial' | 'createClothBinding' | 'createClothParticles' | 'updateClothParticles' | 'setCloth' | 'disposeClothBinding' | 'disposeClothParticles'> & {
|
|
191
193
|
/**
|
|
192
194
|
* A mesh's cloth binding: which simulation triangle each of its vertices follows, where on it and
|
|
193
195
|
* by how much (`ClothBindingData`). The mesh must be skinned — a binding blends each vertex
|
|
@@ -232,12 +234,33 @@ export type RendererApi = Omit<{
|
|
|
232
234
|
createSurfaceTextureArray(sources: readonly SurfaceSource[], options?: Parameters<Renderer['createSurfaceTexture']>[1]): SurfaceTextureHandle;
|
|
233
235
|
/**
|
|
234
236
|
* A baked lightmap page on the device, as the texture a `lightmapModel` material takes for its
|
|
235
|
-
* `modelMap`: two layers of
|
|
236
|
-
*
|
|
237
|
+
* `modelMap`: two layers of four bytes a texel, the irradiance as an rgb9e5 word and the
|
|
238
|
+
* direction, which the lit stage decodes and filters itself, clamped at the page's edges, with no
|
|
239
|
+
* mip chain. A page whose irradiance arrives packed uploads where it lies. Disposed as any texture is, with
|
|
237
240
|
* `disposeSurfaceTexture`; `updateSurfaceTexture` refuses it, as it refuses any array. See
|
|
238
241
|
* `lightmap.ts` for what a surface does with it.
|
|
239
242
|
*/
|
|
240
243
|
createLightmap(page: LightmapPage): SurfaceTextureHandle;
|
|
244
|
+
/**
|
|
245
|
+
* A texture the scene can be drawn into from a camera of the caller's (`captureScene`), which a
|
|
246
|
+
* material then shows like any image — most often as its `emissive`, for a screen in the world
|
|
247
|
+
* showing what a camera elsewhere sees. `width` and `height` in pixels, 1 to 4096. It holds
|
|
248
|
+
* radiance, at the colour format a probe takes: half floats under `hdrScene`, bytes otherwise.
|
|
249
|
+
* Disposed as any texture is; `updateSurfaceTexture` refuses it. See `sceneCapture.ts`.
|
|
250
|
+
*/
|
|
251
|
+
createSceneCapture(width: number, height: number): SurfaceTextureHandle;
|
|
252
|
+
/**
|
|
253
|
+
* Draw the scene into a capture from `camera`, at the moment a caller says, usually once a frame
|
|
254
|
+
* before the frame's own world. `draw` is handed the camera, its matrices updated for the
|
|
255
|
+
* capture's shape, and submits the scene exactly as it would to the screen — `bindMeshPass`,
|
|
256
|
+
* `drawMesh` and the rest; `bindMeshPass` the frame's own camera again afterwards. The output
|
|
257
|
+
* transform is held off, so a screen showing it is graded once, with the frame.
|
|
258
|
+
*
|
|
259
|
+
* **The mesh pass alone**, as a probe bake is: what a scene draws after its world is in the
|
|
260
|
+
* capture only if `draw` draws it, and no temporal resolve or effect after the world runs on it.
|
|
261
|
+
* Returns whether it drew: false for a texture that is not a capture.
|
|
262
|
+
*/
|
|
263
|
+
captureScene(capture: SurfaceTextureHandle, camera: Camera, clearColor: Vec3, draw: (camera: Camera) => void): boolean;
|
|
241
264
|
/**
|
|
242
265
|
* Replace a texture's pixels, keeping the GPU object and its sampler state.
|
|
243
266
|
*
|
|
@@ -444,6 +467,13 @@ export type RendererApi = Omit<{
|
|
|
444
467
|
}): ParticleHandle;
|
|
445
468
|
/** Draw a pool's live particles, after the opaque scene. */
|
|
446
469
|
drawParticles(batch: ParticleHandle, data: Parameters<Renderer['drawParticles']>[1], camera: Parameters<Renderer['drawParticles']>[2], env: Parameters<Renderer['drawParticles']>[3], timeSeconds: number): void;
|
|
470
|
+
/**
|
|
471
|
+
* Draw a pool's particles from a buffer a caller's own compute wrote (`registerCompute`), where
|
|
472
|
+
* they lie: the pool's material, blend, flipbook and fades, its instance stream the caller's
|
|
473
|
+
* buffer. WebGPU only; WebGL2 says so once and draws nothing. Not sorted. See `DeviceParticles`
|
|
474
|
+
* for the layout.
|
|
475
|
+
*/
|
|
476
|
+
drawDeviceParticles(batch: ParticleHandle, particles: DeviceParticles, camera: Parameters<Renderer['drawParticles']>[2], env: Parameters<Renderer['drawParticles']>[3], timeSeconds: number): void;
|
|
447
477
|
/** Release a particle pool. */
|
|
448
478
|
disposeParticles(batch: ParticleHandle): void;
|
|
449
479
|
/** Draw a wet film over geometry, using a handle as the surface it lies on. */
|
|
@@ -61,7 +61,7 @@ import type { Atmosphere } from '../../atmosphere.ts';
|
|
|
61
61
|
import { InstancedMesh } from '../../instancedMesh.ts';
|
|
62
62
|
import { ParticleBatch } from '../../particleBatch.ts';
|
|
63
63
|
import type { ParticleBatchOptions } from '../../particleBatch.ts';
|
|
64
|
-
import type { ParticleInstances } from '../../particlePool.ts';
|
|
64
|
+
import type { DeviceParticles, ParticleInstances } from '../../particlePool.ts';
|
|
65
65
|
import { BoltBatch } from '../../boltBatch.ts';
|
|
66
66
|
import type { BoltSegments } from '../../boltPool.ts';
|
|
67
67
|
import { LineBatch } from '../../lineBatch.ts';
|
|
@@ -198,6 +198,11 @@ export interface Environment extends Atmosphere {
|
|
|
198
198
|
lightDirections: Float32Array;
|
|
199
199
|
/** Two per active light: the cosine of the inner cone angle, then of the outer. */
|
|
200
200
|
lightConeCos: Float32Array;
|
|
201
|
+
/**
|
|
202
|
+
* One per active light: its own falloff exponent, or 0 for the frame's. Optional: absent is 0 for
|
|
203
|
+
* every light. See `PointLightSource.falloffExponent`.
|
|
204
|
+
*/
|
|
205
|
+
lightFalloffExponents?: Float32Array;
|
|
201
206
|
/** One per active light: a row of the photometric atlas, or −1 for none. */
|
|
202
207
|
lightIesProfiles: Float32Array;
|
|
203
208
|
/**
|
|
@@ -1231,6 +1236,15 @@ export declare class WebGL2Renderer implements RendererApi {
|
|
|
1231
1236
|
private warnedEnvironmentAmbient;
|
|
1232
1237
|
/** Whether a probe is being baked, so the passes that would recurse into one can tell. */
|
|
1233
1238
|
private probePassActive;
|
|
1239
|
+
/**
|
|
1240
|
+
* Whether a scene capture is being drawn (`captureScene`): an off-screen pass like a bake, so the
|
|
1241
|
+
* frame's own view, its refraction copy and skin's spread are left alone, but lit as the frame is.
|
|
1242
|
+
*/
|
|
1243
|
+
private capturePassActive;
|
|
1244
|
+
/** Each capture's framebuffer, beside the texture a material binds. See `createSceneCapture`. */
|
|
1245
|
+
private readonly captureTargets;
|
|
1246
|
+
/** Said once, where a driver refuses to draw into a capture. */
|
|
1247
|
+
private warnedCapture;
|
|
1234
1248
|
/** Whether the bake under way lights its faces by the grid. `ProbeBakeOptions.bounce`. */
|
|
1235
1249
|
private probeBounce;
|
|
1236
1250
|
/** The clip-control extension, or null where this context does not offer it. */
|
|
@@ -1833,6 +1847,21 @@ export declare class WebGL2Renderer implements RendererApi {
|
|
|
1833
1847
|
createSurfaceTextureArray(sources: readonly SurfaceSource[], options?: SurfaceTextureOptions): SurfaceTexture;
|
|
1834
1848
|
/** A baked lightmap page, as a `lightmapModel` material's `modelMap`. See `RendererApi`. */
|
|
1835
1849
|
createLightmap(page: LightmapPage): SurfaceTexture;
|
|
1850
|
+
/**
|
|
1851
|
+
* A texture the scene can be drawn into, for a material to show. See `RendererApi` and
|
|
1852
|
+
* `sceneCapture.ts`. Half floats where the frame keeps range, as a probe does.
|
|
1853
|
+
*/
|
|
1854
|
+
createSceneCapture(width: number, height: number): SurfaceTexture;
|
|
1855
|
+
/**
|
|
1856
|
+
* Draw the scene into a capture from `camera`: `draw` is handed the camera, its matrices updated
|
|
1857
|
+
* for the capture's shape, and submits the scene as it would to the screen. See `RendererApi`.
|
|
1858
|
+
*
|
|
1859
|
+
* **Radiance, as a probe bake stores it**: the output transform and exposure are held off for the
|
|
1860
|
+
* pass, so the frame grades a screen showing it once. No temporal jitter, which a capture has no
|
|
1861
|
+
* resolve to undo. Returns whether it drew: false for a texture that is not a capture, or one the
|
|
1862
|
+
* driver will not draw into.
|
|
1863
|
+
*/
|
|
1864
|
+
captureScene(capture: SurfaceTexture, camera: Camera, clearColor: Vec3, draw: (camera: Camera) => void): boolean;
|
|
1836
1865
|
/**
|
|
1837
1866
|
* Replace a surface texture's pixels, keeping the GPU object and its sampler state.
|
|
1838
1867
|
*
|
|
@@ -1963,18 +1992,6 @@ export declare class WebGL2Renderer implements RendererApi {
|
|
|
1963
1992
|
* program state, and this puts it back to what `currentSurfaceTexture` says it should be.
|
|
1964
1993
|
*/
|
|
1965
1994
|
private restoreSurfaceTextureUnit;
|
|
1966
|
-
/**
|
|
1967
|
-
* A pass-level scale over the grain the geometry itself declared, 0 to 1.
|
|
1968
|
-
*
|
|
1969
|
-
* Which surfaces are mineral is now `MeshData.grain`, stated per vertex through
|
|
1970
|
-
* `MeshBuilder.setGrain` — because it is a property of a material, and absent means none.
|
|
1971
|
-
* This stays as the override for the case that has no answer to state: an imported model
|
|
1972
|
-
* arrives with no grain information at all, and a caller drawing one decides for it.
|
|
1973
|
-
*
|
|
1974
|
-
* Pass state, like `setSurfaceTexture`, because a material covers many draws. The default
|
|
1975
|
-
* is 1 and `bindMeshPass` restores it, so it scales geometry that declared grain and
|
|
1976
|
-
* leaves geometry that did not exactly as it is.
|
|
1977
|
-
*/
|
|
1978
1995
|
/**
|
|
1979
1996
|
* The ambient the following draws take, as nine spherical-harmonic coefficients of incoming
|
|
1980
1997
|
* radiance — red, green and blue of each, twenty-seven numbers — or `null` for the frame's own:
|
|
@@ -1986,6 +2003,7 @@ export declare class WebGL2Renderer implements RendererApi {
|
|
|
1986
2003
|
* only — a glossy surface still reflects the probes — and it is pass state like the material,
|
|
1987
2004
|
* which `bindMeshPass` clears, so a mirror or a probe bake drawn after does not inherit it.
|
|
1988
2005
|
*/
|
|
2006
|
+
setAmbientSH(coefficients: ArrayLike<number> | null): void;
|
|
1989
2007
|
/**
|
|
1990
2008
|
* How much of the environment the following draws mirror, 0 to 1.
|
|
1991
2009
|
*
|
|
@@ -1996,7 +2014,6 @@ export declare class WebGL2Renderer implements RendererApi {
|
|
|
1996
2014
|
* Defaults to zero and bindMeshPass restores it, so a scene that never calls this looks
|
|
1997
2015
|
* exactly as it did.
|
|
1998
2016
|
*/
|
|
1999
|
-
setAmbientSH(coefficients: ArrayLike<number> | null): void;
|
|
2000
2017
|
setSurfaceReflectivity(amount: number): void;
|
|
2001
2018
|
/**
|
|
2002
2019
|
* How bright the environment the surfaces drawn next reflect is. 1 is the default and identity.
|
|
@@ -2026,6 +2043,18 @@ export declare class WebGL2Renderer implements RendererApi {
|
|
|
2026
2043
|
* a coordinated release is happening anyway.
|
|
2027
2044
|
*/
|
|
2028
2045
|
setEnvironmentAmbient(_amount: number): void;
|
|
2046
|
+
/**
|
|
2047
|
+
* A pass-level scale over the grain the geometry itself declared, 0 to 1.
|
|
2048
|
+
*
|
|
2049
|
+
* Which surfaces are mineral is now `MeshData.grain`, stated per vertex through
|
|
2050
|
+
* `MeshBuilder.setGrain` — because it is a property of a material, and absent means none.
|
|
2051
|
+
* This stays as the override for the case that has no answer to state: an imported model
|
|
2052
|
+
* arrives with no grain information at all, and a caller drawing one decides for it.
|
|
2053
|
+
*
|
|
2054
|
+
* Pass state, like `setSurfaceTexture`, because a material covers many draws. The default
|
|
2055
|
+
* is 1 and `bindMeshPass` restores it, so it scales geometry that declared grain and
|
|
2056
|
+
* leaves geometry that did not exactly as it is.
|
|
2057
|
+
*/
|
|
2029
2058
|
setSurfaceGrain(amount: number): void;
|
|
2030
2059
|
/**
|
|
2031
2060
|
* Whether the surfaces drawn next meet the medium: distance fog and the global medium's haze.
|
|
@@ -2361,6 +2390,13 @@ export declare class WebGL2Renderer implements RendererApi {
|
|
|
2361
2390
|
* emitters; it is a material that knows what a particle is.
|
|
2362
2391
|
*/
|
|
2363
2392
|
createParticles(capacity: number, options: ParticleBatchOptions): ParticleBatch;
|
|
2393
|
+
/**
|
|
2394
|
+
* Particles a caller's own compute wrote: WebGPU's alone, since this backend has no compute stage
|
|
2395
|
+
* to have written them (`computeSupported`). Said once, and nothing is drawn.
|
|
2396
|
+
*/
|
|
2397
|
+
drawDeviceParticles(_batch: ParticleBatch, _particles: DeviceParticles, _camera: Camera, _env: Environment, _timeSeconds: number): void;
|
|
2398
|
+
/** Said once: see `drawDeviceParticles`. */
|
|
2399
|
+
private warnedDeviceParticles;
|
|
2364
2400
|
/**
|
|
2365
2401
|
* Draw a live particle pool.
|
|
2366
2402
|
*
|