@driftengine/capture 4.12.0 → 4.13.1
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/README.md +1 -1
- package/dist/gaussians/parameters.d.ts +12 -1
- package/dist/gaussians/parameters.js +38 -6
- package/package.json +7 -7
- package/src/gaussians/parameters.ts +39 -6
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
A video to a playable scene, on the player's own device — no service, no account, and a runtime
|
|
4
4
|
that never fetches.
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**73,103 bytes gzipped**, measured by `scripts/size-gate.test.mjs` against
|
|
7
7
|
`scripts/fixtures/size/capture-only.ts`. Optional: nothing in `@driftengine/core` imports it.
|
|
8
8
|
|
|
9
9
|
## What is here so far
|
|
@@ -31,5 +31,16 @@ export declare function clear(gradients: GaussianGradients, count: number): void
|
|
|
31
31
|
* what the refinement grows the busiest of.
|
|
32
32
|
*/
|
|
33
33
|
export declare function chain(cloud: Cloud, gradients: GaussianGradients): void;
|
|
34
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* The fitted cloud as a capture: single precision, cut to what it holds, and its colour as display
|
|
36
|
+
* values.
|
|
37
|
+
*
|
|
38
|
+
* **Encoded, because `SplatSource.colors` is a display value** — what every trained capture stores,
|
|
39
|
+
* since training fits photographs as they look — and the splat shader decodes it after the
|
|
40
|
+
* view-dependent term. The fit runs in linear light against decoded frames, so its colour goes out
|
|
41
|
+
* through the sRGB encode, which the shader's decode undoes exactly. The l=1 band is carried
|
|
42
|
+
* through the encode's slope at that colour, the first-order step: what it gives up is a sheen as
|
|
43
|
+
* large as the colour itself, which comes back a little off. What would make it wrong is a fit
|
|
44
|
+
* run in display values, which this one is not.
|
|
45
|
+
*/
|
|
35
46
|
export declare function harvest(cloud: Cloud): SplatSource;
|
|
@@ -145,21 +145,53 @@ export function chain(cloud, gradients) {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* The fitted cloud as a capture: single precision, cut to what it holds, and its colour as display
|
|
150
|
+
* values.
|
|
151
|
+
*
|
|
152
|
+
* **Encoded, because `SplatSource.colors` is a display value** — what every trained capture stores,
|
|
153
|
+
* since training fits photographs as they look — and the splat shader decodes it after the
|
|
154
|
+
* view-dependent term. The fit runs in linear light against decoded frames, so its colour goes out
|
|
155
|
+
* through the sRGB encode, which the shader's decode undoes exactly. The l=1 band is carried
|
|
156
|
+
* through the encode's slope at that colour, the first-order step: what it gives up is a sheen as
|
|
157
|
+
* large as the colour itself, which comes back a little off. What would make it wrong is a fit
|
|
158
|
+
* run in display values, which this one is not.
|
|
159
|
+
*/
|
|
149
160
|
export function harvest(cloud) {
|
|
150
161
|
const { count } = cloud;
|
|
162
|
+
const linear = cloud.colors.values;
|
|
163
|
+
const colors = new Float32Array(count * 3);
|
|
164
|
+
for (let i = 0; i < count * 3; i += 1)
|
|
165
|
+
colors[i] = encode(Math.max(0, linear[i]));
|
|
151
166
|
const source = {
|
|
152
167
|
count,
|
|
153
168
|
positions: Float32Array.from(cloud.positions.values.subarray(0, count * 3)),
|
|
154
169
|
scales: Float32Array.from(cloud.scales.subarray(0, count * 3)),
|
|
155
170
|
rotations: Float32Array.from(cloud.rotations.values.subarray(0, count * 4)),
|
|
156
|
-
colors
|
|
171
|
+
colors,
|
|
157
172
|
opacities: Float32Array.from(cloud.opacities.subarray(0, count)),
|
|
158
173
|
};
|
|
159
174
|
if (cloud.sh1 === null)
|
|
160
175
|
return source;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
176
|
+
const band = cloud.sh1.values;
|
|
177
|
+
const sh1 = new Float32Array(count * SH1_COEFFICIENTS);
|
|
178
|
+
/* Interleaved by basis and then by channel, so coefficient `k` carries channel `k % 3`. */
|
|
179
|
+
for (let at = 0; at < count; at += 1) {
|
|
180
|
+
for (let k = 0; k < SH1_COEFFICIENTS; k += 1) {
|
|
181
|
+
const slope = encodeSlope(Math.max(0, linear[at * 3 + (k % 3)]));
|
|
182
|
+
sh1[at * SH1_COEFFICIENTS + k] = band[at * SH1_COEFFICIENTS + k] * slope;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { ...source, sh1 };
|
|
186
|
+
}
|
|
187
|
+
/*
|
|
188
|
+
* The sRGB encode and its derivative, through the reproducible `exactExp` and `exactLog` the fit's
|
|
189
|
+
* other transforms use, so a capture fitted on two machines hands over the same colours.
|
|
190
|
+
*/
|
|
191
|
+
function encode(value) {
|
|
192
|
+
return value <= 0.0031308 ? value * 12.92 : 1.055 * exactExp(exactLog(value) / 2.4) - 0.055;
|
|
193
|
+
}
|
|
194
|
+
/** The encode's slope at `value`: 12.92 on its straight segment, and the curve's above it. */
|
|
195
|
+
function encodeSlope(value) {
|
|
196
|
+
return value <= 0.0031308 ? 12.92 : (1.055 / 2.4) * exactExp(exactLog(value) * (1 / 2.4 - 1));
|
|
165
197
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@driftengine/capture",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.1",
|
|
4
4
|
"description": "A video to a playable scene, on the player's device: the models it runs and the stages that use them",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
],
|
|
28
28
|
"sideEffects": false,
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@driftengine/core": "4.
|
|
31
|
-
"@driftengine/drft": "4.
|
|
32
|
-
"@driftengine/nav": "4.
|
|
33
|
-
"@driftengine/physics": "4.
|
|
34
|
-
"@driftengine/splats": "4.
|
|
35
|
-
"@driftengine/texture": "4.
|
|
30
|
+
"@driftengine/core": "4.13.1",
|
|
31
|
+
"@driftengine/drft": "4.13.1",
|
|
32
|
+
"@driftengine/nav": "4.13.1",
|
|
33
|
+
"@driftengine/physics": "4.13.1",
|
|
34
|
+
"@driftengine/splats": "4.13.1",
|
|
35
|
+
"@driftengine/texture": "4.13.1"
|
|
36
36
|
},
|
|
37
37
|
"author": "Drift Technologies",
|
|
38
38
|
"repository": {
|
|
@@ -167,20 +167,53 @@ export function chain(cloud: Cloud, gradients: GaussianGradients): void {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
/**
|
|
170
|
+
/**
|
|
171
|
+
* The fitted cloud as a capture: single precision, cut to what it holds, and its colour as display
|
|
172
|
+
* values.
|
|
173
|
+
*
|
|
174
|
+
* **Encoded, because `SplatSource.colors` is a display value** — what every trained capture stores,
|
|
175
|
+
* since training fits photographs as they look — and the splat shader decodes it after the
|
|
176
|
+
* view-dependent term. The fit runs in linear light against decoded frames, so its colour goes out
|
|
177
|
+
* through the sRGB encode, which the shader's decode undoes exactly. The l=1 band is carried
|
|
178
|
+
* through the encode's slope at that colour, the first-order step: what it gives up is a sheen as
|
|
179
|
+
* large as the colour itself, which comes back a little off. What would make it wrong is a fit
|
|
180
|
+
* run in display values, which this one is not.
|
|
181
|
+
*/
|
|
171
182
|
export function harvest(cloud: Cloud): SplatSource {
|
|
172
183
|
const { count } = cloud;
|
|
184
|
+
const linear = cloud.colors.values;
|
|
185
|
+
const colors = new Float32Array(count * 3);
|
|
186
|
+
for (let i = 0; i < count * 3; i += 1) colors[i] = encode(Math.max(0, linear[i] as number));
|
|
173
187
|
const source: SplatSource = {
|
|
174
188
|
count,
|
|
175
189
|
positions: Float32Array.from(cloud.positions.values.subarray(0, count * 3)),
|
|
176
190
|
scales: Float32Array.from(cloud.scales.subarray(0, count * 3)),
|
|
177
191
|
rotations: Float32Array.from(cloud.rotations.values.subarray(0, count * 4)),
|
|
178
|
-
colors
|
|
192
|
+
colors,
|
|
179
193
|
opacities: Float32Array.from(cloud.opacities.subarray(0, count)),
|
|
180
194
|
};
|
|
181
195
|
if (cloud.sh1 === null) return source;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
196
|
+
const band = cloud.sh1.values;
|
|
197
|
+
const sh1 = new Float32Array(count * SH1_COEFFICIENTS);
|
|
198
|
+
/* Interleaved by basis and then by channel, so coefficient `k` carries channel `k % 3`. */
|
|
199
|
+
for (let at = 0; at < count; at += 1) {
|
|
200
|
+
for (let k = 0; k < SH1_COEFFICIENTS; k += 1) {
|
|
201
|
+
const slope = encodeSlope(Math.max(0, linear[at * 3 + (k % 3)] as number));
|
|
202
|
+
sh1[at * SH1_COEFFICIENTS + k] = (band[at * SH1_COEFFICIENTS + k] as number) * slope;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return { ...source, sh1 };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/*
|
|
209
|
+
* The sRGB encode and its derivative, through the reproducible `exactExp` and `exactLog` the fit's
|
|
210
|
+
* other transforms use, so a capture fitted on two machines hands over the same colours.
|
|
211
|
+
*/
|
|
212
|
+
function encode(value: number): number {
|
|
213
|
+
return value <= 0.0031308 ? value * 12.92 : 1.055 * exactExp(exactLog(value) / 2.4) - 0.055;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** The encode's slope at `value`: 12.92 on its straight segment, and the curve's above it. */
|
|
217
|
+
function encodeSlope(value: number): number {
|
|
218
|
+
return value <= 0.0031308 ? 12.92 : (1.055 / 2.4) * exactExp(exactLog(value) * (1 / 2.4 - 1));
|
|
186
219
|
}
|