rayzee 10.0.0 → 11.1.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/README.md +252 -44
- package/dist/ActiveColor-YvuQq44O.js +13 -0
- package/dist/ArchiveImporter-Hn35o6Z5.js +5145 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-CBw8hkeu.js +946 -0
- package/dist/BufferLayout-D_IBo2ci.js +150 -0
- package/dist/ColorManagement-oeEk7oSu.js +1488 -0
- package/dist/EngineEvents-Ci8dVWCP.js +73 -0
- package/dist/EngineIssues-CIZnXHsF.js +72 -0
- package/dist/FileFormats-sPGJeCRc.js +102 -0
- package/dist/Logger-dDDGj9Av.js +97 -0
- package/dist/{NeuralRetouch-CYgkQY8Z.js → NeuralRetouch-BzNpiVHZ.js} +8 -6
- package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-Bk7bHg2B.js} +55 -120
- package/dist/PathTracer-72XufKAr.js +29976 -0
- package/dist/PhysicalSky-BgjdV88k.js +1219 -0
- package/dist/RayzeeRenderer-1QRO97eq.js +3551 -0
- package/dist/SolarLimb-CPaeZVwz.js +721 -0
- package/dist/ToneMapGPU-CjU3osDd.js +177 -0
- package/dist/ViewTransforms-CYN7bq2w.js +255 -0
- package/dist/WorkingMatrix-C6y233hT.js +27 -0
- package/dist/ZipReader-gDSWr0I5.js +98 -0
- package/dist/addons/archives.es.js +3 -0
- package/dist/addons/bidirectional.es.js +2 -0
- package/dist/addons/color.es.js +3 -0
- package/dist/addons/formats.es.js +2 -0
- package/dist/addons/physical-sky.es.js +2 -0
- package/dist/addons/storage.es.js +3 -0
- package/dist/archiveFormats-tnAoUL1j.js +94 -0
- package/dist/identity-DrQsGT2o.js +39 -0
- package/dist/openStorage-DwcBRUj7.js +820 -0
- package/dist/rayzee-core.es.js +12 -0
- package/dist/rayzee.es.js +2551 -44024
- package/dist/rayzee.umd.js +528 -487
- package/dist/sceneCachePolicy-C67jbci-.js +443 -0
- package/dist/shared-BGBcSxBQ.js +17 -0
- package/package.json +23 -2
- package/src/Color/ActiveColor.js +34 -0
- package/src/Color/BasicColor.js +147 -0
- package/src/Color/ColorManagement.js +7 -31
- package/src/Color/ViewTransforms.js +5 -1
- package/src/EngineDefaults.js +62 -1029
- package/src/EngineEvents.js +2 -0
- package/src/EngineIssues.js +2 -0
- package/src/Headless.js +6 -5
- package/src/Passes/AIUpscaler.js +58 -141
- package/src/Passes/OIDNDenoiser.js +92 -65
- package/src/Passes/OIDNTemporalHistory.js +1 -1
- package/src/PathTracerApp.js +620 -4026
- package/src/Pipeline/PipelineContext.js +0 -4
- package/src/Platform.js +36 -0
- package/src/Processor/ArchiveCache.js +20 -7
- package/src/Processor/ArchiveImporter.js +1265 -0
- package/src/Processor/ArchiveReader.js +22 -4
- package/src/Processor/AssetLoader.js +327 -1763
- package/src/Processor/AtmosphereModel.js +1 -2
- package/src/Processor/BVHBuilder.js +14 -126
- package/src/Processor/BVHLeafFold.js +4 -6
- package/src/Processor/BVHRefitter.js +67 -46
- package/src/Processor/BufferLayout.js +291 -0
- package/src/Processor/EmissiveTriangleBuilder.js +1 -1
- package/src/Processor/EnvironmentExactTable.js +187 -0
- package/src/Processor/EquirectHDRInfo.js +30 -223
- package/src/Processor/FileFormats.js +116 -0
- package/src/Processor/GLTFDecoders.js +85 -0
- package/src/Processor/GLTFDiffuseTransmission.js +63 -0
- package/src/Processor/GeometryExtractor.js +15 -5
- package/src/Processor/HostMemory.js +7 -1
- package/src/Processor/IESParser.js +47 -35
- package/src/Processor/InstanceTable.js +1 -1
- package/src/Processor/KernelManager.js +35 -2
- package/src/Processor/MaterialPacking.js +10 -8
- package/src/Processor/PBRT/PBRTMaterials.js +254 -42
- package/src/Processor/PBRT/PBRTParser.js +49 -19
- package/src/Processor/PBRT/PBRTScattering.js +93 -0
- package/src/Processor/PBRT/PBRTSceneBuilder.js +1050 -75
- package/src/Processor/PBRT/PBRTTextureBake.js +179 -0
- package/src/Processor/PBRT/PFM.js +59 -0
- package/src/Processor/PackedRayBuffer.js +116 -9
- package/src/Processor/ParallelBVHBuilder.js +3 -6
- package/src/Processor/PhysicalSky.js +5 -4
- package/src/Processor/PlatformImageLoader.js +50 -6
- package/src/Processor/QueueManager.js +39 -5
- package/src/Processor/ReinsertionOptimizer.js +2 -2
- package/src/Processor/SceneMetadata.js +30 -5
- package/src/Processor/SceneProcessor.js +53 -62
- package/src/Processor/ShaderBuilder.js +6 -16
- package/src/Processor/SimpleSky.js +1 -62
- package/src/Processor/SolarLimb.js +3 -0
- package/src/Processor/SplitBLAS.js +1 -1
- package/src/Processor/StorageTexturePool.js +22 -1
- package/src/Processor/TLASBuilder.js +1 -3
- package/src/Processor/TextureBuckets.js +237 -0
- package/src/Processor/TextureCreator.js +181 -8
- package/src/Processor/ToneMapGPU.js +64 -15
- package/src/Processor/Workers/BVHRefitWorker.js +5 -2
- package/src/Processor/Workers/BVHSubtreeWorker.js +1 -34
- package/src/Processor/Workers/BVHWorker.js +5 -18
- package/src/Processor/Workers/CDFWorker.js +6 -183
- package/src/Processor/Workers/TexturesWorker.js +103 -18
- package/src/Processor/archiveFormats.js +7 -0
- package/src/Processor/utils.js +2 -1
- package/src/RayzeeRenderer.js +3900 -0
- package/src/RenderSettings.js +68 -62
- package/src/Stages/ASVGF.js +13 -14
- package/src/Stages/AutoExposure.js +17 -17
- package/src/Stages/BilateralFilter.js +2 -1
- package/src/Stages/Compositor.js +8 -23
- package/src/Stages/DenoiserSettings.js +182 -0
- package/src/Stages/EdgeFilter.js +2 -1
- package/src/Stages/MotionVector.js +1 -1
- package/src/Stages/NRD.js +11 -5
- package/src/Stages/NormalDepth.js +12 -8
- package/src/Stages/PathTracer.js +336 -43
- package/src/Stages/PathTracerStage.js +69 -66
- package/src/Stages/Variance.js +1 -1
- package/src/Storage/BLASCache.js +1 -1
- package/src/Storage/CDFCache.js +18 -17
- package/src/Storage/DownloadCache.js +1 -1
- package/src/Storage/SceneGraphCodec.js +46 -3
- package/src/Storage/SpillStore.js +1 -1
- package/src/Storage/StorageManager.js +45 -9
- package/src/Storage/areas.js +4 -0
- package/src/TSL/BVHTraversal.js +50 -25
- package/src/TSL/Bidirectional.js +208 -0
- package/src/TSL/BidirectionalLamps.js +132 -0
- package/src/TSL/Clearcoat.js +15 -6
- package/src/TSL/Common.js +20 -15
- package/src/TSL/ConnectKernel.js +167 -0
- package/src/TSL/Debugger.js +1 -1
- package/src/TSL/Displacement.js +4 -3
- package/src/TSL/EmissiveSampling.js +65 -18
- package/src/TSL/Environment.js +77 -106
- package/src/TSL/EnvironmentCDF.js +85 -39
- package/src/TSL/ExtendKernel.js +8 -3
- package/src/TSL/FinalWriteKernel.js +4 -4
- package/src/TSL/GenerateKernel.js +18 -4
- package/src/TSL/HitFacet.js +35 -5
- package/src/TSL/LightBVHSampling.js +40 -9
- package/src/TSL/LightGenerateKernel.js +293 -0
- package/src/TSL/LightGuide.js +198 -0
- package/src/TSL/LightSplatKernel.js +180 -0
- package/src/TSL/LightVisibility.js +111 -0
- package/src/TSL/LightsCore.js +13 -38
- package/src/TSL/LightsDirect.js +28 -29
- package/src/TSL/LightsIndirect.js +3 -1
- package/src/TSL/LightsSampling.js +239 -51
- package/src/TSL/MaterialEvaluation.js +113 -31
- package/src/TSL/MaterialProperties.js +44 -17
- package/src/TSL/MaterialTransmission.js +52 -47
- package/src/TSL/MergeKernel.js +224 -0
- package/src/TSL/PathTracerCore.js +65 -29
- package/src/TSL/Random.js +5 -1
- package/src/TSL/SceneResources.js +51 -0
- package/src/TSL/ShadeKernel.js +985 -101
- package/src/TSL/Struct.js +10 -0
- package/src/TSL/Sun.js +1 -1
- package/src/TSL/TextureSampling.js +66 -61
- package/src/addons/archives.js +14 -0
- package/src/addons/bidirectional.js +13 -0
- package/src/addons/color.js +32 -0
- package/src/addons/formats.js +16 -0
- package/src/addons/physicalSky.js +14 -0
- package/src/addons/storage.js +19 -0
- package/src/core.js +31 -0
- package/src/index.js +13 -23
- package/src/integrators/BidirectionalIntegrator.js +838 -0
- package/src/managers/AnimationManager.js +88 -6
- package/src/managers/CameraManager.js +103 -46
- package/src/managers/DenoisingManager.js +14 -10
- package/src/managers/EnvironmentManager.js +125 -103
- package/src/managers/GoboManager.js +9 -0
- package/src/managers/MaterialDataManager.js +48 -37
- package/src/managers/UniformManager.js +32 -10
- package/dist/ToneMapGPU-B6XIe3DU.js +0 -544
- package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
- package/src/Processor/TreeletOptimizer.js +0 -574
|
@@ -1,44 +1,7 @@
|
|
|
1
1
|
import { DataUtils, HalfFloatType, FloatType, SRGBColorSpace } from 'three';
|
|
2
2
|
import CDFWorker from './Workers/CDFWorker.js?worker&inline';
|
|
3
3
|
import { createWorker } from '../Platform.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Binary search to find the closest index
|
|
7
|
-
*/
|
|
8
|
-
function binarySearchFindClosestIndexOf( array, targetValue, offset = 0, count = array.length ) {
|
|
9
|
-
|
|
10
|
-
let lower = offset;
|
|
11
|
-
let upper = offset + count - 1;
|
|
12
|
-
|
|
13
|
-
while ( lower < upper ) {
|
|
14
|
-
|
|
15
|
-
const mid = ( lower + upper ) >> 1;
|
|
16
|
-
|
|
17
|
-
if ( array[ mid ] < targetValue ) {
|
|
18
|
-
|
|
19
|
-
lower = mid + 1;
|
|
20
|
-
|
|
21
|
-
} else {
|
|
22
|
-
|
|
23
|
-
upper = mid;
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return lower - offset;
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Calculate luminance from RGB values
|
|
35
|
-
*/
|
|
36
|
-
function colorToLuminance( r, g, b ) {
|
|
37
|
-
|
|
38
|
-
// https://en.wikipedia.org/wiki/Relative_luminance
|
|
39
|
-
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
40
|
-
|
|
41
|
-
}
|
|
4
|
+
import { buildExactEnvironmentTable } from './EnvironmentExactTable.js';
|
|
42
5
|
|
|
43
6
|
/**
|
|
44
7
|
* sRGB to linear conversion (IEC 61966-2-1 transfer function)
|
|
@@ -154,27 +117,24 @@ export function extractFloatData( envMap ) {
|
|
|
154
117
|
}
|
|
155
118
|
|
|
156
119
|
/**
|
|
157
|
-
* EquirectHDRInfo -
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* Outputs Float32Arrays consumed directly by StorageInstancedBufferAttribute
|
|
161
|
-
* on the GPU — no intermediate DataTexture or HalfFloat conversion needed.
|
|
162
|
-
*
|
|
163
|
-
* Supports two modes:
|
|
164
|
-
* - `updateFrom(hdr)`: synchronous, runs on main thread
|
|
165
|
-
* - `updateFromAsync(hdr)`: offloads CDF math to a Web Worker
|
|
120
|
+
* EquirectHDRInfo - an equirectangular environment's sampling table (EnvironmentExactTable.js), built on the
|
|
121
|
+
* main thread (`updateFrom`) or in CDFWorker (`updateFromAsync`). `totalSum` is the map's ∫ luminance dω, 0
|
|
122
|
+
* when there is nothing to sample.
|
|
166
123
|
*/
|
|
167
124
|
export class EquirectHDRInfo {
|
|
168
125
|
|
|
169
126
|
constructor() {
|
|
170
127
|
|
|
171
|
-
// Placeholder data matching the default storage buffer sizes in PathTracer
|
|
172
|
-
this.marginalData = new Float32Array( [ 0, 1 ] );
|
|
173
|
-
this.conditionalData = new Float32Array( [ 0, 0, 1, 1 ] );
|
|
174
128
|
this.totalSum = 0;
|
|
175
|
-
this.compensationDelta = 0;
|
|
176
129
|
this.width = 0;
|
|
177
130
|
this.height = 0;
|
|
131
|
+
this.exactConditional = null;
|
|
132
|
+
this.exactMarginal = null;
|
|
133
|
+
this.exactRowGuide = null;
|
|
134
|
+
this.exactMarginalGuide = null;
|
|
135
|
+
this.exactWidth = 0;
|
|
136
|
+
this.exactHeight = 0;
|
|
137
|
+
this.radianceIntegral = 0;
|
|
178
138
|
|
|
179
139
|
this._worker = null;
|
|
180
140
|
|
|
@@ -182,8 +142,10 @@ export class EquirectHDRInfo {
|
|
|
182
142
|
|
|
183
143
|
dispose() {
|
|
184
144
|
|
|
185
|
-
this.
|
|
186
|
-
this.
|
|
145
|
+
this.exactConditional = null;
|
|
146
|
+
this.exactMarginal = null;
|
|
147
|
+
this.exactRowGuide = null;
|
|
148
|
+
this.exactMarginalGuide = null;
|
|
187
149
|
|
|
188
150
|
if ( this._worker ) {
|
|
189
151
|
|
|
@@ -194,28 +156,28 @@ export class EquirectHDRInfo {
|
|
|
194
156
|
|
|
195
157
|
}
|
|
196
158
|
|
|
159
|
+
_adopt( table, width, height ) {
|
|
160
|
+
|
|
161
|
+
Object.assign( this, table );
|
|
162
|
+
this.width = width;
|
|
163
|
+
this.height = height;
|
|
164
|
+
this.totalSum = table.radianceIntegral;
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
197
168
|
/**
|
|
198
|
-
* Synchronous
|
|
169
|
+
* Synchronous build on the main thread (fallback path).
|
|
199
170
|
*/
|
|
200
171
|
updateFrom( hdr ) {
|
|
201
172
|
|
|
202
173
|
const { floatData, width, height } = extractFloatData( hdr );
|
|
203
|
-
|
|
204
|
-
const result = EquirectHDRInfo.computeCDF( floatData, width, height );
|
|
205
|
-
|
|
206
|
-
this.marginalData = result.marginalData;
|
|
207
|
-
this.conditionalData = result.conditionalData;
|
|
208
|
-
this.totalSum = result.totalSum;
|
|
209
|
-
this.compensationDelta = result.compensationDelta;
|
|
210
|
-
this.width = width;
|
|
211
|
-
this.height = height;
|
|
174
|
+
this._adopt( buildExactEnvironmentTable( floatData, width, height ), width, height );
|
|
212
175
|
|
|
213
176
|
}
|
|
214
177
|
|
|
215
178
|
/**
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* then the pure-math CDF computation runs off-thread.
|
|
179
|
+
* The build offloaded to a Web Worker. Float extraction (HalfFloat → Float32) runs on the main thread
|
|
180
|
+
* (it needs three's DataUtils); the table's math runs off it.
|
|
219
181
|
* @returns {Promise<void>}
|
|
220
182
|
*/
|
|
221
183
|
async updateFromAsync( hdr ) {
|
|
@@ -253,12 +215,8 @@ export class EquirectHDRInfo {
|
|
|
253
215
|
|
|
254
216
|
} );
|
|
255
217
|
|
|
256
|
-
|
|
257
|
-
this.
|
|
258
|
-
this.totalSum = result.totalSum;
|
|
259
|
-
this.compensationDelta = result.compensationDelta;
|
|
260
|
-
this.width = result.width;
|
|
261
|
-
this.height = result.height;
|
|
218
|
+
const { width: w, height: h, ...table } = result;
|
|
219
|
+
this._adopt( table, w, h );
|
|
262
220
|
|
|
263
221
|
} finally {
|
|
264
222
|
|
|
@@ -273,155 +231,4 @@ export class EquirectHDRInfo {
|
|
|
273
231
|
|
|
274
232
|
}
|
|
275
233
|
|
|
276
|
-
/**
|
|
277
|
-
* Pure-math CDF computation. Used by both the sync path and CDFWorker.
|
|
278
|
-
* Static so it can be called without an instance.
|
|
279
|
-
*/
|
|
280
|
-
static computeCDF( floatData, width, height ) {
|
|
281
|
-
|
|
282
|
-
const numPixels = width * height;
|
|
283
|
-
|
|
284
|
-
// Pass 1: compute per-pixel luminance weighted by sin(theta) and raw total sum.
|
|
285
|
-
// sin(theta) compensates for the equirectangular projection: pixels near the poles
|
|
286
|
-
// cover less solid angle, so weighting by sin(theta) makes the CDF proportional to
|
|
287
|
-
// luminance per solid angle rather than luminance per pixel.
|
|
288
|
-
const pixelWeights = new Float32Array( numPixels );
|
|
289
|
-
let rawTotalSum = 0.0;
|
|
290
|
-
|
|
291
|
-
for ( let y = 0; y < height; y ++ ) {
|
|
292
|
-
|
|
293
|
-
const sinTheta = Math.sin( Math.PI * ( y + 0.5 ) / height );
|
|
294
|
-
|
|
295
|
-
for ( let x = 0; x < width; x ++ ) {
|
|
296
|
-
|
|
297
|
-
const i = y * width + x;
|
|
298
|
-
const w = colorToLuminance(
|
|
299
|
-
floatData[ 4 * i ],
|
|
300
|
-
floatData[ 4 * i + 1 ],
|
|
301
|
-
floatData[ 4 * i + 2 ],
|
|
302
|
-
) * sinTheta;
|
|
303
|
-
pixelWeights[ i ] = w;
|
|
304
|
-
rawTotalSum += w;
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// MIS Compensation (Karlík et al. 2019, Eq. 14)
|
|
311
|
-
// With equal sample allocation (c_I = 0.5): delta = 2*(1 - 0.5)*meanWeight = meanWeight
|
|
312
|
-
// Subtracting mean sharpens the env map PDF, reducing oversampling
|
|
313
|
-
// of dim regions already well-covered by BSDF sampling.
|
|
314
|
-
const meanWeight = rawTotalSum / numPixels;
|
|
315
|
-
let compensatedTotalSum = 0.0;
|
|
316
|
-
|
|
317
|
-
for ( let i = 0; i < numPixels; i ++ ) {
|
|
318
|
-
|
|
319
|
-
pixelWeights[ i ] = Math.max( 0, pixelWeights[ i ] - meanWeight );
|
|
320
|
-
compensatedTotalSum += pixelWeights[ i ];
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Fall back to raw weights if compensation zeroed everything (uniform env map)
|
|
325
|
-
const useCompensation = compensatedTotalSum > 0;
|
|
326
|
-
const totalSumValue = useCompensation ? compensatedTotalSum : rawTotalSum;
|
|
327
|
-
const compensationDelta = useCompensation ? meanWeight : 0;
|
|
328
|
-
|
|
329
|
-
if ( ! useCompensation ) {
|
|
330
|
-
|
|
331
|
-
for ( let y = 0; y < height; y ++ ) {
|
|
332
|
-
|
|
333
|
-
const sinTheta = Math.sin( Math.PI * ( y + 0.5 ) / height );
|
|
334
|
-
|
|
335
|
-
for ( let x = 0; x < width; x ++ ) {
|
|
336
|
-
|
|
337
|
-
const i = y * width + x;
|
|
338
|
-
pixelWeights[ i ] = colorToLuminance(
|
|
339
|
-
floatData[ 4 * i ],
|
|
340
|
-
floatData[ 4 * i + 1 ],
|
|
341
|
-
floatData[ 4 * i + 2 ],
|
|
342
|
-
) * sinTheta;
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Pass 2: build conditional and marginal CDFs from (compensated) weights
|
|
351
|
-
const cdfConditional = new Float32Array( numPixels );
|
|
352
|
-
const cdfMarginal = new Float32Array( height );
|
|
353
|
-
|
|
354
|
-
let cumulativeWeightMarginal = 0.0;
|
|
355
|
-
|
|
356
|
-
for ( let y = 0; y < height; y ++ ) {
|
|
357
|
-
|
|
358
|
-
let cumulativeRowWeight = 0.0;
|
|
359
|
-
for ( let x = 0; x < width; x ++ ) {
|
|
360
|
-
|
|
361
|
-
const i = y * width + x;
|
|
362
|
-
cumulativeRowWeight += pixelWeights[ i ];
|
|
363
|
-
cdfConditional[ i ] = cumulativeRowWeight;
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Normalize row CDF to [0, 1]
|
|
368
|
-
if ( cumulativeRowWeight !== 0 ) {
|
|
369
|
-
|
|
370
|
-
for ( let i = y * width, l = y * width + width; i < l; i ++ ) {
|
|
371
|
-
|
|
372
|
-
cdfConditional[ i ] /= cumulativeRowWeight;
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
cumulativeWeightMarginal += cumulativeRowWeight;
|
|
379
|
-
cdfMarginal[ y ] = cumulativeWeightMarginal;
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Normalize marginal CDF to [0, 1]
|
|
384
|
-
if ( cumulativeWeightMarginal !== 0 ) {
|
|
385
|
-
|
|
386
|
-
for ( let i = 0, l = cdfMarginal.length; i < l; i ++ ) {
|
|
387
|
-
|
|
388
|
-
cdfMarginal[ i ] /= cumulativeWeightMarginal;
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Create inverted CDF arrays (Float32 directly for storage buffers)
|
|
395
|
-
const marginalData = new Float32Array( height );
|
|
396
|
-
const conditionalData = new Float32Array( numPixels );
|
|
397
|
-
|
|
398
|
-
// Invert marginal CDF
|
|
399
|
-
for ( let i = 0; i < height; i ++ ) {
|
|
400
|
-
|
|
401
|
-
const dist = ( i + 1 ) / height;
|
|
402
|
-
const row = binarySearchFindClosestIndexOf( cdfMarginal, dist );
|
|
403
|
-
|
|
404
|
-
marginalData[ i ] = ( row + 0.5 ) / height;
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Invert conditional CDFs
|
|
409
|
-
for ( let y = 0; y < height; y ++ ) {
|
|
410
|
-
|
|
411
|
-
for ( let x = 0; x < width; x ++ ) {
|
|
412
|
-
|
|
413
|
-
const i = y * width + x;
|
|
414
|
-
const dist = ( x + 1 ) / width;
|
|
415
|
-
const col = binarySearchFindClosestIndexOf( cdfConditional, dist, y * width, width );
|
|
416
|
-
|
|
417
|
-
conditionalData[ i ] = ( col + 0.5 ) / width;
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
return { marginalData, conditionalData, totalSum: totalSumValue, compensationDelta };
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
|
|
427
234
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { FloatType, Mesh, MeshStandardMaterial, Points, PointsMaterial } from 'three';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* File formats beyond glTF and .hdr, each registered on its own (`assetLoader.registerFormat( fbxFormat )`) so a host
|
|
5
|
+
* ships only the readers it uses. A model format's `parse( file, { filename, cache } )` resolves to `{ model, result? }`;
|
|
6
|
+
* an environment format's `createLoader( manager )` to a three.js loader whose `loadAsync` resolves to a texture.
|
|
7
|
+
* Each three.js loader is imported the first time its format is read.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const fbxFormat = {
|
|
11
|
+
name: 'FBX', label: 'FBX', type: 'model', extensions: [ 'fbx' ],
|
|
12
|
+
async parse( file, { cache } ) {
|
|
13
|
+
|
|
14
|
+
cache.fbx ??= new ( await import( 'three/addons/loaders/FBXLoader.js' ) ).FBXLoader();
|
|
15
|
+
return { model: cache.fbx.parse( await file.arrayBuffer() ) };
|
|
16
|
+
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const objFormat = {
|
|
21
|
+
name: 'OBJ', label: 'OBJ', type: 'model', extensions: [ 'obj' ],
|
|
22
|
+
async parse( file, { filename, cache } ) {
|
|
23
|
+
|
|
24
|
+
cache.obj ??= new ( await import( 'three/addons/loaders/OBJLoader.js' ) ).OBJLoader();
|
|
25
|
+
const model = cache.obj.parse( await file.text() );
|
|
26
|
+
model.name = filename;
|
|
27
|
+
return { model };
|
|
28
|
+
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const stlFormat = {
|
|
33
|
+
name: 'STL', label: 'STL', type: 'model', extensions: [ 'stl' ],
|
|
34
|
+
async parse( file, { filename, cache } ) {
|
|
35
|
+
|
|
36
|
+
cache.stl ??= new ( await import( 'three/addons/loaders/STLLoader.js' ) ).STLLoader();
|
|
37
|
+
const model = new Mesh( cache.stl.parse( await file.arrayBuffer() ), new MeshStandardMaterial() );
|
|
38
|
+
model.name = filename;
|
|
39
|
+
return { model };
|
|
40
|
+
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const plyFormat = {
|
|
45
|
+
name: 'PLY (Polygon File Format)', label: 'PLY', type: 'model', extensions: [ 'ply' ],
|
|
46
|
+
async parse( file, { filename, cache } ) {
|
|
47
|
+
|
|
48
|
+
cache.ply ??= new ( await import( 'three/addons/loaders/PLYLoader.js' ) ).PLYLoader();
|
|
49
|
+
const geometry = cache.ply.parse( await file.arrayBuffer() );
|
|
50
|
+
let model;
|
|
51
|
+
if ( geometry.index !== null ) {
|
|
52
|
+
|
|
53
|
+
model = new Mesh( geometry, new MeshStandardMaterial() );
|
|
54
|
+
|
|
55
|
+
} else {
|
|
56
|
+
|
|
57
|
+
const material = new PointsMaterial( { size: 0.01 } );
|
|
58
|
+
material.vertexColors = geometry.hasAttribute( 'color' );
|
|
59
|
+
model = new Points( geometry, material );
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
model.name = filename;
|
|
64
|
+
return { model };
|
|
65
|
+
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const colladaFormat = {
|
|
70
|
+
name: 'Collada', label: 'Collada', type: 'model', extensions: [ 'dae' ],
|
|
71
|
+
async parse( file, { filename, cache } ) {
|
|
72
|
+
|
|
73
|
+
cache.collada ??= new ( await import( 'three/addons/loaders/ColladaLoader.js' ) ).ColladaLoader();
|
|
74
|
+
const collada = cache.collada.parse( await file.text() );
|
|
75
|
+
collada.scene.name = filename;
|
|
76
|
+
return { model: collada.scene, result: collada };
|
|
77
|
+
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const threeMFFormat = {
|
|
82
|
+
name: '3D Manufacturing Format', label: '3MF', type: 'model', extensions: [ '3mf' ],
|
|
83
|
+
async parse( file, { cache } ) {
|
|
84
|
+
|
|
85
|
+
cache.threemf ??= new ( await import( 'three/addons/loaders/3MFLoader.js' ) ).ThreeMFLoader();
|
|
86
|
+
return { model: cache.threemf.parse( await file.arrayBuffer() ) };
|
|
87
|
+
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const usdFormat = {
|
|
92
|
+
name: 'USD (Universal Scene Description)', label: 'USD', type: 'model', extensions: [ 'usd', 'usda', 'usdc', 'usdz' ],
|
|
93
|
+
async parse( file, { filename, cache } ) {
|
|
94
|
+
|
|
95
|
+
cache.usd ??= new ( await import( 'three/addons/loaders/USDLoader.js' ) ).USDLoader();
|
|
96
|
+
const data = await file.arrayBuffer();
|
|
97
|
+
// parse() returns the group at once but resolves textures later; the materials are read after, so wait for them.
|
|
98
|
+
const model = await new Promise( ( resolve, reject ) => cache.usd.parse( data, '', resolve, reject ) );
|
|
99
|
+
model.name = filename;
|
|
100
|
+
return { model };
|
|
101
|
+
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const exrFormat = {
|
|
106
|
+
name: 'EXR (OpenEXR)', label: 'EXR', type: 'environment', extensions: [ 'exr' ],
|
|
107
|
+
async createLoader( manager ) {
|
|
108
|
+
|
|
109
|
+
const { EXRLoader } = await import( 'three/addons/loaders/EXRLoader.js' );
|
|
110
|
+
return new EXRLoader( manager ).setDataType( FloatType );
|
|
111
|
+
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/** Every format above. */
|
|
116
|
+
export const allFormats = [ fbxFormat, objFormat, stlFormat, plyFormat, colladaFormat, threeMFFormat, usdFormat, exrFormat ];
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { getAssetConfig } from '../AssetConfig.js';
|
|
2
|
+
|
|
3
|
+
const DRACO = 'KHR_draco_mesh_compression';
|
|
4
|
+
const BASISU = 'KHR_texture_basisu';
|
|
5
|
+
const MESHOPT = [ 'EXT_meshopt_compression', 'KHR_meshopt_compression' ];
|
|
6
|
+
|
|
7
|
+
const decoder = new TextDecoder();
|
|
8
|
+
|
|
9
|
+
// The glTF's JSON as text: a .glb's first chunk, a .gltf whole. Only searched, never parsed.
|
|
10
|
+
function jsonText( data ) {
|
|
11
|
+
|
|
12
|
+
if ( typeof data === 'string' ) return data;
|
|
13
|
+
if ( ! ( data instanceof ArrayBuffer ) ) return JSON.stringify( data?.extensionsUsed ?? [] );
|
|
14
|
+
|
|
15
|
+
const view = new DataView( data );
|
|
16
|
+
const isBinary = data.byteLength >= 20 && view.getUint32( 0, true ) === 0x46546C67;
|
|
17
|
+
if ( ! isBinary ) return decoder.decode( data );
|
|
18
|
+
const length = Math.min( view.getUint32( 12, true ), data.byteLength - 20 );
|
|
19
|
+
return decoder.decode( new Uint8Array( data, 20, length ) );
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function attachDecoders( loader, text, renderer ) {
|
|
24
|
+
|
|
25
|
+
const { dracoDecoderPath, ktx2TranscoderPath } = getAssetConfig();
|
|
26
|
+
const [ draco, ktx2, meshopt ] = await Promise.all( [
|
|
27
|
+
text.includes( DRACO ) && ! loader.dracoLoader ? import( 'three/addons/loaders/DRACOLoader.js' ) : null,
|
|
28
|
+
text.includes( BASISU ) && ! loader.ktx2Loader ? import( 'three/addons/loaders/KTX2Loader.js' ) : null,
|
|
29
|
+
MESHOPT.some( name => text.includes( name ) ) && ! loader.meshoptDecoder ? import( 'three/addons/libs/meshopt_decoder.module.js' ) : null,
|
|
30
|
+
] );
|
|
31
|
+
|
|
32
|
+
if ( draco ) {
|
|
33
|
+
|
|
34
|
+
const dracoLoader = new draco.DRACOLoader();
|
|
35
|
+
dracoLoader.setDecoderConfig( { type: 'js' } );
|
|
36
|
+
dracoLoader.setDecoderPath( dracoDecoderPath );
|
|
37
|
+
loader.setDRACOLoader( dracoLoader );
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ( ktx2 ) {
|
|
42
|
+
|
|
43
|
+
const ktx2Loader = new ktx2.KTX2Loader();
|
|
44
|
+
ktx2Loader.setTranscoderPath( ktx2TranscoderPath );
|
|
45
|
+
if ( renderer ) {
|
|
46
|
+
|
|
47
|
+
ktx2Loader.detectSupport( renderer );
|
|
48
|
+
// RGBA only: GPU-compressed texture arrays are blocked by a three.js TSL limitation (the node compiler's
|
|
49
|
+
// state survives dispose(), so swapping DataArrayTexture for CompressedArrayTexture breaks WGSL compilation).
|
|
50
|
+
ktx2Loader.workerConfig = {
|
|
51
|
+
astcSupported: false, etc1Supported: false, etc2Supported: false,
|
|
52
|
+
dxtSupported: false, bptcSupported: false, pvrtcSupported: false,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
loader.setKTX2Loader( ktx2Loader );
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if ( meshopt ) loader.setMeshoptDecoder( meshopt.MeshoptDecoder );
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Gives a GLTFLoader the Draco, KTX2 and meshopt decoders only when the file it parses uses them, importing each then:
|
|
67
|
+
* most glTFs use none, and the three are ~35 KB compressed a host would otherwise always ship.
|
|
68
|
+
* @param {Object} loader - a GLTFLoader
|
|
69
|
+
* @param {?Object} renderer - for KTX2's format detection
|
|
70
|
+
*/
|
|
71
|
+
export function decodersOnDemand( loader, renderer ) {
|
|
72
|
+
|
|
73
|
+
const parse = loader.parse.bind( loader );
|
|
74
|
+
loader.parse = ( data, path, onLoad, onError ) => {
|
|
75
|
+
|
|
76
|
+
attachDecoders( loader, jsonText( data ), renderer ).then(
|
|
77
|
+
() => parse( data, path, onLoad, onError ),
|
|
78
|
+
( error ) => onError?.( error ),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return loader;
|
|
84
|
+
|
|
85
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Color, LinearSRGBColorSpace, SRGBColorSpace } from 'three';
|
|
2
|
+
|
|
3
|
+
export const DIFFUSE_TRANSMISSION_EXTENSION = 'KHR_materials_diffuse_transmission';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A GLTFLoader plugin for KHR_materials_diffuse_transmission, which three.js does not read: each material's factors
|
|
7
|
+
* and textures become the engine's `diffuseTransmission`, `diffuseTransmissionColor`, `diffuseTransmissionMap` (its
|
|
8
|
+
* alpha is the factor) and `diffuseTransmissionColorMap`. The engine folds the maps in like the other extension maps,
|
|
9
|
+
* through the albedo map's uv transform.
|
|
10
|
+
*/
|
|
11
|
+
export function diffuseTransmissionPlugin( parser ) {
|
|
12
|
+
|
|
13
|
+
// The factor texture is read for its alpha alone and may be another slot's colour texture, so its colour space is
|
|
14
|
+
// left as it is.
|
|
15
|
+
const assign = ( material, key, info, colorSpace ) => {
|
|
16
|
+
|
|
17
|
+
const params = {};
|
|
18
|
+
return parser.assignTexture( params, key, info, colorSpace ).then( () => {
|
|
19
|
+
|
|
20
|
+
if ( params[ key ] ) material[ key ] = params[ key ];
|
|
21
|
+
|
|
22
|
+
} );
|
|
23
|
+
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
|
|
28
|
+
name: DIFFUSE_TRANSMISSION_EXTENSION,
|
|
29
|
+
|
|
30
|
+
afterRoot( result ) {
|
|
31
|
+
|
|
32
|
+
const definitions = parser.json.materials ?? [];
|
|
33
|
+
const done = new Set();
|
|
34
|
+
const pending = [];
|
|
35
|
+
|
|
36
|
+
for ( const scene of result.scenes ?? [] ) scene.traverse( ( object ) => {
|
|
37
|
+
|
|
38
|
+
const materials = Array.isArray( object.material ) ? object.material : object.material ? [ object.material ] : [];
|
|
39
|
+
for ( const material of materials ) {
|
|
40
|
+
|
|
41
|
+
if ( done.has( material ) ) continue;
|
|
42
|
+
done.add( material );
|
|
43
|
+
const index = parser.associations.get( material )?.materials;
|
|
44
|
+
const extension = index === undefined ? null : definitions[ index ]?.extensions?.[ DIFFUSE_TRANSMISSION_EXTENSION ];
|
|
45
|
+
if ( ! extension ) continue;
|
|
46
|
+
|
|
47
|
+
material.diffuseTransmission = extension.diffuseTransmissionFactor ?? 0;
|
|
48
|
+
const [ r, g, b ] = extension.diffuseTransmissionColorFactor ?? [ 1, 1, 1 ];
|
|
49
|
+
material.diffuseTransmissionColor = new Color().setRGB( r, g, b, LinearSRGBColorSpace );
|
|
50
|
+
if ( extension.diffuseTransmissionTexture ) pending.push( assign( material, 'diffuseTransmissionMap', extension.diffuseTransmissionTexture ) );
|
|
51
|
+
if ( extension.diffuseTransmissionColorTexture ) pending.push( assign( material, 'diffuseTransmissionColorMap', extension.diffuseTransmissionColorTexture, SRGBColorSpace ) );
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
} );
|
|
56
|
+
|
|
57
|
+
return Promise.all( pending );
|
|
58
|
+
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BufferAttribute, Vector3, Vector2, Color, Matrix3, Matrix4, FrontSide, BackSide, DoubleSide, RGBAFormat } from "three";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
} from '
|
|
2
|
+
import { MATERIAL_DEFAULTS } from '../EngineDefaults.js';
|
|
3
|
+
import { TRIANGLE_DATA_LAYOUT, packNormalOct, packTriangleFlags } from './BufferLayout.js';
|
|
4
|
+
import { TEXTURE_CONSTANTS } from './TextureBuckets.js';
|
|
5
5
|
import { ISSUE_CODES } from '../EngineIssues.js';
|
|
6
6
|
import { ChunkedRecords, SHARED_MEMORY_AVAILABLE } from './ChunkedRecords.js';
|
|
7
7
|
import { createLogger, fmt, warnOnce } from '../utils/Logger.js';
|
|
@@ -11,7 +11,7 @@ const log = createLogger( 'geometry' );
|
|
|
11
11
|
|
|
12
12
|
const MAX_TEXTURES_LIMIT = TEXTURE_CONSTANTS.MAX_TEXTURES_LIMIT;
|
|
13
13
|
|
|
14
|
-
const COLOR_DEFAULTS = new Set( [ 'color', 'emissive', 'attenuationColor', 'sheenColor', 'specularColor', 'subsurfaceColor' ] );
|
|
14
|
+
const COLOR_DEFAULTS = new Set( [ 'color', 'emissive', 'attenuationColor', 'sheenColor', 'specularColor', 'subsurfaceColor', 'diffuseTransmissionColor' ] );
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Where a packed material value came from: the three.js material carried it, a legacy-type
|
|
@@ -58,6 +58,8 @@ export function resolveMaterialTextures( material ) {
|
|
|
58
58
|
sheenRoughnessMap: material.sheenRoughnessMap,
|
|
59
59
|
specularIntensityMap: material.specularIntensityMap,
|
|
60
60
|
specularColorMap: material.specularColorMap,
|
|
61
|
+
diffuseTransmissionMap: material.diffuseTransmissionMap,
|
|
62
|
+
diffuseTransmissionColorMap: material.diffuseTransmissionColorMap,
|
|
61
63
|
iridescenceMap: material.iridescenceMap,
|
|
62
64
|
iridescenceThicknessMap: material.iridescenceThicknessMap,
|
|
63
65
|
};
|
|
@@ -1110,6 +1112,9 @@ export class GeometryExtractor {
|
|
|
1110
1112
|
specularIntensity: pick( 'specularIntensity' ),
|
|
1111
1113
|
specularColor: pick( 'specularColor' ),
|
|
1112
1114
|
|
|
1115
|
+
diffuseTransmission: pick( 'diffuseTransmission' ),
|
|
1116
|
+
diffuseTransmissionColor: pick( 'diffuseTransmissionColor' ),
|
|
1117
|
+
|
|
1113
1118
|
normalScale: pick( 'normalScale' ),
|
|
1114
1119
|
bumpScale: pick( 'bumpScale' ),
|
|
1115
1120
|
displacementScale: pick( 'displacementScale' ),
|
|
@@ -1141,6 +1146,8 @@ export class GeometryExtractor {
|
|
|
1141
1146
|
sheenRoughnessMap: this.processTexture( textures.sheenRoughnessMap, this.sheenRoughnessMaps ),
|
|
1142
1147
|
specularIntensityMap: this.processTexture( textures.specularIntensityMap, this.specularIntensityMaps ),
|
|
1143
1148
|
specularColorMap: this.processTexture( textures.specularColorMap, this.specularColorMaps ),
|
|
1149
|
+
diffuseTransmissionMap: this.processTexture( textures.diffuseTransmissionMap, this.diffuseTransmissionMaps ),
|
|
1150
|
+
diffuseTransmissionColorMap: this.processTexture( textures.diffuseTransmissionColorMap, this.diffuseTransmissionColorMaps ),
|
|
1144
1151
|
iridescenceMap: this.processTexture( textures.iridescenceMap, this.iridescenceMaps ),
|
|
1145
1152
|
iridescenceThicknessMap: this.processTexture( textures.iridescenceThicknessMap, this.iridescenceThicknessMaps ),
|
|
1146
1153
|
|
|
@@ -1171,7 +1178,6 @@ export class GeometryExtractor {
|
|
|
1171
1178
|
getMaterialSide( material ) {
|
|
1172
1179
|
|
|
1173
1180
|
if ( material.transmission > 0.0 ) return 2;
|
|
1174
|
-
if ( material.userData?.cutaway === true ) return MATERIAL_SIDE_CUTAWAY;
|
|
1175
1181
|
switch ( material.side ) {
|
|
1176
1182
|
|
|
1177
1183
|
case FrontSide: return 0;
|
|
@@ -1538,6 +1544,8 @@ export class GeometryExtractor {
|
|
|
1538
1544
|
this.iridescenceThicknessMaps = [];
|
|
1539
1545
|
this.specularIntensityMaps = [];
|
|
1540
1546
|
this.specularColorMaps = [];
|
|
1547
|
+
this.diffuseTransmissionMaps = [];
|
|
1548
|
+
this.diffuseTransmissionColorMaps = [];
|
|
1541
1549
|
this.directionalLights = [];
|
|
1542
1550
|
this.cameras = [];
|
|
1543
1551
|
|
|
@@ -1579,6 +1587,8 @@ export class GeometryExtractor {
|
|
|
1579
1587
|
iridescenceThicknessMaps: this.iridescenceThicknessMaps,
|
|
1580
1588
|
specularIntensityMaps: this.specularIntensityMaps,
|
|
1581
1589
|
specularColorMaps: this.specularColorMaps,
|
|
1590
|
+
diffuseTransmissionMaps: this.diffuseTransmissionMaps,
|
|
1591
|
+
diffuseTransmissionColorMaps: this.diffuseTransmissionColorMaps,
|
|
1582
1592
|
directionalLights: this.directionalLights,
|
|
1583
1593
|
cameras: this.cameras
|
|
1584
1594
|
};
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* that actually runs out (BVH assembly), where it asks only for that step's bytes.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { TRIANGLE_DATA_LAYOUT } from '
|
|
17
|
+
import { TRIANGLE_DATA_LAYOUT } from './BufferLayout.js';
|
|
18
18
|
import { DEFAULT_CHUNK_BYTES } from './ChunkedRecords.js';
|
|
19
19
|
|
|
20
20
|
/** Bytes one stored triangle occupies in the triangle records. */
|
|
@@ -59,6 +59,12 @@ export const SAFE_SCENE_BYTES = 7040 * 1024 * 1024;
|
|
|
59
59
|
*/
|
|
60
60
|
export const MAX_SCENE_BYTES = 9216 * 1024 * 1024;
|
|
61
61
|
|
|
62
|
+
// Scene-archive budgets with the memory spill on: the triangles and BVH leave the heap as the build goes, so the host
|
|
63
|
+
// passes these instead of the importer's own. The whole 15-part Moana subset (55.7M / 7.0M) loads cold under them, at
|
|
64
|
+
// an 8.1 GB preflight estimate; the preflight, not the budget, refuses anything larger.
|
|
65
|
+
export const SPILL_TRIANGLE_BUDGET = 60_000_000;
|
|
66
|
+
export const SPILL_PLACEMENT_BUDGET = 8_000_000;
|
|
67
|
+
|
|
62
68
|
/**
|
|
63
69
|
* The host's memory in GB: the host's own figure when it gives one, else Chrome's
|
|
64
70
|
* `navigator.deviceMemory`, else an assumed 4 (every other runtime lacks it).
|