rayzee 9.4.2 → 9.5.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 +223 -21
- package/dist/ActiveColor-YvuQq44O.js +13 -0
- package/dist/ArchiveImporter-xuUJiklP.js +4301 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-C5PKjJoT.js +934 -0
- package/dist/ColorManagement-CheBCPaW.js +1488 -0
- package/dist/EngineDefaults-DH3bI5t-.js +844 -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-BnHghprG.js +97 -0
- package/dist/{NeuralRetouch-vkdXXyK2.js → NeuralRetouch-CW11yLZ_.js} +8 -6
- package/dist/{NeuralSuperRes-FVqRJKQV.js → NeuralSuperRes-BekaecYg.js} +55 -120
- package/dist/PathTracer-Ccl9KOuF.js +29729 -0
- package/dist/PhysicalSky-Dv2PMFGW.js +1219 -0
- package/dist/RayzeeRenderer-BQxnzCTD.js +3542 -0
- package/dist/SolarLimb-ken-JbDK.js +721 -0
- package/dist/ToneMapGPU-BHi5JzIq.js +177 -0
- package/dist/ViewTransforms-D0rTLBsX.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-BZw7TiDp.js +75 -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 +2266 -44079
- package/dist/rayzee.umd.js +485 -473
- package/dist/sceneCachePolicy-BmwYOYDu.js +183 -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/EngineDefaults.js +22 -8
- package/src/EngineEvents.js +2 -0
- package/src/EngineIssues.js +1 -0
- package/src/PathTracerApp.js +617 -4016
- package/src/Pipeline/PipelineContext.js +0 -4
- package/src/Platform.js +36 -0
- package/src/Processor/ArchiveCache.js +1 -1
- package/src/Processor/ArchiveImporter.js +1259 -0
- package/src/Processor/AssetLoader.js +322 -1746
- package/src/Processor/AtmosphereModel.js +1 -2
- package/src/Processor/BVHBuilder.js +4 -95
- 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 +12 -1
- package/src/Processor/IESParser.js +47 -35
- package/src/Processor/KernelManager.js +35 -2
- package/src/Processor/MaterialPacking.js +8 -7
- package/src/Processor/PBRT/PBRTMaterials.js +129 -41
- package/src/Processor/PBRT/PBRTParser.js +30 -17
- package/src/Processor/PBRT/PBRTSceneBuilder.js +548 -37
- package/src/Processor/PBRT/PBRTTextureBake.js +154 -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 +12 -3
- package/src/Processor/ReinsertionOptimizer.js +2 -2
- package/src/Processor/SceneProcessor.js +15 -55
- package/src/Processor/ShaderBuilder.js +6 -16
- package/src/Processor/SolarLimb.js +3 -0
- package/src/Processor/TextureCreator.js +1 -1
- 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/archiveFormats.js +7 -0
- package/src/Processor/utils.js +2 -1
- package/src/RayzeeRenderer.js +3902 -0
- package/src/RenderSettings.js +49 -41
- package/src/Stages/ASVGF.js +5 -7
- package/src/Stages/AutoExposure.js +3 -12
- package/src/Stages/Compositor.js +8 -23
- package/src/Stages/NRD.js +9 -2
- package/src/Stages/NormalDepth.js +9 -6
- package/src/Stages/PathTracer.js +254 -38
- package/src/Stages/PathTracerStage.js +11 -16
- 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 +2 -4
- package/src/Storage/areas.js +4 -0
- package/src/TSL/BVHTraversal.js +62 -24
- package/src/TSL/Bidirectional.js +204 -0
- package/src/TSL/BidirectionalLamps.js +132 -0
- package/src/TSL/Clearcoat.js +15 -6
- package/src/TSL/Common.js +19 -14
- package/src/TSL/ConnectKernel.js +147 -0
- package/src/TSL/Debugger.js +1 -1
- package/src/TSL/Displacement.js +4 -3
- package/src/TSL/EmissiveSampling.js +64 -17
- 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 +165 -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 +90 -38
- 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 +218 -0
- package/src/TSL/PathTracerCore.js +65 -29
- package/src/TSL/Random.js +4 -0
- package/src/TSL/SceneResources.js +51 -0
- package/src/TSL/ShadeKernel.js +881 -103
- package/src/TSL/Struct.js +10 -0
- package/src/TSL/Sun.js +1 -1
- package/src/TSL/TextureSampling.js +65 -60
- 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 +35 -0
- package/src/index.js +3 -1
- package/src/integrators/BidirectionalIntegrator.js +832 -0
- package/src/managers/EnvironmentManager.js +85 -33
- package/src/managers/MaterialDataManager.js +42 -0
- package/src/managers/UniformManager.js +0 -1
- package/dist/ToneMapGPU-DKQM1pMd.js +0 -552
- package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
- package/src/Processor/TreeletOptimizer.js +0 -574
|
@@ -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
|
+
}
|
|
@@ -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
|
|
|
@@ -1537,6 +1544,8 @@ export class GeometryExtractor {
|
|
|
1537
1544
|
this.iridescenceThicknessMaps = [];
|
|
1538
1545
|
this.specularIntensityMaps = [];
|
|
1539
1546
|
this.specularColorMaps = [];
|
|
1547
|
+
this.diffuseTransmissionMaps = [];
|
|
1548
|
+
this.diffuseTransmissionColorMaps = [];
|
|
1540
1549
|
this.directionalLights = [];
|
|
1541
1550
|
this.cameras = [];
|
|
1542
1551
|
|
|
@@ -1578,6 +1587,8 @@ export class GeometryExtractor {
|
|
|
1578
1587
|
iridescenceThicknessMaps: this.iridescenceThicknessMaps,
|
|
1579
1588
|
specularIntensityMaps: this.specularIntensityMaps,
|
|
1580
1589
|
specularColorMaps: this.specularColorMaps,
|
|
1590
|
+
diffuseTransmissionMaps: this.diffuseTransmissionMaps,
|
|
1591
|
+
diffuseTransmissionColorMaps: this.diffuseTransmissionColorMaps,
|
|
1581
1592
|
directionalLights: this.directionalLights,
|
|
1582
1593
|
cameras: this.cameras
|
|
1583
1594
|
};
|
|
@@ -125,19 +125,39 @@ export function parseIES( text, name = 'ies' ) {
|
|
|
125
125
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* The horizontal angle a type C profile stores for `hDeg` in [0, 360), by the symmetry its range implies
|
|
130
|
+
* (LM-63): one angle — the same all round; 0–90 — mirrored about the 0–180 and 90–270 planes; 0–180 — about the
|
|
131
|
+
* 0–180 plane; 90–270 — about the 90–270 plane; 0–360 — none.
|
|
132
|
+
*/
|
|
133
|
+
function storedHorizontalAngle( hDeg, hMin, hMax ) {
|
|
134
|
+
|
|
135
|
+
if ( hMin === 0 && hMax === 90 ) {
|
|
136
|
+
|
|
137
|
+
const half = hDeg % 180;
|
|
138
|
+
return half > 90 ? 180 - half : half;
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if ( hMin === 0 && hMax === 180 ) return hDeg > 180 ? 360 - hDeg : hDeg;
|
|
143
|
+
if ( hMin === 90 && hMax === 270 ) return hDeg >= 90 && hDeg <= 270 ? hDeg : ( ( 540 - hDeg ) % 360 );
|
|
144
|
+
return hDeg;
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
128
148
|
/**
|
|
129
149
|
* Resample an IESProfile onto a fixed-size 2D grid suitable for a
|
|
130
150
|
* DataArrayTexture layer. Values are normalised to [0,1] by `maxCandela`
|
|
131
151
|
* so the shader gets a pure shape multiplier; absolute intensity scaling
|
|
132
152
|
* stays in `light.intensity`.
|
|
133
153
|
*
|
|
134
|
-
* UV convention:
|
|
154
|
+
* UV convention (TSL/LightsCore.js sampleIESProfile reads it so):
|
|
135
155
|
* U = horizontal angle / 360 (0..1)
|
|
136
156
|
* V = vertical angle / 180 (0..1, 0 = bulb axis, 1 = opposite axis)
|
|
137
157
|
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
158
|
+
* The grid always spans the whole sphere: a downlight's 0–90° fills the lower half and leaves the upper dark, and
|
|
159
|
+
* a horizontal range with a symmetry is mirrored round (storedHorizontalAngle). Angles outside the file's range
|
|
160
|
+
* emit nothing. Type A and B profiles, whose angles mean something else, are stretched over the grid as before.
|
|
141
161
|
*
|
|
142
162
|
* @param {IESProfile} profile
|
|
143
163
|
* @param {number} width - texture width in samples (horizontal/U axis)
|
|
@@ -147,20 +167,34 @@ export function parseIES( text, name = 'ies' ) {
|
|
|
147
167
|
export function resampleIESToGrid( profile, width, height ) {
|
|
148
168
|
|
|
149
169
|
const data = new Uint8Array( width * height );
|
|
150
|
-
const { verticalAngles: vA, horizontalAngles: hA, candela, maxCandela } = profile;
|
|
170
|
+
const { verticalAngles: vA, horizontalAngles: hA, candela, maxCandela, photometricType } = profile;
|
|
151
171
|
|
|
152
172
|
if ( maxCandela <= 0 ) return data; // dead profile → zeros
|
|
153
173
|
|
|
154
|
-
const
|
|
155
|
-
const
|
|
174
|
+
const typeC = photometricType === undefined || photometricType === 1;
|
|
175
|
+
const vMin = vA[ 0 ];
|
|
176
|
+
const vMax = vA[ vA.length - 1 ];
|
|
156
177
|
const hMin = hA[ 0 ];
|
|
157
|
-
const
|
|
178
|
+
const hMax = hA[ hA.length - 1 ];
|
|
179
|
+
const rotationallySymmetric = hA.length === 1 || hMax === hMin;
|
|
180
|
+
|
|
181
|
+
const at = ( v0, v1, vt, hDeg ) => {
|
|
182
|
+
|
|
183
|
+
if ( rotationallySymmetric ) return lerp( candela[ v0 ][ 0 ], candela[ v1 ][ 0 ], vt );
|
|
184
|
+
if ( hDeg < hMin || hDeg > hMax ) return 0;
|
|
185
|
+
const h0 = lowerBoundIdx( hA, hDeg );
|
|
186
|
+
const h1 = Math.min( h0 + 1, hA.length - 1 );
|
|
187
|
+
const hSpan = hA[ h1 ] - hA[ h0 ];
|
|
188
|
+
const ht = hSpan > 0 ? ( hDeg - hA[ h0 ] ) / hSpan : 0;
|
|
189
|
+
return lerp( lerp( candela[ v0 ][ h0 ], candela[ v0 ][ h1 ], ht ), lerp( candela[ v1 ][ h0 ], candela[ v1 ][ h1 ], ht ), vt );
|
|
190
|
+
|
|
191
|
+
};
|
|
158
192
|
|
|
159
193
|
for ( let py = 0; py < height; py ++ ) {
|
|
160
194
|
|
|
161
|
-
// V coordinate → vertical angle in degrees. Texture covers [0, vMaxDeg].
|
|
162
195
|
const tV = ( py + 0.5 ) / height;
|
|
163
|
-
const vDeg = tV *
|
|
196
|
+
const vDeg = typeC ? tV * 180 : vMin + tV * ( vMax - vMin );
|
|
197
|
+
if ( vDeg < vMin || vDeg > vMax ) continue;
|
|
164
198
|
const v0 = lowerBoundIdx( vA, vDeg );
|
|
165
199
|
const v1 = Math.min( v0 + 1, vA.length - 1 );
|
|
166
200
|
const vSpan = vA[ v1 ] - vA[ v0 ];
|
|
@@ -168,31 +202,9 @@ export function resampleIESToGrid( profile, width, height ) {
|
|
|
168
202
|
|
|
169
203
|
for ( let px = 0; px < width; px ++ ) {
|
|
170
204
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// Single column → just bilerp on V axis.
|
|
176
|
-
cd = lerp( candela[ v0 ][ 0 ], candela[ v1 ][ 0 ], vt );
|
|
177
|
-
|
|
178
|
-
} else {
|
|
179
|
-
|
|
180
|
-
const tH = ( px + 0.5 ) / width;
|
|
181
|
-
const hDeg = hMin + tH * ( hMaxDeg - hMin );
|
|
182
|
-
const h0 = lowerBoundIdx( hA, hDeg );
|
|
183
|
-
const h1 = Math.min( h0 + 1, hA.length - 1 );
|
|
184
|
-
const hSpan = hA[ h1 ] - hA[ h0 ];
|
|
185
|
-
const ht = hSpan > 0 ? ( hDeg - hA[ h0 ] ) / hSpan : 0;
|
|
186
|
-
|
|
187
|
-
const c00 = candela[ v0 ][ h0 ];
|
|
188
|
-
const c10 = candela[ v0 ][ h1 ];
|
|
189
|
-
const c01 = candela[ v1 ][ h0 ];
|
|
190
|
-
const c11 = candela[ v1 ][ h1 ];
|
|
191
|
-
cd = lerp( lerp( c00, c10, ht ), lerp( c01, c11, ht ), vt );
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const norm = Math.min( 1, Math.max( 0, cd / maxCandela ) );
|
|
205
|
+
const tH = ( px + 0.5 ) / width;
|
|
206
|
+
const hDeg = typeC ? storedHorizontalAngle( tH * 360, hMin, hMax ) : hMin + tH * ( hMax - hMin );
|
|
207
|
+
const norm = Math.min( 1, Math.max( 0, at( v0, v1, vt, hDeg ) / maxCandela ) );
|
|
196
208
|
data[ py * width + px ] = Math.round( norm * 255 );
|
|
197
209
|
|
|
198
210
|
}
|
|
@@ -95,11 +95,44 @@ export class KernelManager {
|
|
|
95
95
|
* Register a pre-built compute node.
|
|
96
96
|
* @param {string} name - Kernel name (e.g. 'generate', 'extend')
|
|
97
97
|
* @param {ComputeNode} computeNode - Built via `Fn().compute([dx,dy,dz], [wgx,wgy,wgz])`
|
|
98
|
+
* @param {{eager?: boolean}} [options] - `eager: false` leaves it out of compile(): it compiles at its first dispatch
|
|
98
99
|
*/
|
|
99
|
-
register( name, computeNode ) {
|
|
100
|
+
register( name, computeNode, { eager = true } = {} ) {
|
|
100
101
|
|
|
101
102
|
this.kernels.set( name, computeNode );
|
|
102
|
-
this.timing.set( name, { compiledOnce: false, lastDispatchMs: 0 } );
|
|
103
|
+
this.timing.set( name, { compiledOnce: false, lastDispatchMs: 0, eager } );
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Whether compile() can run here: three yields between build steps through scheduler.yield or requestAnimationFrame,
|
|
109
|
+
* and Node has neither (nor a page to keep responsive).
|
|
110
|
+
*/
|
|
111
|
+
static get canCompileInBackground() {
|
|
112
|
+
|
|
113
|
+
return typeof globalThis.requestAnimationFrame === 'function' || typeof globalThis.scheduler?.yield === 'function';
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Compiles the eager kernels without blocking the page: three.js generates their WGSL in steps that yield and
|
|
119
|
+
* creates the GPU pipelines asynchronously. A dispatch after it compiles nothing.
|
|
120
|
+
* @returns {Promise<void>}
|
|
121
|
+
*/
|
|
122
|
+
async compile() {
|
|
123
|
+
|
|
124
|
+
const eager = [ ...this.kernels ].filter( ( [ name ] ) => this.timing.get( name )?.eager );
|
|
125
|
+
const t0 = performance.now();
|
|
126
|
+
// One call per kernel, all at once: the GPU compiles them side by side rather than each after the last.
|
|
127
|
+
await Promise.all( eager.map( ( [ , node ] ) => this.renderer.compileComputeAsync( node ) ) );
|
|
128
|
+
for ( const [ name ] of eager ) {
|
|
129
|
+
|
|
130
|
+
const entry = this.timing.get( name );
|
|
131
|
+
if ( entry ) entry.compiledOnce = true;
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
log.info( `${eager.length} kernels compiled in the background in ${fmt.ms( performance.now() - t0 )}` );
|
|
103
136
|
|
|
104
137
|
}
|
|
105
138
|
|
|
@@ -15,8 +15,7 @@ const TRANSFORMS = [
|
|
|
15
15
|
|
|
16
16
|
/** Floats no field writes; the packer gives them fixed values. */
|
|
17
17
|
export const MATERIAL_RESERVED_FLOATS = Object.freeze( [
|
|
18
|
-
M.VISIBLE, M.
|
|
19
|
-
M.SPECULAR_COLOR_MAP_INDEX + 1, M.SPECULAR_COLOR_MAP_INDEX + 2, M.SPECULAR_COLOR_MAP_INDEX + 3,
|
|
18
|
+
M.VISIBLE, M.DISPLACEMENT_MAP_INDEX + 1, M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 1, M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 2,
|
|
20
19
|
] );
|
|
21
20
|
|
|
22
21
|
/**
|
|
@@ -25,7 +24,7 @@ export const MATERIAL_RESERVED_FLOATS = Object.freeze( [
|
|
|
25
24
|
*/
|
|
26
25
|
export const UNIT_RANGE_PROPERTIES = Object.freeze( new Set( [
|
|
27
26
|
'metalness', 'roughness', 'transmission', 'opacity', 'clearcoat', 'clearcoatRoughness',
|
|
28
|
-
'sheen', 'sheenRoughness', 'specularIntensity', 'iridescence', 'subsurface', 'anisotropy',
|
|
27
|
+
'sheen', 'sheenRoughness', 'specularIntensity', 'iridescence', 'subsurface', 'anisotropy', 'diffuseTransmission',
|
|
29
28
|
] ) );
|
|
30
29
|
|
|
31
30
|
export const clampUnit = ( value ) => Math.min( Math.max( value, 0 ), 1 );
|
|
@@ -116,6 +115,7 @@ export function packMaterial( data, base, mat ) {
|
|
|
116
115
|
u( M.SHEEN_ROUGHNESS, mat.sheenRoughness, D.sheenRoughness );
|
|
117
116
|
|
|
118
117
|
writeTriple( data, base + M.SHEEN_COLOR, mat.sheenColor, D.sheenColor );
|
|
118
|
+
u( M.DIFFUSE_TRANSMISSION, mat.diffuseTransmission, D.diffuseTransmission );
|
|
119
119
|
|
|
120
120
|
u( M.SPECULAR_INTENSITY, mat.specularIntensity, D.specularIntensity );
|
|
121
121
|
writeTriple( data, base + M.SPECULAR_COLOR, mat.specularColor, D.specularColor );
|
|
@@ -157,12 +157,13 @@ export function packMaterial( data, base, mat ) {
|
|
|
157
157
|
data[ base + M.SPECULAR_INTENSITY_MAP_INDEX ] = mapIndex( mat.specularIntensityMap );
|
|
158
158
|
|
|
159
159
|
data[ base + M.SPECULAR_COLOR_MAP_INDEX ] = mapIndex( mat.specularColorMap );
|
|
160
|
+
writeTriple( data, base + M.DIFFUSE_TRANSMISSION_COLOR, mat.diffuseTransmissionColor, D.diffuseTransmissionColor );
|
|
161
|
+
data[ base + M.DIFFUSE_TRANSMISSION_MAP_INDEX ] = mapIndex( mat.diffuseTransmissionMap );
|
|
162
|
+
data[ base + M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX ] = mapIndex( mat.diffuseTransmissionColorMap );
|
|
160
163
|
|
|
161
164
|
data[ base + M.VISIBLE ] = 1;
|
|
162
|
-
data[ base + M.SHEEN_COLOR + 3 ] = 1;
|
|
163
165
|
data[ base + M.DISPLACEMENT_MAP_INDEX + 1 ] = 0;
|
|
164
|
-
data[ base + M.
|
|
165
|
-
data[ base + M.
|
|
166
|
-
data[ base + M.SPECULAR_COLOR_MAP_INDEX + 3 ] = 0;
|
|
166
|
+
data[ base + M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 1 ] = 0;
|
|
167
|
+
data[ base + M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 2 ] = 0;
|
|
167
168
|
|
|
168
169
|
}
|