@driftengine/core 4.2.1 → 4.4.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 +272 -0
- package/README.md +1 -1
- package/dist/cinematic/cameraPath.d.ts +53 -0
- package/dist/cinematic/cameraPath.js +118 -0
- package/dist/environment/daylight.d.ts +77 -0
- package/dist/environment/daylight.js +77 -0
- package/dist/geometry/meshConcat.d.ts +9 -0
- package/dist/geometry/meshConcat.js +101 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +14 -1
- package/dist/render/backend/createRenderer.d.ts +13 -1
- package/dist/render/backend/createRenderer.js +6 -5
- package/dist/render/backend/webgl2/renderer.d.ts +166 -1
- package/dist/render/backend/webgl2/renderer.js +424 -23
- package/dist/render/backend/webgpu/buffers.js +46 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +81 -3
- package/dist/render/backend/webgpu/depthPass.js +75 -14
- package/dist/render/backend/webgpu/exposurePass.d.ts +39 -0
- package/dist/render/backend/webgpu/exposurePass.js +190 -0
- package/dist/render/backend/webgpu/fieldCompose.d.ts +11 -0
- package/dist/render/backend/webgpu/fieldCompose.js +13 -0
- package/dist/render/backend/webgpu/flatPass.d.ts +3 -1
- package/dist/render/backend/webgpu/flatPass.js +12 -5
- package/dist/render/backend/webgpu/particlePass.d.ts +8 -0
- package/dist/render/backend/webgpu/particlePass.js +1 -0
- package/dist/render/backend/webgpu/postPass.d.ts +12 -2
- package/dist/render/backend/webgpu/probeBake.d.ts +59 -3
- package/dist/render/backend/webgpu/probeBake.js +97 -7
- package/dist/render/backend/webgpu/probeTargets.d.ts +65 -0
- package/dist/render/backend/webgpu/probeTargets.js +180 -0
- package/dist/render/backend/webgpu/renderer.d.ts +176 -11
- package/dist/render/backend/webgpu/renderer.js +680 -250
- package/dist/render/backend/webgpu/scatterPass.js +7 -7
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
- package/dist/render/backend/webgpu/skinPaletteRing.js +9 -0
- package/dist/render/backend/webgpu/skyPass.js +5 -1
- package/dist/render/backend/webgpu/uniformRing.d.ts +31 -1
- package/dist/render/backend/webgpu/uniformRing.js +53 -3
- package/dist/render/bloomChain.d.ts +6 -0
- package/dist/render/bloomChain.js +8 -0
- package/dist/render/clusteredLights.d.ts +19 -11
- package/dist/render/clusteredLights.js +96 -45
- package/dist/render/cutoutCaster.d.ts +23 -0
- package/dist/render/cutoutCaster.js +20 -0
- package/dist/render/driftLight/bake.d.ts +34 -0
- package/dist/render/driftLight/bake.js +95 -0
- package/dist/render/driftLight/falloff.d.ts +16 -0
- package/dist/render/driftLight/falloff.js +23 -0
- package/dist/render/driftLight/layout.d.ts +59 -0
- package/dist/render/driftLight/layout.js +138 -0
- package/dist/render/driftLight/lightField.d.ts +108 -0
- package/dist/render/driftLight/lightField.js +179 -0
- package/dist/render/driftLight/uniforms.d.ts +28 -0
- package/dist/render/driftLight/uniforms.js +41 -0
- package/dist/render/driftLight/visibility.d.ts +18 -0
- package/dist/render/driftLight/visibility.js +47 -0
- package/dist/render/emptyTexture.d.ts +6 -0
- package/dist/render/emptyTexture.js +19 -0
- package/dist/render/exposurePass.d.ts +48 -0
- package/dist/render/exposurePass.js +172 -0
- package/dist/render/flameLight.d.ts +71 -0
- package/dist/render/flameLight.js +63 -0
- package/dist/render/gi/bounceLights.d.ts +34 -0
- package/dist/render/gi/bounceLights.js +66 -0
- package/dist/render/gi/fieldReach.d.ts +12 -0
- package/dist/render/gi/fieldReach.js +62 -0
- package/dist/render/gi/globalField.d.ts +8 -0
- package/dist/render/gi/globalField.js +31 -0
- package/dist/render/gi/probeTrace.d.ts +3 -1
- package/dist/render/gi/probeTrace.js +3 -1
- package/dist/render/gpuCapability.js +19 -4
- package/dist/render/lightBudget.d.ts +11 -0
- package/dist/render/lightBudget.js +11 -0
- package/dist/render/pointLightSelection.d.ts +16 -0
- package/dist/render/pointLightSelection.js +178 -83
- package/dist/render/probeGrid.d.ts +11 -1
- package/dist/render/probeGrid.js +5 -2
- package/dist/render/probeSweeps.d.ts +45 -0
- package/dist/render/probeSweeps.js +77 -0
- package/dist/render/reflectionProbe.d.ts +43 -1
- package/dist/render/reflectionProbe.js +17 -3
- package/dist/render/renderQuality.d.ts +3 -1
- package/dist/render/rendererHarness.d.ts +9 -0
- package/dist/render/rendererHarness.js +18 -3
- package/dist/render/sceneTarget.d.ts +20 -0
- package/dist/render/sceneTarget.js +62 -1
- package/dist/render/shaders/agx.d.ts +31 -0
- package/dist/render/shaders/agx.js +81 -0
- package/dist/render/shaders/ambientOcclusion.d.ts +24 -5
- package/dist/render/shaders/ambientOcclusion.js +120 -63
- package/dist/render/shaders/cutoutCoverage.d.ts +31 -0
- package/dist/render/shaders/cutoutCoverage.js +40 -0
- package/dist/render/shaders/depth.d.ts +25 -0
- package/dist/render/shaders/depth.js +69 -3
- package/dist/render/shaders/exposure.d.ts +52 -0
- package/dist/render/shaders/exposure.js +124 -0
- package/dist/render/shaders/filmLook.d.ts +47 -0
- package/dist/render/shaders/filmLook.js +98 -0
- package/dist/render/shaders/flat/directionalShadow.js +35 -4
- package/dist/render/shaders/flat/driftLight.d.ts +29 -0
- package/dist/render/shaders/flat/driftLight.js +75 -0
- package/dist/render/shaders/flat/index.js +5 -0
- package/dist/render/shaders/flat/lobes.js +13 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +68 -9
- package/dist/render/shaders/flat/preamble.js +23 -5
- package/dist/render/shaders/flat/probeGrid.js +46 -3
- package/dist/render/shaders/generated/ambientOcclusion.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/ambientOcclusion.wgsl.js +1 -1
- package/dist/render/shaders/generated/depth.wgsl.d.ts +100 -0
- package/dist/render/shaders/generated/depth.wgsl.js +100 -0
- package/dist/render/shaders/generated/exposure.wgsl.d.ts +42 -0
- package/dist/render/shaders/generated/exposure.wgsl.js +48 -0
- package/dist/render/shaders/generated/flat.wgsl.d.ts +1800 -1344
- package/dist/render/shaders/generated/flat.wgsl.js +1816 -1360
- package/dist/render/shaders/generated/localExposure.wgsl.d.ts +18 -0
- package/dist/render/shaders/generated/localExposure.wgsl.js +24 -0
- package/dist/render/shaders/generated/rush.wgsl.d.ts +40 -10
- package/dist/render/shaders/generated/rush.wgsl.js +40 -10
- package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +1 -1
- package/dist/render/shaders/gi/driftLight.wgsl.d.ts +16 -0
- package/dist/render/shaders/gi/driftLight.wgsl.js +49 -0
- package/dist/render/shaders/gi/probeBake.wgsl.d.ts +29 -4
- package/dist/render/shaders/gi/probeBake.wgsl.js +190 -20
- package/dist/render/shaders/globalMedium.js +4 -0
- package/dist/render/shaders/localExposure.d.ts +35 -0
- package/dist/render/shaders/localExposure.js +138 -0
- package/dist/render/shaders/prefilter.d.ts +1 -1
- package/dist/render/shaders/prefilter.js +6 -0
- package/dist/render/shaders/rush.js +33 -5
- package/dist/render/shaders/tangentFrame.d.ts +1 -1
- package/dist/render/shaders/tangentFrame.js +15 -3
- package/dist/render/shaders/temporalResolve.js +39 -1
- package/dist/render/shadowCasters.d.ts +5 -3
- package/dist/render/shadowMap.js +13 -0
- package/dist/render/surfaceTexture.d.ts +5 -0
- package/package.json +6 -6
- package/scripts/gpuCompute.mjs +24 -3
- package/scripts/png.mjs +23 -12
- package/src/cinematic/cameraPath.ts +178 -0
- package/src/environment/daylight.ts +152 -0
- package/src/geometry/meshConcat.ts +100 -0
- package/src/index.ts +32 -0
- package/src/render/backend/createRenderer.ts +22 -6
- package/src/render/backend/webgl2/renderer.ts +462 -20
- package/src/render/backend/webgpu/buffers.ts +51 -8
- package/src/render/backend/webgpu/depthPass.ts +78 -10
- package/src/render/backend/webgpu/exposurePass.ts +234 -0
- package/src/render/backend/webgpu/fieldCompose.ts +15 -0
- package/src/render/backend/webgpu/flatPass.ts +10 -2
- package/src/render/backend/webgpu/particlePass.ts +9 -0
- package/src/render/backend/webgpu/probeBake.ts +143 -9
- package/src/render/backend/webgpu/probeTargets.ts +211 -0
- package/src/render/backend/webgpu/renderer.ts +807 -271
- package/src/render/backend/webgpu/scatterPass.ts +7 -7
- package/src/render/backend/webgpu/skinPaletteRing.ts +10 -0
- package/src/render/backend/webgpu/skyPass.ts +5 -1
- package/src/render/backend/webgpu/uniformRing.ts +49 -3
- package/src/render/bloomChain.ts +9 -0
- package/src/render/clusteredLights.ts +108 -63
- package/src/render/cutoutCaster.ts +44 -0
- package/src/render/driftLight/bake.ts +125 -0
- package/src/render/driftLight/falloff.ts +26 -0
- package/src/render/driftLight/layout.ts +177 -0
- package/src/render/driftLight/lightField.ts +227 -0
- package/src/render/driftLight/uniforms.ts +61 -0
- package/src/render/driftLight/visibility.ts +58 -0
- package/src/render/emptyTexture.ts +41 -0
- package/src/render/exposurePass.ts +186 -0
- package/src/render/flameLight.ts +135 -0
- package/src/render/gi/bounceLights.ts +68 -0
- package/src/render/gi/fieldReach.ts +74 -0
- package/src/render/gi/globalField.ts +39 -0
- package/src/render/gi/probeTrace.ts +3 -1
- package/src/render/gpuCapability.ts +18 -5
- package/src/render/lightBudget.ts +12 -0
- package/src/render/pointLightSelection.ts +191 -79
- package/src/render/probeGrid.ts +13 -2
- package/src/render/probeSweeps.ts +80 -0
- package/src/render/reflectionProbe.ts +54 -2
- package/src/render/renderQuality.ts +3 -1
- package/src/render/rendererHarness.ts +25 -3
- package/src/render/sceneTarget.ts +75 -1
- package/src/render/shaders/ambientOcclusion.ts +125 -63
- package/src/render/shaders/cutoutCoverage.ts +43 -0
- package/src/render/shaders/depth.ts +80 -3
- package/src/render/shaders/exposure.ts +128 -0
- package/src/render/shaders/filmLook.ts +111 -0
- package/src/render/shaders/flat/directionalShadow.ts +35 -4
- package/src/render/shaders/flat/driftLight.ts +75 -0
- package/src/render/shaders/flat/index.ts +5 -0
- package/src/render/shaders/flat/lobes.ts +13 -0
- package/src/render/shaders/flat/main.ts +68 -9
- package/src/render/shaders/flat/preamble.ts +23 -5
- package/src/render/shaders/flat/probeGrid.ts +46 -3
- package/src/render/shaders/generated/ambientOcclusion.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +103 -0
- package/src/render/shaders/generated/exposure.wgsl.ts +51 -0
- package/src/render/shaders/generated/flat.wgsl.ts +1816 -1360
- package/src/render/shaders/generated/localExposure.wgsl.ts +26 -0
- package/src/render/shaders/generated/rush.wgsl.ts +40 -10
- package/src/render/shaders/generated/temporalResolve.wgsl.ts +1 -1
- package/src/render/shaders/gi/driftLight.wgsl.ts +49 -0
- package/src/render/shaders/gi/probeBake.wgsl.ts +191 -20
- package/src/render/shaders/globalMedium.ts +4 -0
- package/src/render/shaders/localExposure.ts +154 -0
- package/src/render/shaders/prefilter.ts +6 -0
- package/src/render/shaders/rush.ts +33 -5
- package/src/render/shaders/tangentFrame.ts +15 -3
- package/src/render/shaders/temporalResolve.ts +39 -1
- package/src/render/shadowCasters.ts +5 -3
- package/src/render/shadowMap.ts +14 -0
- package/src/render/surfaceTexture.ts +5 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Sort and check the keys. Throws at construction, so a bad palette never reaches a frame. */
|
|
2
|
+
export function createDaylightPalette(keys) {
|
|
3
|
+
if (keys.length === 0)
|
|
4
|
+
throw new Error('a daylight palette needs at least one key');
|
|
5
|
+
const sorted = [...keys].sort((a, b) => a.at - b.at);
|
|
6
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
7
|
+
const current = sorted[i];
|
|
8
|
+
if (!(current.exposure > 0)) {
|
|
9
|
+
throw new Error(`the key at ${current.at} has exposure ${current.exposure}; it must be > 0`);
|
|
10
|
+
}
|
|
11
|
+
if (i > 0 && sorted[i - 1].at === current.at) {
|
|
12
|
+
throw new Error(`a daylight palette has two keys at ${current.at}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return { keys: sorted };
|
|
16
|
+
}
|
|
17
|
+
export function createDaylightState() {
|
|
18
|
+
return {
|
|
19
|
+
sunColor: [0, 0, 0],
|
|
20
|
+
moonColor: [0, 0, 0],
|
|
21
|
+
skyTop: [0, 0, 0],
|
|
22
|
+
skyHorizon: [0, 0, 0],
|
|
23
|
+
skyDeep: [0, 0, 0],
|
|
24
|
+
ambient: [0, 0, 0],
|
|
25
|
+
ambientGround: [0, 0, 0],
|
|
26
|
+
fogColor: [0, 0, 0],
|
|
27
|
+
fogDensity: 0,
|
|
28
|
+
shadowStrength: 0,
|
|
29
|
+
emissiveGain: 0,
|
|
30
|
+
exposure: 1,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function blendInto(out, a, b, t) {
|
|
34
|
+
out[0] = a[0] + (b[0] - a[0]) * t;
|
|
35
|
+
out[1] = a[1] + (b[1] - a[1]) * t;
|
|
36
|
+
out[2] = a[2] + (b[2] - a[2]) * t;
|
|
37
|
+
}
|
|
38
|
+
/** The palette at `at`, into `out`. Past either end the nearest key holds. */
|
|
39
|
+
export function resolveDaylight(at, palette, out) {
|
|
40
|
+
const keys = palette.keys;
|
|
41
|
+
let upper = 0;
|
|
42
|
+
while (upper < keys.length && keys[upper].at < at)
|
|
43
|
+
upper++;
|
|
44
|
+
const b = keys[Math.min(upper, keys.length - 1)];
|
|
45
|
+
const a = keys[Math.max(upper - 1, 0)];
|
|
46
|
+
const t = a === b ? 0 : (at - a.at) / (b.at - a.at);
|
|
47
|
+
blendInto(out.sunColor, a.sunColor, b.sunColor, t);
|
|
48
|
+
blendInto(out.moonColor, a.moonColor, b.moonColor, t);
|
|
49
|
+
blendInto(out.skyTop, a.skyTop, b.skyTop, t);
|
|
50
|
+
blendInto(out.skyHorizon, a.skyHorizon, b.skyHorizon, t);
|
|
51
|
+
blendInto(out.skyDeep, a.skyDeep, b.skyDeep, t);
|
|
52
|
+
blendInto(out.ambient, a.ambient, b.ambient, t);
|
|
53
|
+
blendInto(out.ambientGround, a.ambientGround, b.ambientGround, t);
|
|
54
|
+
blendInto(out.fogColor, a.fogColor, b.fogColor, t);
|
|
55
|
+
out.fogDensity = a.fogDensity + (b.fogDensity - a.fogDensity) * t;
|
|
56
|
+
out.shadowStrength = a.shadowStrength + (b.shadowStrength - a.shadowStrength) * t;
|
|
57
|
+
out.emissiveGain = a.emissiveGain + (b.emissiveGain - a.emissiveGain) * t;
|
|
58
|
+
out.exposure = t === 0 ? a.exposure : a.exposure * (b.exposure / a.exposure) ** t;
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* `current` moved toward `target` over `dtSec`, closing half the distance in stops every
|
|
63
|
+
* `halfLifeSec`.
|
|
64
|
+
*
|
|
65
|
+
* **In time, not per frame**, so a 144 Hz display adapts exactly as fast as a 60 Hz one: the
|
|
66
|
+
* remaining distance after any number of steps is `2^(−elapsed / halfLife)` of what it was, however
|
|
67
|
+
* the elapsed time was cut up. A half-life of zero is a cut to the target. Both exposures must be
|
|
68
|
+
* positive, which is what an exposure is.
|
|
69
|
+
*/
|
|
70
|
+
export function easeExposure(current, target, dtSec, halfLifeSec) {
|
|
71
|
+
if (halfLifeSec <= 0)
|
|
72
|
+
return target;
|
|
73
|
+
if (dtSec <= 0)
|
|
74
|
+
return current;
|
|
75
|
+
const closed = 1 - 2 ** (-dtSec / halfLifeSec);
|
|
76
|
+
return current * (target / current) ** closed;
|
|
77
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MeshData } from '../render/mesh.ts';
|
|
2
|
+
/**
|
|
3
|
+
* `mesh` scaled uniformly and then moved by `x, y, z`. The same object when the fit is the
|
|
4
|
+
* identity; otherwise a copy of the positions and every other attribute shared, since a uniform
|
|
5
|
+
* scale turns no normal. Morph deltas are the caller's to scale.
|
|
6
|
+
*/
|
|
7
|
+
export declare function placeMesh(mesh: MeshData, x: number, y: number, z: number, scale?: number): MeshData;
|
|
8
|
+
/** `meshes` as one, in order, each member's indices moved past the vertices before it. */
|
|
9
|
+
export declare function concatMeshes(meshes: readonly MeshData[]): MeshData;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meshes moved and joined as typed arrays: the loader's fast path, with no builder in between.
|
|
3
|
+
*
|
|
4
|
+
* **`MeshBuilder` is for building geometry, and a loader was using it to copy geometry.** It
|
|
5
|
+
* pushes every vertex one number at a time into growable arrays, and it carries the attributes a
|
|
6
|
+
* procedural mesh has. Streaming a bought courtyard spent seven seconds of its main thread there,
|
|
7
|
+
* copying each part twice, once to upload it and once into its merge group. Worse, the builder has
|
|
8
|
+
* no tangent channel, so every normal-mapped part lost the frame its file carried and the shader
|
|
9
|
+
* fell back to derivatives.
|
|
10
|
+
*
|
|
11
|
+
* So `placeMesh` moves a mesh by a fit, or hands it back untouched when the fit is the identity,
|
|
12
|
+
* and `concatMeshes` joins a group once, into arrays sized in advance. An attribute one member
|
|
13
|
+
* lacks is filled with the value a mesh without it draws with (`ABSENT_ATTRIBUTE`). One no member
|
|
14
|
+
* carries is left out, as absent rather than invented.
|
|
15
|
+
*/
|
|
16
|
+
import { ABSENT_ATTRIBUTE } from '../render/vertexDefaults.js';
|
|
17
|
+
/** The optional per-vertex attributes, with how many floats a vertex each carries. */
|
|
18
|
+
const OPTIONAL = [
|
|
19
|
+
['specular', 1],
|
|
20
|
+
['tangents', 4],
|
|
21
|
+
['uvs', 2],
|
|
22
|
+
['emissiveColor', 3],
|
|
23
|
+
['roughness', 1],
|
|
24
|
+
['grain', 1],
|
|
25
|
+
['relief', 1],
|
|
26
|
+
['channel', 4],
|
|
27
|
+
['joints', 4],
|
|
28
|
+
['weights', 4],
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* `mesh` scaled uniformly and then moved by `x, y, z`. The same object when the fit is the
|
|
32
|
+
* identity; otherwise a copy of the positions and every other attribute shared, since a uniform
|
|
33
|
+
* scale turns no normal. Morph deltas are the caller's to scale.
|
|
34
|
+
*/
|
|
35
|
+
export function placeMesh(mesh, x, y, z, scale = 1) {
|
|
36
|
+
if (x === 0 && y === 0 && z === 0 && scale === 1)
|
|
37
|
+
return mesh;
|
|
38
|
+
const from = mesh.positions;
|
|
39
|
+
const positions = new Float32Array(from.length);
|
|
40
|
+
for (let i = 0; i + 2 < from.length; i += 3) {
|
|
41
|
+
positions[i] = from[i] * scale + x;
|
|
42
|
+
positions[i + 1] = from[i + 1] * scale + y;
|
|
43
|
+
positions[i + 2] = from[i + 2] * scale + z;
|
|
44
|
+
}
|
|
45
|
+
return { ...mesh, positions };
|
|
46
|
+
}
|
|
47
|
+
/** `meshes` as one, in order, each member's indices moved past the vertices before it. */
|
|
48
|
+
export function concatMeshes(meshes) {
|
|
49
|
+
const only = meshes[0];
|
|
50
|
+
if (meshes.length === 1 && only !== undefined)
|
|
51
|
+
return only;
|
|
52
|
+
let vertices = 0;
|
|
53
|
+
let indexCount = 0;
|
|
54
|
+
for (const mesh of meshes) {
|
|
55
|
+
vertices += mesh.positions.length / 3;
|
|
56
|
+
indexCount += mesh.indices.length;
|
|
57
|
+
}
|
|
58
|
+
const out = {
|
|
59
|
+
positions: new Float32Array(vertices * 3),
|
|
60
|
+
normals: new Float32Array(vertices * 3),
|
|
61
|
+
colors: new Float32Array(vertices * 3),
|
|
62
|
+
emissive: new Float32Array(vertices),
|
|
63
|
+
indices: new Uint32Array(indexCount),
|
|
64
|
+
};
|
|
65
|
+
const optional = out;
|
|
66
|
+
for (const [key, width] of OPTIONAL) {
|
|
67
|
+
if (meshes.some((mesh) => mesh[key] !== undefined)) {
|
|
68
|
+
optional[key] = new Float32Array(vertices * width);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
let vertex = 0;
|
|
72
|
+
let index = 0;
|
|
73
|
+
for (const mesh of meshes) {
|
|
74
|
+
const count = mesh.positions.length / 3;
|
|
75
|
+
out.positions.set(mesh.positions, vertex * 3);
|
|
76
|
+
out.normals.set(mesh.normals, vertex * 3);
|
|
77
|
+
out.colors.set(mesh.colors, vertex * 3);
|
|
78
|
+
out.emissive.set(mesh.emissive, vertex);
|
|
79
|
+
for (const [key, width] of OPTIONAL) {
|
|
80
|
+
const target = optional[key];
|
|
81
|
+
if (target === undefined)
|
|
82
|
+
continue;
|
|
83
|
+
const source = mesh[key];
|
|
84
|
+
if (source !== undefined) {
|
|
85
|
+
target.set(source, vertex * width);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const fill = ABSENT_ATTRIBUTE[key] ?? [];
|
|
89
|
+
for (let v = 0; v < count; v++) {
|
|
90
|
+
for (let c = 0; c < width; c++)
|
|
91
|
+
target[(vertex + v) * width + c] = fill[c] ?? 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const from = mesh.indices;
|
|
95
|
+
for (let i = 0; i < from.length; i++)
|
|
96
|
+
out.indices[index + i] = from[i] + vertex;
|
|
97
|
+
vertex += count;
|
|
98
|
+
index += from.length;
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -28,12 +28,16 @@ export { OnceSet } from './core/onceSet.ts';
|
|
|
28
28
|
export { MAX_TIME_CURVE_AMOUNT, curveOffsetSec, curveSpanSec, linearCurve, timeCurve, } from './core/timeCurve.ts';
|
|
29
29
|
export type { TimeCurve, TimeCurveKind, TimeCurveOptions } from './core/timeCurve.ts';
|
|
30
30
|
export { CinematicPlayer } from './cinematic/player.ts';
|
|
31
|
+
export { createCameraPath, createCameraPathSample, sampleCameraPath, } from './cinematic/cameraPath.ts';
|
|
32
|
+
export type { CameraPath, CameraPathKey, CameraPathOptions, CameraPathSample, } from './cinematic/cameraPath.ts';
|
|
31
33
|
export { defineCinematic, validateCinematic } from './cinematic/script.ts';
|
|
32
34
|
export type { CameraKeyframe, CinematicLine, CinematicScript, CinematicShot, } from './cinematic/script.ts';
|
|
33
35
|
export { MessageQueue } from './core/messageQueue.ts';
|
|
34
36
|
export type { MessageQueueOptions, QueuedMessage } from './core/messageQueue.ts';
|
|
35
37
|
export { celestialStateAt, createCelestialState, moonIllumination, } from './environment/celestialClock.ts';
|
|
36
38
|
export type { CelestialSite, CelestialState } from './environment/celestialClock.ts';
|
|
39
|
+
export { createDaylightPalette, createDaylightState, easeExposure, resolveDaylight, } from './environment/daylight.ts';
|
|
40
|
+
export type { DaylightKey, DaylightPalette, DaylightState } from './environment/daylight.ts';
|
|
37
41
|
export { TAU, DEG_TO_RAD, clamp, lerp, smoothstep, damp, dampTracking, angleDelta, dampAngle, wrapAngle, lerpAngle, } from './math/scalar.ts';
|
|
38
42
|
export { hslToRgb, mixColor, mixColorInto, scaleColor } from './math/color.ts';
|
|
39
43
|
export type { Vec3 } from './math/color.ts';
|
|
@@ -72,7 +76,7 @@ export type { OcclusionOptions } from './render/occlusion.ts';
|
|
|
72
76
|
export { OcclusionBuffer } from './render/occlusion.ts';
|
|
73
77
|
export type { ComputeContext, ComputeDefinition, ComputeDevice, ComputeHandle, } from './render/compute.ts';
|
|
74
78
|
export { createRenderer } from './render/backend/createRenderer.ts';
|
|
75
|
-
export type { CreatedRenderer, CreateRendererOptions, RenderPipeline, } from './render/backend/createRenderer.ts';
|
|
79
|
+
export type { CreatedRenderer, CreateRendererOptions, QualityForBackend, RenderPipeline, } from './render/backend/createRenderer.ts';
|
|
76
80
|
export { GPU_DRIVEN_LISTS, GpuDrivenPass, MATERIAL_FLOATS, VERTEX_FLOATS, } from './render/backend/webgpu/gpuDrivenPass.ts';
|
|
77
81
|
export type { GpuDrivenList, GpuDrivenMaterial, GpuDrivenShadowOptions, GpuDrivenView, } from './render/backend/webgpu/gpuDrivenPass.ts';
|
|
78
82
|
export { atmosphereFog, createFogTarget } from './render/fog.ts';
|
|
@@ -113,6 +117,8 @@ export { GI_SOURCE_FIELD, GI_SOURCE_PROBES, GI_SOURCE_SCREEN, newIndirectResult,
|
|
|
113
117
|
export type { GiResources, GiSource, IndirectRay, IndirectResult } from './render/gi/chain.ts';
|
|
114
118
|
export { GLOBAL_FIELD_BLEND, composeGlobalField, createGlobalField, sampleGlobalField, } from './render/gi/globalField.ts';
|
|
115
119
|
export type { FieldSource, GlobalField, GlobalFieldCascade, GlobalFieldInstance, } from './render/gi/globalField.ts';
|
|
120
|
+
export { FIELD_FADE_SEC, LightField } from './render/driftLight/lightField.ts';
|
|
121
|
+
export type { LightFieldOptions, LightFieldSource } from './render/driftLight/lightField.ts';
|
|
116
122
|
export { GI_SCREEN_MARCH, SCREEN_TRACE_BIAS_M, screenRayOrigin, traceScreen, } from './render/gi/traceScreen.ts';
|
|
117
123
|
export { FIELD_MARCH, coneRadiusAt, newFieldHit, traceField } from './render/gi/traceField.ts';
|
|
118
124
|
export type { FieldHit, FieldMarch } from './render/gi/traceField.ts';
|
|
@@ -189,6 +195,7 @@ export type { PrefilterQuality } from './render/prefilterEnvMap.ts';
|
|
|
189
195
|
export type { ProbeBakeOptions } from './render/reflectionProbe.ts';
|
|
190
196
|
export type { DirectionalShadowDepthLayers, OutputTransform, RenderQuality, RenderQualityOptions, ShadowFilterTaps, WaterReflectionFilterTaps, } from './render/renderQuality.ts';
|
|
191
197
|
export { MAX_POINT_LIGHTS, SURFACE_TEXTURE_UNIT } from './render/lightBudget.ts';
|
|
198
|
+
export { MAX_CLUSTERED_LIGHTS } from './render/clusteredLights.ts';
|
|
192
199
|
export { SurfaceTexture } from './render/surfaceTexture.ts';
|
|
193
200
|
export type { SurfaceMaterial, SurfaceTextureOptions } from './render/surfaceTexture.ts';
|
|
194
201
|
export { DEFAULT_GOVERNOR_LIMITS, ResolutionGovernor } from './render/resolutionGovernor.ts';
|
|
@@ -204,6 +211,8 @@ export { describeGpu } from './render/gpuCapability.ts';
|
|
|
204
211
|
export type { GpuIdentity, DescribeGpuOptions } from './render/gpuCapability.ts';
|
|
205
212
|
export { DEFAULT_POINT_LIGHT_VIEW_RANGE, createPointLightBuffer, selectPointLights, } from './render/pointLightSelection.ts';
|
|
206
213
|
export type { PointLightBuffer, PointLightSource } from './render/pointLightSelection.ts';
|
|
214
|
+
export { createFlame, flameFrequencyHz, updateFlame } from './render/flameLight.ts';
|
|
215
|
+
export type { Flame, FlameOptions } from './render/flameLight.ts';
|
|
207
216
|
export { computeLightMatrix } from './render/lightMatrix.ts';
|
|
208
217
|
export { PlumeRenderer } from './render/plumeRenderer.ts';
|
|
209
218
|
export { createEnvironment } from './render/backend/webgl2/renderer.ts';
|
|
@@ -224,6 +233,7 @@ export { SMOKE_FRAG } from './render/shaders/smoke.ts';
|
|
|
224
233
|
export { WaterRenderer } from './render/waterRenderer.ts';
|
|
225
234
|
export type { WaterBody, WaterBounds, WaterSettings } from './render/waterRenderer.ts';
|
|
226
235
|
export { MeshBuilder } from './geometry/meshBuilder.ts';
|
|
236
|
+
export { concatMeshes, placeMesh } from './geometry/meshConcat.ts';
|
|
227
237
|
export { generateTangents } from './geometry/tangents.ts';
|
|
228
238
|
export type { MeshBuildOptions } from './geometry/meshBuilder.ts';
|
|
229
239
|
export { Spline, createSplineSample } from './geometry/spline.ts';
|
|
@@ -331,7 +341,7 @@ export { BoltBatch } from './render/boltBatch.ts';
|
|
|
331
341
|
export { createLineSegments, setPolyline } from './render/linePoints.ts';
|
|
332
342
|
export type { LineSegments } from './render/linePoints.ts';
|
|
333
343
|
export { FlockRenderer } from './render/flockRenderer.ts';
|
|
334
|
-
export { DEFAULT_TEXT_STYLE, deviceSnappedCellSize, textHeightPx, textWidthPx, } from './render/textLayout.ts';
|
|
344
|
+
export { DEFAULT_TEXT_STYLE, deviceSnappedCellSize, MAX_CELLS as MAX_TEXT_CELLS, textHeightPx, textWidthPx, } from './render/textLayout.ts';
|
|
335
345
|
export type { TextStyle } from './render/textLayout.ts';
|
|
336
346
|
export { GLYPH_HEIGHT, GLYPH_SPACING, GLYPH_WIDTH, countCells, forEachCell, forEachRun, glyphRows, hasGlyph, measureText, } from './geometry/pixelFont.ts';
|
|
337
347
|
export { parseSdfFont } from './render/sdfFont.ts';
|
package/dist/index.js
CHANGED
|
@@ -30,9 +30,11 @@ export { PreferenceStore, loadPreferences, savePreferences } from './core/prefer
|
|
|
30
30
|
export { OnceSet } from './core/onceSet.js';
|
|
31
31
|
export { MAX_TIME_CURVE_AMOUNT, curveOffsetSec, curveSpanSec, linearCurve, timeCurve, } from './core/timeCurve.js';
|
|
32
32
|
export { CinematicPlayer } from './cinematic/player.js';
|
|
33
|
+
export { createCameraPath, createCameraPathSample, sampleCameraPath, } from './cinematic/cameraPath.js';
|
|
33
34
|
export { defineCinematic, validateCinematic } from './cinematic/script.js';
|
|
34
35
|
export { MessageQueue } from './core/messageQueue.js';
|
|
35
36
|
export { celestialStateAt, createCelestialState, moonIllumination, } from './environment/celestialClock.js';
|
|
37
|
+
export { createDaylightPalette, createDaylightState, easeExposure, resolveDaylight, } from './environment/daylight.js';
|
|
36
38
|
export { TAU, DEG_TO_RAD, clamp, lerp, smoothstep, damp, dampTracking, angleDelta, dampAngle, wrapAngle, lerpAngle, } from './math/scalar.js';
|
|
37
39
|
export { hslToRgb, mixColor, mixColorInto, scaleColor } from './math/color.js';
|
|
38
40
|
export { Camera } from './render/camera.js';
|
|
@@ -170,6 +172,7 @@ export { countSplatTiles, fillSplatTiles, splatPixelBox, splatTileGrid, splatTil
|
|
|
170
172
|
*/
|
|
171
173
|
export { GI_SOURCE_FIELD, GI_SOURCE_PROBES, GI_SOURCE_SCREEN, newIndirectResult, traceIndirect, } from './render/gi/chain.js';
|
|
172
174
|
export { GLOBAL_FIELD_BLEND, composeGlobalField, createGlobalField, sampleGlobalField, } from './render/gi/globalField.js';
|
|
175
|
+
export { FIELD_FADE_SEC, LightField } from './render/driftLight/lightField.js';
|
|
173
176
|
export { GI_SCREEN_MARCH, SCREEN_TRACE_BIAS_M, screenRayOrigin, traceScreen, } from './render/gi/traceScreen.js';
|
|
174
177
|
export { FIELD_MARCH, coneRadiusAt, newFieldHit, traceField } from './render/gi/traceField.js';
|
|
175
178
|
export { PROBE_VISIBILITY_SHARPNESS, bakeProbeVisibility, createProbeVisibility, probeUpdateSchedule, probeVisibilityWeight, sampleProbeVolume, visibleProbes, } from './render/gi/probeVolume.js';
|
|
@@ -244,6 +247,8 @@ export { MAX_AREA_LIGHTS, createAreaLightBuffer, selectAreaLights } from './rend
|
|
|
244
247
|
*/
|
|
245
248
|
export { areaShadowLayerCount, castingRange, firstAreaShadowLayer, } from './render/areaShadowSet.js';
|
|
246
249
|
export { MAX_POINT_LIGHTS, SURFACE_TEXTURE_UNIT } from './render/lightBudget.js';
|
|
250
|
+
/* The width a light buffer can usefully be with `clusteredLights` on; `createPointLightBuffer`. */
|
|
251
|
+
export { MAX_CLUSTERED_LIGHTS } from './render/clusteredLights.js';
|
|
247
252
|
export { SurfaceTexture } from './render/surfaceTexture.js';
|
|
248
253
|
export { DEFAULT_GOVERNOR_LIMITS, ResolutionGovernor } from './render/resolutionGovernor.js';
|
|
249
254
|
export { isWeakGpuFamily } from './render/gpuCapability.js';
|
|
@@ -255,6 +260,7 @@ export { isWeakGpuFamily } from './render/gpuCapability.js';
|
|
|
255
260
|
*/
|
|
256
261
|
export { describeGpu } from './render/gpuCapability.js';
|
|
257
262
|
export { DEFAULT_POINT_LIGHT_VIEW_RANGE, createPointLightBuffer, selectPointLights, } from './render/pointLightSelection.js';
|
|
263
|
+
export { createFlame, flameFrequencyHz, updateFlame } from './render/flameLight.js';
|
|
258
264
|
export { computeLightMatrix } from './render/lightMatrix.js';
|
|
259
265
|
export { PlumeRenderer } from './render/plumeRenderer.js';
|
|
260
266
|
export { createEnvironment } from './render/backend/webgl2/renderer.js';
|
|
@@ -292,6 +298,7 @@ export { ARCANE_FRAG } from './render/shaders/arcane.js';
|
|
|
292
298
|
export { SMOKE_FRAG } from './render/shaders/smoke.js';
|
|
293
299
|
export { WaterRenderer } from './render/waterRenderer.js';
|
|
294
300
|
export { MeshBuilder } from './geometry/meshBuilder.js';
|
|
301
|
+
export { concatMeshes, placeMesh } from './geometry/meshConcat.js';
|
|
295
302
|
/* A tangent frame, which every map in the material track reads. */
|
|
296
303
|
export { generateTangents } from './geometry/tangents.js';
|
|
297
304
|
export { Spline, createSplineSample } from './geometry/spline.js';
|
|
@@ -439,7 +446,13 @@ export { DEFAULT_TEXT_STYLE,
|
|
|
439
446
|
* the note at the cell upload in `render/textRenderer.ts`: snap once, then measure, lay out
|
|
440
447
|
* and draw with that one number.
|
|
441
448
|
*/
|
|
442
|
-
deviceSnappedCellSize,
|
|
449
|
+
deviceSnappedCellSize,
|
|
450
|
+
/*
|
|
451
|
+
* How many lit cells one text object draws before the rest of its string is cut. Exported so a
|
|
452
|
+
* caller laying out a runtime string, a readout that grows, can break it before the engine does:
|
|
453
|
+
* the cut is silent by design, since a clipped message beats a frame that does not render.
|
|
454
|
+
*/
|
|
455
|
+
MAX_CELLS as MAX_TEXT_CELLS, textHeightPx, textWidthPx, } from './render/textLayout.js';
|
|
443
456
|
export { GLYPH_HEIGHT, GLYPH_SPACING, GLYPH_WIDTH, countCells, forEachCell, forEachRun, glyphRows, hasGlyph, measureText, } from './geometry/pixelFont.js';
|
|
444
457
|
/*
|
|
445
458
|
* SDF text, reached the same way pixel text is: the verbs are on the renderer and the
|
|
@@ -34,6 +34,18 @@ export declare const DEFAULT_PIPELINE: RenderPipeline;
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function pipelineRefusal(pipeline: RenderPipeline, backend: RenderBackend, reason: string): string | null;
|
|
36
36
|
/** Everything about selection a caller may want to decide instead of inherit. */
|
|
37
|
+
/**
|
|
38
|
+
* The quality to build with, or a function of the backend `createRenderer` chose.
|
|
39
|
+
*
|
|
40
|
+
* **A function is how an option only one backend has is asked of that backend alone.** Traced
|
|
41
|
+
* indirect light and reconstruction are WebGPU's, and WebGL2 refuses either in words when handed
|
|
42
|
+
* one: right for a consumer who asked for it there, and noise for one who wanted it wherever it
|
|
43
|
+
* runs, since every device that fell back printed a refusal. Called once for the backend that
|
|
44
|
+
* draws, and once more for WebGPU's timing request where WebGPU is tried. What would make it wrong
|
|
45
|
+
* is a consumer needing to know *why* the backend fell back before choosing, which `reason` on the
|
|
46
|
+
* result says after the fact and nothing says before.
|
|
47
|
+
*/
|
|
48
|
+
export type QualityForBackend = RenderQualityOptions | ((backend: RenderBackend) => RenderQualityOptions);
|
|
37
49
|
export interface CreateRendererOptions {
|
|
38
50
|
/**
|
|
39
51
|
* Whether to try WebGPU at all. **Defaults to true**: WebGPU is the backend this engine is
|
|
@@ -189,4 +201,4 @@ export interface CreatedRenderer {
|
|
|
189
201
|
* returned and ignored by every caller for long enough that a silent fallback could be
|
|
190
202
|
* mistaken for a comparison.
|
|
191
203
|
*/
|
|
192
|
-
export declare function createRenderer(canvas: HTMLCanvasElement, quality?:
|
|
204
|
+
export declare function createRenderer(canvas: HTMLCanvasElement, quality?: QualityForBackend, options?: CreateRendererOptions): Promise<CreatedRenderer>;
|
|
@@ -72,6 +72,7 @@ function presentOnFirstFrame(renderer, splash) {
|
|
|
72
72
|
* mistaken for a comparison.
|
|
73
73
|
*/
|
|
74
74
|
export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
75
|
+
const qualityFor = (backend) => typeof quality === 'function' ? quality(backend) : quality;
|
|
75
76
|
const search = options.search ?? globalThis.location?.search ?? '';
|
|
76
77
|
/*
|
|
77
78
|
* **Mounted before the probe, because the probe is part of the wait.** `selectBackend` asks for
|
|
@@ -143,7 +144,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
143
144
|
forward step makes `spent` exceed the budget, so the engine falls back to WebGL2 reporting
|
|
144
145
|
"WebGPU stalled" about a device that was fine. */
|
|
145
146
|
const startedAt = performance.now();
|
|
146
|
-
const choice = await selectBackend(search, options.preferWebGpu ?? true,
|
|
147
|
+
const choice = await selectBackend(search, options.preferWebGpu ?? true, (options.preferWebGpu ?? true) ? (qualityFor('webgpu').gpuTiming ?? false) : false, options.probeShaders ?? [], budgetMs);
|
|
147
148
|
if (choice.backend === 'webgpu' && choice.device !== null) {
|
|
148
149
|
/*
|
|
149
150
|
* **A failure here falls back rather than propagating.** Everything up to this point
|
|
@@ -185,7 +186,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
185
186
|
if (settled === TIMED_OUT) {
|
|
186
187
|
device.destroy();
|
|
187
188
|
return built({
|
|
188
|
-
renderer: new Renderer(canvas,
|
|
189
|
+
renderer: new Renderer(canvas, qualityFor('webgl2')),
|
|
189
190
|
backend: 'webgl2',
|
|
190
191
|
reason: `WebGPU stalled while ${stage}, fell back after ${budgetMs} ms`,
|
|
191
192
|
});
|
|
@@ -204,7 +205,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
204
205
|
* resolves internally, so the two backends get the same numbers by construction rather
|
|
205
206
|
* than from a copied set of defaults somebody has to keep in step.
|
|
206
207
|
*/
|
|
207
|
-
renderer: new WebGPURenderer(surface, resolveRenderQuality(
|
|
208
|
+
renderer: new WebGPURenderer(surface, resolveRenderQuality(qualityFor('webgpu')),
|
|
208
209
|
/* The adapter's own words, so the capability clamp has a part number to
|
|
209
210
|
recognise rather than the literal string `WebGPU`. */
|
|
210
211
|
choice.rendererName ?? undefined),
|
|
@@ -216,7 +217,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
216
217
|
choice.device.destroy();
|
|
217
218
|
const detail = error instanceof Error ? error.message : String(error);
|
|
218
219
|
return built({
|
|
219
|
-
renderer: new Renderer(canvas,
|
|
220
|
+
renderer: new Renderer(canvas, qualityFor('webgl2')),
|
|
220
221
|
backend: 'webgl2',
|
|
221
222
|
reason: `WebGPU surface failed, fell back: ${detail}`,
|
|
222
223
|
});
|
|
@@ -243,7 +244,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
243
244
|
console.warn(`[driftengine] WebGPU was asked for and is not being used: ${choice.reason}`);
|
|
244
245
|
}
|
|
245
246
|
return built({
|
|
246
|
-
renderer: new Renderer(canvas,
|
|
247
|
+
renderer: new Renderer(canvas, qualityFor('webgl2')),
|
|
247
248
|
backend: 'webgl2',
|
|
248
249
|
reason: choice.reason,
|
|
249
250
|
});
|