rayzee 10.0.0 → 11.0.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-BRQvLggb.js +4300 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-9lZQxFVH.js +934 -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-BCXylThH.js} +8 -6
- package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-sZAeS142.js} +55 -120
- package/dist/PathTracer-CQPW06Mm.js +29971 -0
- package/dist/PhysicalSky-BvqCw_dy.js +1219 -0
- package/dist/RayzeeRenderer-COpwotpU.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-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 +2551 -44024
- package/dist/rayzee.umd.js +528 -487
- package/dist/sceneCachePolicy-BSSsKY98.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 +1 -1
- package/src/Processor/ArchiveImporter.js +1259 -0
- 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 +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 +39 -5
- package/src/Processor/ReinsertionOptimizer.js +2 -2
- 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 +3899 -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 +338 -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 +204 -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 +147 -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 +165 -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 +218 -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 +964 -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 +833 -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
|
@@ -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
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* denormalised one. World bounds and the inverse transform are derived on demand.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { TRIANGLE_DATA_LAYOUT, BVH_LEAF_MARKERS, assertBVHIndexFits, bvhIndexView } from './BufferLayout.js';
|
|
13
13
|
|
|
14
14
|
const IDENTITY = Float64Array.from( [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] );
|
|
15
15
|
|
|
@@ -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
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MATERIAL_DEFAULTS as D } from '../EngineDefaults.js';
|
|
2
|
+
import { MATERIAL_DATA_LAYOUT as M, normalizeAttenuationDistance } from './BufferLayout.js';
|
|
2
3
|
|
|
3
4
|
// The first 8 Matrix3 elements; the GPU rebuilds the 9th (always 1).
|
|
4
5
|
const IDENTITY_UV = [ 1, 0, 0, 0, 1, 0, 0, 0 ];
|
|
@@ -15,8 +16,7 @@ const TRANSFORMS = [
|
|
|
15
16
|
|
|
16
17
|
/** Floats no field writes; the packer gives them fixed values. */
|
|
17
18
|
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,
|
|
19
|
+
M.VISIBLE, M.DISPLACEMENT_MAP_INDEX + 1, M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 1, M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 2,
|
|
20
20
|
] );
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -25,7 +25,7 @@ export const MATERIAL_RESERVED_FLOATS = Object.freeze( [
|
|
|
25
25
|
*/
|
|
26
26
|
export const UNIT_RANGE_PROPERTIES = Object.freeze( new Set( [
|
|
27
27
|
'metalness', 'roughness', 'transmission', 'opacity', 'clearcoat', 'clearcoatRoughness',
|
|
28
|
-
'sheen', 'sheenRoughness', 'specularIntensity', 'iridescence', 'subsurface', 'anisotropy',
|
|
28
|
+
'sheen', 'sheenRoughness', 'specularIntensity', 'iridescence', 'subsurface', 'anisotropy', 'diffuseTransmission',
|
|
29
29
|
] ) );
|
|
30
30
|
|
|
31
31
|
export const clampUnit = ( value ) => Math.min( Math.max( value, 0 ), 1 );
|
|
@@ -116,6 +116,7 @@ export function packMaterial( data, base, mat ) {
|
|
|
116
116
|
u( M.SHEEN_ROUGHNESS, mat.sheenRoughness, D.sheenRoughness );
|
|
117
117
|
|
|
118
118
|
writeTriple( data, base + M.SHEEN_COLOR, mat.sheenColor, D.sheenColor );
|
|
119
|
+
u( M.DIFFUSE_TRANSMISSION, mat.diffuseTransmission, D.diffuseTransmission );
|
|
119
120
|
|
|
120
121
|
u( M.SPECULAR_INTENSITY, mat.specularIntensity, D.specularIntensity );
|
|
121
122
|
writeTriple( data, base + M.SPECULAR_COLOR, mat.specularColor, D.specularColor );
|
|
@@ -157,12 +158,13 @@ export function packMaterial( data, base, mat ) {
|
|
|
157
158
|
data[ base + M.SPECULAR_INTENSITY_MAP_INDEX ] = mapIndex( mat.specularIntensityMap );
|
|
158
159
|
|
|
159
160
|
data[ base + M.SPECULAR_COLOR_MAP_INDEX ] = mapIndex( mat.specularColorMap );
|
|
161
|
+
writeTriple( data, base + M.DIFFUSE_TRANSMISSION_COLOR, mat.diffuseTransmissionColor, D.diffuseTransmissionColor );
|
|
162
|
+
data[ base + M.DIFFUSE_TRANSMISSION_MAP_INDEX ] = mapIndex( mat.diffuseTransmissionMap );
|
|
163
|
+
data[ base + M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX ] = mapIndex( mat.diffuseTransmissionColorMap );
|
|
160
164
|
|
|
161
165
|
data[ base + M.VISIBLE ] = 1;
|
|
162
|
-
data[ base + M.SHEEN_COLOR + 3 ] = 1;
|
|
163
166
|
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;
|
|
167
|
+
data[ base + M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 1 ] = 0;
|
|
168
|
+
data[ base + M.DIFFUSE_TRANSMISSION_COLOR_MAP_INDEX + 2 ] = 0;
|
|
167
169
|
|
|
168
170
|
}
|
|
@@ -65,6 +65,13 @@ export function pString( params, name, dflt ) {
|
|
|
65
65
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
export function pBool( params, name, dflt ) {
|
|
69
|
+
|
|
70
|
+
const v = params[ name ]?.value?.[ 0 ];
|
|
71
|
+
return v === undefined ? dflt : v === true || v === 'true';
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
68
75
|
/**
|
|
69
76
|
* Resolve a spectrum/color/float-valued parameter to an RGB triple and/or a
|
|
70
77
|
* texture. Returns `{ rgb, texture }` — exactly one is typically non-null.
|
|
@@ -144,15 +151,74 @@ function namedMetalKey( s ) {
|
|
|
144
151
|
|
|
145
152
|
}
|
|
146
153
|
|
|
147
|
-
|
|
148
|
-
function
|
|
154
|
+
// A float parameter's value, or a float texture's mean (`ctx.floatTextureMean`); null when absent or unreadable.
|
|
155
|
+
async function floatOrMean( params, name, ctx ) {
|
|
156
|
+
|
|
157
|
+
const p = params[ name ];
|
|
158
|
+
if ( ! p ) return null;
|
|
159
|
+
if ( typeof p.value[ 0 ] === 'number' ) return p.value[ 0 ];
|
|
160
|
+
if ( p.type === 'texture' ) return ( await ctx.floatTextureMean?.( p.value[ 0 ] ) ) ?? null;
|
|
161
|
+
return null;
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The engine's roughness for pbrt's `roughness` or anisotropic `uroughness`/`vroughness` (their α averaged), under
|
|
167
|
+
* `prefix` for a layer (`conductor.`, `interface.`); a textured roughness counts as its mean. pbrt-v4 takes GGX
|
|
168
|
+
* α = √roughness (`remaproughness`, the default) or α = roughness; the engine's GGX takes α = roughness². Passing
|
|
169
|
+
* pbrt's number through made `remaproughness false` 0.1 an α of 0.01, a near mirror. `dflt` is the engine's.
|
|
170
|
+
*/
|
|
171
|
+
async function resolveRoughness( params, dflt, ctx, prefix = '' ) {
|
|
172
|
+
|
|
173
|
+
const remap = params.remaproughness?.value?.[ 0 ];
|
|
174
|
+
const alpha = ( r ) => ( remap === false || remap === 'false' ? r : Math.sqrt( Math.max( r, 0 ) ) );
|
|
175
|
+
let a = null;
|
|
176
|
+
const r = await floatOrMean( params, `${prefix}roughness`, ctx );
|
|
177
|
+
if ( r !== null ) a = alpha( r );
|
|
178
|
+
else {
|
|
179
|
+
|
|
180
|
+
const u = await floatOrMean( params, `${prefix}uroughness`, ctx );
|
|
181
|
+
const v = await floatOrMean( params, `${prefix}vroughness`, ctx );
|
|
182
|
+
if ( u !== null ) a = v !== null ? ( alpha( u ) + alpha( v ) ) / 2 : alpha( u );
|
|
183
|
+
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return a === null ? dflt : Math.sqrt( Math.max( a, 0 ) );
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// A conductor's colour: `reflectance`, else normal-incidence Fresnel of `eta`/`k` (under `prefix` for a coated
|
|
191
|
+
// conductor). pbrt's default is copper.
|
|
192
|
+
async function applyConductorColor( mat, params, ctx, prefix, applyAlbedo, setColor ) {
|
|
193
|
+
|
|
194
|
+
const refl = await resolveSpectrum( params, 'reflectance', ctx, null );
|
|
195
|
+
const etaP = params[ `${prefix}eta` ], kP = params[ `${prefix}k` ];
|
|
196
|
+
const etaNamed = etaP && etaP.type === 'spectrum' && typeof etaP.value[ 0 ] === 'string';
|
|
197
|
+
|
|
198
|
+
if ( refl.rgb || refl.texture ) {
|
|
199
|
+
|
|
200
|
+
applyAlbedo( refl );
|
|
201
|
+
|
|
202
|
+
} else if ( etaP && kP && ! etaNamed ) {
|
|
203
|
+
|
|
204
|
+
// Normal-incidence reflectance from complex IOR: ((η-1)²+k²)/((η+1)²+k²).
|
|
205
|
+
const eta = ( await resolveSpectrum( params, `${prefix}eta`, ctx, [ 0.2, 0.92, 1.1 ] ) ).rgb;
|
|
206
|
+
const k = ( await resolveSpectrum( params, `${prefix}k`, ctx, [ 3.9, 2.45, 2.14 ] ) ).rgb;
|
|
207
|
+
const fr = ( n, kk ) => ( ( n - 1 ) ** 2 + kk ** 2 ) / ( ( n + 1 ) ** 2 + kk ** 2 );
|
|
208
|
+
setColor( [ fr( eta[ 0 ], k[ 0 ] ), fr( eta[ 1 ], k[ 1 ] ), fr( eta[ 2 ], k[ 2 ] ) ] );
|
|
209
|
+
|
|
210
|
+
} else if ( etaP ) {
|
|
149
211
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
212
|
+
// Named conductor spectrum → metal albedo table.
|
|
213
|
+
setColor( ( await resolveSpectrum( params, `${prefix}eta`, ctx, DEFAULT_METAL ) ).rgb || DEFAULT_METAL );
|
|
214
|
+
|
|
215
|
+
} else {
|
|
216
|
+
|
|
217
|
+
setColor( METAL_ALBEDO.cu ); // pbrt-v4 default conductor is copper
|
|
218
|
+
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
mat.metalness = 1;
|
|
156
222
|
|
|
157
223
|
}
|
|
158
224
|
|
|
@@ -193,9 +259,11 @@ export async function buildMaterial( def, ctx ) {
|
|
|
193
259
|
|
|
194
260
|
case 'diffuse': {
|
|
195
261
|
|
|
262
|
+
// Lambertian: no dielectric specular layer, which MeshPhysicalMaterial has by default.
|
|
196
263
|
applyAlbedo( await resolveSpectrum( params, 'reflectance', ctx, [ 0.5, 0.5, 0.5 ] ) );
|
|
197
264
|
mat.roughness = 1;
|
|
198
265
|
mat.metalness = 0;
|
|
266
|
+
mat.specularIntensity = 0;
|
|
199
267
|
break;
|
|
200
268
|
|
|
201
269
|
}
|
|
@@ -203,35 +271,19 @@ export async function buildMaterial( def, ctx ) {
|
|
|
203
271
|
case 'conductor':
|
|
204
272
|
case 'metal': {
|
|
205
273
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if ( refl.rgb || refl.texture ) {
|
|
211
|
-
|
|
212
|
-
applyAlbedo( refl );
|
|
213
|
-
|
|
214
|
-
} else if ( etaP && kP && ! etaNamed ) {
|
|
215
|
-
|
|
216
|
-
// Normal-incidence reflectance from complex IOR: ((η-1)²+k²)/((η+1)²+k²).
|
|
217
|
-
const eta = ( await resolveSpectrum( params, 'eta', ctx, [ 0.2, 0.92, 1.1 ] ) ).rgb;
|
|
218
|
-
const k = ( await resolveSpectrum( params, 'k', ctx, [ 3.9, 2.45, 2.14 ] ) ).rgb;
|
|
219
|
-
const fr = ( n, kk ) => ( ( n - 1 ) ** 2 + kk ** 2 ) / ( ( n + 1 ) ** 2 + kk ** 2 );
|
|
220
|
-
setColor( [ fr( eta[ 0 ], k[ 0 ] ), fr( eta[ 1 ], k[ 1 ] ), fr( eta[ 2 ], k[ 2 ] ) ] );
|
|
221
|
-
|
|
222
|
-
} else if ( etaP ) {
|
|
223
|
-
|
|
224
|
-
// Named conductor spectrum → metal albedo table.
|
|
225
|
-
setColor( ( await resolveSpectrum( params, 'eta', ctx, DEFAULT_METAL ) ).rgb || DEFAULT_METAL );
|
|
226
|
-
|
|
227
|
-
} else {
|
|
274
|
+
await applyConductorColor( mat, params, ctx, '', applyAlbedo, setColor );
|
|
275
|
+
mat.roughness = await resolveRoughness( params, 0.1, ctx );
|
|
276
|
+
break;
|
|
228
277
|
|
|
229
|
-
|
|
278
|
+
}
|
|
230
279
|
|
|
231
|
-
|
|
280
|
+
case 'coatedconductor': {
|
|
232
281
|
|
|
233
|
-
|
|
234
|
-
|
|
282
|
+
// A conductor under a dielectric coat; pbrt's roughnesses default to 0 for both.
|
|
283
|
+
await applyConductorColor( mat, params, ctx, 'conductor.', applyAlbedo, setColor );
|
|
284
|
+
mat.roughness = await resolveRoughness( params, 0, ctx, 'conductor.' );
|
|
285
|
+
mat.clearcoat = 1;
|
|
286
|
+
mat.clearcoatRoughness = await resolveRoughness( params, 0, ctx, 'interface.' );
|
|
235
287
|
break;
|
|
236
288
|
|
|
237
289
|
}
|
|
@@ -243,7 +295,7 @@ export async function buildMaterial( def, ctx ) {
|
|
|
243
295
|
mat.metalness = 0;
|
|
244
296
|
mat.color.setRGB( 1, 1, 1 );
|
|
245
297
|
mat.ior = pFloat( params, 'eta', 1.5 );
|
|
246
|
-
mat.roughness = resolveRoughness( params, 0 );
|
|
298
|
+
mat.roughness = await resolveRoughness( params, 0, ctx );
|
|
247
299
|
mat.thickness = type === 'thindielectric' ? 0 : pFloat( params, 'thickness', 0 );
|
|
248
300
|
break;
|
|
249
301
|
|
|
@@ -255,18 +307,30 @@ export async function buildMaterial( def, ctx ) {
|
|
|
255
307
|
mat.roughness = 0.6;
|
|
256
308
|
mat.metalness = 0;
|
|
257
309
|
mat.clearcoat = 1;
|
|
258
|
-
mat.clearcoatRoughness = resolveRoughness( params, 0 );
|
|
310
|
+
mat.clearcoatRoughness = await resolveRoughness( params, 0, ctx );
|
|
259
311
|
break;
|
|
260
312
|
|
|
261
313
|
}
|
|
262
314
|
|
|
263
315
|
case 'diffusetransmission': {
|
|
264
316
|
|
|
317
|
+
// pbrt reflects R and transmits T, both diffusely and both × `scale`, clamped to [0, 1]; no specular layer.
|
|
318
|
+
// The engine splits its diffuse lobe by `diffuseTransmission`: reflecting (1 − dt) · base, transmitting
|
|
319
|
+
// dt · colour. dt = max(T) makes both exact whenever max(R) + max(T) ≤ 1.
|
|
320
|
+
const scale = pFloat( params, 'scale', 1 );
|
|
321
|
+
const unit = ( v ) => Math.min( 1, Math.max( 0, scale * v ) );
|
|
265
322
|
const trans = await resolveSpectrum( params, 'transmittance', ctx, [ 0.25, 0.25, 0.25 ] );
|
|
266
|
-
|
|
267
|
-
|
|
323
|
+
const T = trans.rgb ? trans.rgb.map( unit ) : [ 0.5, 0.5, 0.5 ];
|
|
324
|
+
const dt = Math.min( 0.99, Math.max( ...T ) );
|
|
325
|
+
const refl = await resolveSpectrum( params, 'reflectance', ctx, [ 0.25, 0.25, 0.25 ] );
|
|
326
|
+
const base = ( v ) => Math.min( 1, unit( v ) / ( 1 - dt ) );
|
|
327
|
+
applyAlbedo( { texture: refl.texture, rgb: refl.rgb ? refl.rgb.map( base ) : ( refl.texture ? [ 1, 1, 1 ].map( base ) : null ) } );
|
|
328
|
+
if ( trans.texture ) ctx.warn( 'diffusetransmission: a textured "transmittance" is not supported — using 0.5' );
|
|
329
|
+
mat.diffuseTransmission = dt;
|
|
330
|
+
mat.diffuseTransmissionColor = new Color().setRGB( ...T.map( ( v ) => ( dt > 0 ? Math.min( 1, v / dt ) : 1 ) ) );
|
|
268
331
|
mat.roughness = 1;
|
|
269
|
-
mat.
|
|
332
|
+
mat.metalness = 0;
|
|
333
|
+
mat.specularIntensity = 0;
|
|
270
334
|
break;
|
|
271
335
|
|
|
272
336
|
}
|
|
@@ -292,13 +356,18 @@ export async function buildMaterial( def, ctx ) {
|
|
|
292
356
|
// instead of warning per shape. Recursive: mix-in-mix terminates as the
|
|
293
357
|
// chain bottoms out at a non-mix.
|
|
294
358
|
const matNames = params.materials?.value || [];
|
|
295
|
-
|
|
359
|
+
let t = Math.max( 0, Math.min( 1, pFloat( params, 'amount', 0.5 ) ) );
|
|
296
360
|
const defA = matNames[ 0 ] ? ctx.namedMaterials?.get( matNames[ 0 ] ) : null;
|
|
297
361
|
const defB = matNames[ 1 ] ? ctx.namedMaterials?.get( matNames[ 1 ] ) : null;
|
|
298
362
|
|
|
299
363
|
if ( defA && defB ) {
|
|
300
364
|
|
|
301
365
|
const [ matA, matB ] = await Promise.all( [ buildMaterial( defA, ctx ), buildMaterial( defB, ctx ) ] );
|
|
366
|
+
// pbrt picks the second material where a texture amount says so; its colours are baked by that
|
|
367
|
+
// texture (`ctx.bakeMaterialMix`) and the rest is weighed by the texture's mean.
|
|
368
|
+
const amountP = params.amount;
|
|
369
|
+
const baked = amountP?.type === 'texture' ? await ctx.bakeMaterialMix?.( matA, matB, amountP.value[ 0 ] ) : null;
|
|
370
|
+
if ( baked ) t = baked.mean;
|
|
302
371
|
const lerp = ( a, b ) => a * ( 1 - t ) + b * t;
|
|
303
372
|
mat.color.lerpColors( matA.color, matB.color, t );
|
|
304
373
|
mat.roughness = lerp( matA.roughness, matB.roughness );
|
|
@@ -309,9 +378,25 @@ export async function buildMaterial( def, ctx ) {
|
|
|
309
378
|
mat.clearcoat = lerp( matA.clearcoat ?? 0, matB.clearcoat ?? 0 );
|
|
310
379
|
mat.clearcoatRoughness = lerp( matA.clearcoatRoughness ?? 0, matB.clearcoatRoughness ?? 0 );
|
|
311
380
|
mat.emissive.lerpColors( matA.emissive, matB.emissive, t );
|
|
381
|
+
const dtA = matA.diffuseTransmission ?? 0, dtB = matB.diffuseTransmission ?? 0;
|
|
382
|
+
if ( dtA > 0 || dtB > 0 ) {
|
|
383
|
+
|
|
384
|
+
mat.diffuseTransmission = lerp( dtA, dtB );
|
|
385
|
+
mat.diffuseTransmissionColor = new Color().lerpColors( matA.diffuseTransmissionColor ?? new Color( 1, 1, 1 ), matB.diffuseTransmissionColor ?? new Color( 1, 1, 1 ), t );
|
|
386
|
+
|
|
387
|
+
}
|
|
388
|
+
|
|
312
389
|
mat.emissiveIntensity = lerp( matA.emissiveIntensity ?? 0, matB.emissiveIntensity ?? 0 );
|
|
313
|
-
// Maps can't be lerped — pick the dominant side.
|
|
390
|
+
// Maps can't be lerped — pick the dominant side, unless the amount's own texture baked them together.
|
|
314
391
|
mat.map = ( t < 0.5 ? matA.map : matB.map ) || null;
|
|
392
|
+
mat.normalMap = ( t < 0.5 ? matA.normalMap : matB.normalMap ) || null;
|
|
393
|
+
if ( baked?.texture ) {
|
|
394
|
+
|
|
395
|
+
mat.map = baked.texture;
|
|
396
|
+
mat.color.setRGB( 1, 1, 1 );
|
|
397
|
+
|
|
398
|
+
}
|
|
399
|
+
|
|
315
400
|
break;
|
|
316
401
|
|
|
317
402
|
}
|
|
@@ -344,6 +429,9 @@ export async function buildMaterial( def, ctx ) {
|
|
|
344
429
|
|
|
345
430
|
}
|
|
346
431
|
|
|
432
|
+
const normalMap = pString( params, 'normalmap', null );
|
|
433
|
+
if ( normalMap && ctx.resolveNormalMap ) mat.normalMap = await ctx.resolveNormalMap( normalMap );
|
|
434
|
+
|
|
347
435
|
mat.roughness = Math.max( 0, Math.min( 1, mat.roughness ) );
|
|
348
436
|
return mat;
|
|
349
437
|
|
|
@@ -111,6 +111,7 @@ export class PBRTParser {
|
|
|
111
111
|
instanceCount: 0,
|
|
112
112
|
skippedInstances: 0,
|
|
113
113
|
objects: new Map(),
|
|
114
|
+
media: new Map(),
|
|
114
115
|
transformTimes: { start: 0, end: 1 },
|
|
115
116
|
hasMotion: false,
|
|
116
117
|
warnings: []
|
|
@@ -122,14 +123,13 @@ export class PBRTParser {
|
|
|
122
123
|
this.activeTransform = BOTH;
|
|
123
124
|
this._ctmSource = null;
|
|
124
125
|
this._ctmValue = null;
|
|
125
|
-
this.state = { material: null, areaLight: null, reverseOrientation: false };
|
|
126
|
+
this.state = { material: null, areaLight: null, reverseOrientation: false, interior: null };
|
|
126
127
|
this.attributeStack = [];
|
|
127
128
|
this.transformStack = [];
|
|
128
129
|
this.coordSystems = new Map();
|
|
129
130
|
|
|
130
131
|
// Object capture (ObjectBegin/End)
|
|
131
132
|
this.currentObject = null; // name being captured, or null
|
|
132
|
-
this.objectBeginCTM = null; // CTM frame at ObjectBegin
|
|
133
133
|
|
|
134
134
|
// Directory stack for resolving nested Includes
|
|
135
135
|
this.dirStack = [ '' ];
|
|
@@ -275,7 +275,8 @@ export class PBRTParser {
|
|
|
275
275
|
activeTransform: this.activeTransform,
|
|
276
276
|
material: this.state.material,
|
|
277
277
|
areaLight: this.state.areaLight,
|
|
278
|
-
reverseOrientation: this.state.reverseOrientation
|
|
278
|
+
reverseOrientation: this.state.reverseOrientation,
|
|
279
|
+
interior: this.state.interior
|
|
279
280
|
} );
|
|
280
281
|
|
|
281
282
|
}
|
|
@@ -287,7 +288,7 @@ export class PBRTParser {
|
|
|
287
288
|
this.ctm = s.ctm;
|
|
288
289
|
this.ctmEnd = s.ctmEnd;
|
|
289
290
|
this.activeTransform = s.activeTransform;
|
|
290
|
-
this.state = { material: s.material, areaLight: s.areaLight, reverseOrientation: s.reverseOrientation };
|
|
291
|
+
this.state = { material: s.material, areaLight: s.areaLight, reverseOrientation: s.reverseOrientation, interior: s.interior };
|
|
291
292
|
|
|
292
293
|
}
|
|
293
294
|
|
|
@@ -624,7 +625,7 @@ export class PBRTParser {
|
|
|
624
625
|
this.ctm = M.identity();
|
|
625
626
|
this.ctmEnd = null;
|
|
626
627
|
this.activeTransform = BOTH;
|
|
627
|
-
this.state = { material: null, areaLight: null, reverseOrientation: false };
|
|
628
|
+
this.state = { material: null, areaLight: null, reverseOrientation: false, interior: null };
|
|
628
629
|
break;
|
|
629
630
|
case 'WorldEnd': break; // legacy v3
|
|
630
631
|
|
|
@@ -673,14 +674,21 @@ export class PBRTParser {
|
|
|
673
674
|
|
|
674
675
|
case 'MediumInterface': {
|
|
675
676
|
|
|
676
|
-
//
|
|
677
|
-
|
|
678
|
-
if ( this._peek()
|
|
677
|
+
// "interior" "exterior"; a single name is both. Only the interior colours a shape.
|
|
678
|
+
const interior = this._peek()?.type === TokenType.STRING ? this._next().value : '';
|
|
679
|
+
if ( this._peek()?.type === TokenType.STRING ) this._next();
|
|
680
|
+
this.state.interior = interior || null;
|
|
679
681
|
break;
|
|
680
682
|
|
|
681
683
|
}
|
|
682
684
|
|
|
683
|
-
case 'MakeNamedMedium':
|
|
685
|
+
case 'MakeNamedMedium': {
|
|
686
|
+
|
|
687
|
+
const mediumName = this._expectString( 'MakeNamedMedium name' );
|
|
688
|
+
this.ir.media.set( mediumName, this._parseParams() );
|
|
689
|
+
break;
|
|
690
|
+
|
|
691
|
+
}
|
|
684
692
|
|
|
685
693
|
// ── materials ──
|
|
686
694
|
case 'Material': {
|
|
@@ -748,13 +756,18 @@ export class PBRTParser {
|
|
|
748
756
|
|
|
749
757
|
const type = this._expectString( 'Shape type' );
|
|
750
758
|
const params = this._parseParams();
|
|
759
|
+
// pbrt: a shape of alpha 0 is never hit, and an area light on it emits nothing.
|
|
760
|
+
const alpha = params.alpha;
|
|
761
|
+
if ( alpha?.type === 'float' && alpha.value[ 0 ] <= 0 ) break;
|
|
762
|
+
if ( alpha && ! ( alpha.type === 'float' && alpha.value[ 0 ] >= 1 ) ) this._warnOnce( 'alpha', 'shape "alpha" between 0 and 1, or as a texture, is not supported — drawn opaque' );
|
|
751
763
|
const shape = {
|
|
752
764
|
type,
|
|
753
765
|
params,
|
|
754
766
|
ctm: this._ctmSnapshot(),
|
|
755
767
|
material: this.state.material,
|
|
756
768
|
areaLight: this.state.areaLight,
|
|
757
|
-
reverseOrientation: this.state.reverseOrientation
|
|
769
|
+
reverseOrientation: this.state.reverseOrientation,
|
|
770
|
+
interior: this.state.interior
|
|
758
771
|
};
|
|
759
772
|
const end = this.currentObject === null ? this._ctmEndSnapshot() : null;
|
|
760
773
|
if ( end ) shape.ctmEnd = end;
|
|
@@ -776,7 +789,6 @@ export class PBRTParser {
|
|
|
776
789
|
// pbrt implicitly pushes graphics state.
|
|
777
790
|
this._pushGraphicsState();
|
|
778
791
|
this.currentObject = objName;
|
|
779
|
-
this.objectBeginCTM = this.ctm.slice();
|
|
780
792
|
if ( ! this.ir.objects.has( objName ) ) this.ir.objects.set( objName, [] );
|
|
781
793
|
break;
|
|
782
794
|
|
|
@@ -785,7 +797,6 @@ export class PBRTParser {
|
|
|
785
797
|
case 'ObjectEnd': {
|
|
786
798
|
|
|
787
799
|
this.currentObject = null;
|
|
788
|
-
this.objectBeginCTM = null;
|
|
789
800
|
this._popGraphicsState();
|
|
790
801
|
break;
|
|
791
802
|
|
|
@@ -824,8 +835,8 @@ export class PBRTParser {
|
|
|
824
835
|
|
|
825
836
|
if ( this.currentObject !== null ) {
|
|
826
837
|
|
|
827
|
-
//
|
|
828
|
-
|
|
838
|
+
// pbrt keeps a template shape's whole transform and puts each placement's on top of it,
|
|
839
|
+
// whatever the transform was at ObjectBegin (kroken defines under one and places at Identity).
|
|
829
840
|
this.ir.objects.get( this.currentObject ).push( shape );
|
|
830
841
|
|
|
831
842
|
} else {
|
|
@@ -880,7 +891,7 @@ export class PBRTParser {
|
|
|
880
891
|
|
|
881
892
|
if ( ! this.instanceIncludes || this.currentObject !== null ) return null;
|
|
882
893
|
if ( this.ctmEnd !== null || this.activeTransform !== BOTH || this.state.areaLight ) return null;
|
|
883
|
-
return `${dir}\0${path}\0${this._stateId( this.state.material )}\0${this.state.reverseOrientation}`;
|
|
894
|
+
return `${dir}\0${path}\0${this._stateId( this.state.material )}\0${this.state.reverseOrientation}\0${this.state.interior}`;
|
|
884
895
|
|
|
885
896
|
}
|
|
886
897
|
|
|
@@ -902,7 +913,8 @@ export class PBRTParser {
|
|
|
902
913
|
attributes: this.attributeStack.length,
|
|
903
914
|
transforms: this.transformStack.length,
|
|
904
915
|
material: this.state.material,
|
|
905
|
-
reverseOrientation: this.state.reverseOrientation
|
|
916
|
+
reverseOrientation: this.state.reverseOrientation,
|
|
917
|
+
interior: this.state.interior
|
|
906
918
|
};
|
|
907
919
|
|
|
908
920
|
}
|
|
@@ -912,7 +924,8 @@ export class PBRTParser {
|
|
|
912
924
|
return this._effects === before.effects && this.ctmEnd === null && this.activeTransform === BOTH &&
|
|
913
925
|
sameMatrix( this.ctm, before.ctm ) && this.attributeStack.length === before.attributes &&
|
|
914
926
|
this.transformStack.length === before.transforms && this.state.material === before.material &&
|
|
915
|
-
this.state.areaLight === null && this.state.reverseOrientation === before.reverseOrientation
|
|
927
|
+
this.state.areaLight === null && this.state.reverseOrientation === before.reverseOrientation &&
|
|
928
|
+
this.state.interior === before.interior;
|
|
916
929
|
|
|
917
930
|
}
|
|
918
931
|
|