rayzee 7.22.9 → 7.23.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/dist/rayzee.es.js +1467 -1450
- package/dist/rayzee.umd.js +51 -53
- package/package.json +1 -1
- package/src/EngineDefaults.js +5 -0
- package/src/PathTracerApp.js +12 -0
- package/src/Processor/GeometryExtractor.js +5 -13
- package/src/Processor/TextureCreator.js +2 -2
- package/src/TSL/MaterialTransmission.js +4 -45
- package/src/managers/MaterialDataManager.js +51 -3
package/package.json
CHANGED
package/src/EngineDefaults.js
CHANGED
|
@@ -524,6 +524,11 @@ export const MATERIAL_DATA_LAYOUT = {
|
|
|
524
524
|
|
|
525
525
|
};
|
|
526
526
|
|
|
527
|
+
// glTF/three.js spell "no volume absorption" as attenuationDistance = Infinity, while the GPU
|
|
528
|
+
// contract is `> 0 = on` (calculateBeerLawAbsorption). Every writer into ATTENUATION_DISTANCE
|
|
529
|
+
// collapses both spellings to 0 so no shader divides by Inf.
|
|
530
|
+
export const normalizeAttenuationDistance = d => ( Number.isFinite( d ) && d > 0 ? d : 0 );
|
|
531
|
+
|
|
527
532
|
// BVH node leaf markers
|
|
528
533
|
export const BVH_LEAF_MARKERS = {
|
|
529
534
|
TRIANGLE_LEAF: - 1, // Leaf containing triangle references
|
package/src/PathTracerApp.js
CHANGED
|
@@ -2104,6 +2104,18 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
2104
2104
|
|
|
2105
2105
|
}
|
|
2106
2106
|
|
|
2107
|
+
/**
|
|
2108
|
+
* Read back the scalar material property the shader is actually using.
|
|
2109
|
+
* @param {number} materialIndex
|
|
2110
|
+
* @param {string} property
|
|
2111
|
+
* @returns {number|undefined}
|
|
2112
|
+
*/
|
|
2113
|
+
getMaterialProperty( materialIndex, property ) {
|
|
2114
|
+
|
|
2115
|
+
return this.stages.pathTracer?.materialData.getMaterialProperty( materialIndex, property );
|
|
2116
|
+
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2107
2119
|
setMaterialProperty( materialIndex, property, value ) {
|
|
2108
2120
|
|
|
2109
2121
|
this.stages.pathTracer?.materialData.updateMaterialProperty( materialIndex, property, value );
|
|
@@ -373,20 +373,12 @@ export class GeometryExtractor {
|
|
|
373
373
|
const materialType = this.getMaterialType( material );
|
|
374
374
|
const legacyMapping = this.mapLegacyMaterialToPhysical( material, materialType );
|
|
375
375
|
|
|
376
|
-
//
|
|
376
|
+
// A transmissive surface is a dielectric interface whose IOR drives refraction, so it wins
|
|
377
|
+
// over the metal Fresnel hack: glTF defaults metallicFactor to 1, which otherwise stamps
|
|
378
|
+
// 2.5 onto water/glass authored as MeshStandardMaterial.
|
|
379
|
+
const isTransmissive = ( material.transmission ?? 0.0 ) > 0.0;
|
|
377
380
|
const isMetallic = ( material.metalness ?? legacyMapping.metalness ?? 0.0 ) > 0.1;
|
|
378
|
-
|
|
379
|
-
// Set appropriate IOR based on material type
|
|
380
|
-
let defaultIOR = defaults.ior;
|
|
381
|
-
if ( isMetallic ) {
|
|
382
|
-
|
|
383
|
-
defaultIOR = 2.5; // Typical metallic IOR
|
|
384
|
-
|
|
385
|
-
} else if ( material.transmission > 0.0 ) {
|
|
386
|
-
|
|
387
|
-
defaultIOR = 1.5; // Glass-like for transmissive materials
|
|
388
|
-
|
|
389
|
-
}
|
|
381
|
+
const defaultIOR = ( isMetallic && ! isTransmissive ) ? 2.5 : defaults.ior;
|
|
390
382
|
|
|
391
383
|
// Handle color conversion for different material types
|
|
392
384
|
let baseColor = material.color || new Color( 0xffffff );
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DataArrayTexture, RGBAFormat, LinearFilter, UnsignedByteType, SRGBColorSpace, RepeatWrapping } from "three";
|
|
2
|
-
import { TEXTURE_CONSTANTS, MEMORY_CONSTANTS, DEFAULT_TEXTURE_MATRIX, MATERIAL_DATA_LAYOUT } from '../EngineDefaults.js';
|
|
2
|
+
import { TEXTURE_CONSTANTS, MEMORY_CONSTANTS, DEFAULT_TEXTURE_MATRIX, MATERIAL_DATA_LAYOUT, normalizeAttenuationDistance } from '../EngineDefaults.js';
|
|
3
3
|
import TexturesWorker from './Workers/TexturesWorker.js?worker&inline';
|
|
4
4
|
|
|
5
5
|
// Canvas pooling for efficient reuse of canvas elements
|
|
@@ -948,7 +948,7 @@ export class TextureCreator {
|
|
|
948
948
|
// Slot 0: shadow core (ior, transmission, thickness, emissiveIntensity)
|
|
949
949
|
mat.ior, mat.transmission, mat.thickness, mat.emissiveIntensity,
|
|
950
950
|
// Slot 1: shadow (attenuationColor, attenuationDistance)
|
|
951
|
-
mat.attenuationColor.r, mat.attenuationColor.g, mat.attenuationColor.b, mat.attenuationDistance,
|
|
951
|
+
mat.attenuationColor.r, mat.attenuationColor.g, mat.attenuationColor.b, normalizeAttenuationDistance( mat.attenuationDistance ),
|
|
952
952
|
// Slot 2: shadow + culling (opacity, side, transparent, alphaTest)
|
|
953
953
|
mat.opacity, mat.side, mat.transparent, mat.alphaTest,
|
|
954
954
|
// Slot 3: shadow (alphaMode, depthWrite, normalScale)
|
|
@@ -141,57 +141,16 @@ export const sampleWavelengthForDispersion = Fn( ( [ baseIOR, dispersionStrength
|
|
|
141
141
|
// ABSORPTION
|
|
142
142
|
// ================================================================================
|
|
143
143
|
|
|
144
|
-
//
|
|
144
|
+
// Beer-Lambert transmittance over pathLength. attenuationDistance <= 0 (or non-finite,
|
|
145
|
+
// normalized to 0 by MaterialDataManager) means "no absorption".
|
|
145
146
|
export const calculateBeerLawAbsorption = /*@__PURE__*/ wgslFn( `
|
|
146
|
-
fn calculateBeerLawAbsorption( attenuationColor: vec3f, attenuationDistance: f32,
|
|
147
|
+
fn calculateBeerLawAbsorption( attenuationColor: vec3f, attenuationDistance: f32, pathLength: f32 ) -> vec3f {
|
|
147
148
|
if ( attenuationDistance <= 0.0f ) { return vec3f( 1.0f ); }
|
|
148
|
-
// Convert RGB attenuation color to absorption coefficients
|
|
149
149
|
let absorption = -log( max( attenuationColor, vec3f( 0.001f ) ) ) / attenuationDistance;
|
|
150
|
-
|
|
151
|
-
return exp( -absorption * thickness );
|
|
150
|
+
return exp( -absorption * pathLength );
|
|
152
151
|
}
|
|
153
152
|
` );
|
|
154
153
|
|
|
155
|
-
// ================================================================================
|
|
156
|
-
// SHADOW TRANSMITTANCE
|
|
157
|
-
// ================================================================================
|
|
158
|
-
|
|
159
|
-
export const calculateShadowTransmittance = Fn( ( [ rayDir, normal, material, entering ] ) => {
|
|
160
|
-
|
|
161
|
-
const n1 = select( entering, float( 1.0 ), material.ior ).toVar();
|
|
162
|
-
const n2 = select( entering, material.ior, float( 1.0 ) ).toVar();
|
|
163
|
-
|
|
164
|
-
const cosThetaI = abs( dot( normal, rayDir ) );
|
|
165
|
-
const sinThetaT2 = n1.mul( n1 ).div( n2.mul( n2 ) ).mul( float( 1.0 ).sub( cosThetaI.mul( cosThetaI ) ) );
|
|
166
|
-
|
|
167
|
-
// Handle total internal reflection
|
|
168
|
-
const result = float( 0.0 ).toVar();
|
|
169
|
-
|
|
170
|
-
If( sinThetaT2.lessThanEqual( 1.0 ), () => {
|
|
171
|
-
|
|
172
|
-
// Calculate Fresnel reflectance
|
|
173
|
-
const F0 = iorToFresnel0( n2, n1 );
|
|
174
|
-
const Fr = fresnelSchlickFloat( cosThetaI, F0 );
|
|
175
|
-
|
|
176
|
-
// Base transmission: what gets through after Fresnel reflection
|
|
177
|
-
const baseTransmission = float( 1.0 ).sub( Fr ).mul( material.transmission ).toVar();
|
|
178
|
-
|
|
179
|
-
// Apply Beer's law absorption for exiting rays
|
|
180
|
-
If( entering.not().and( material.attenuationDistance.greaterThan( 0.0 ) ), () => {
|
|
181
|
-
|
|
182
|
-
const absorption = calculateBeerLawAbsorption( { attenuationColor: material.attenuationColor, attenuationDistance: material.attenuationDistance, thickness: material.thickness } );
|
|
183
|
-
baseTransmission.assign( baseTransmission.mul( absorption.x.add( absorption.y ).add( absorption.z ).div( 3.0 ) ) );
|
|
184
|
-
|
|
185
|
-
} );
|
|
186
|
-
|
|
187
|
-
result.assign( clamp( baseTransmission, 0.0, 1.0 ) );
|
|
188
|
-
|
|
189
|
-
} );
|
|
190
|
-
|
|
191
|
-
return result;
|
|
192
|
-
|
|
193
|
-
} );
|
|
194
|
-
|
|
195
154
|
// ================================================================================
|
|
196
155
|
// MICROFACET TRANSMISSION
|
|
197
156
|
// ================================================================================
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { StorageInstancedBufferAttribute } from 'three/webgpu';
|
|
11
11
|
import { storage } from 'three/tsl';
|
|
12
|
-
import { MATERIAL_DATA_LAYOUT as M, TRIANGLE_DATA_LAYOUT as T } from '../EngineDefaults.js';
|
|
12
|
+
import { MATERIAL_DATA_LAYOUT as M, TRIANGLE_DATA_LAYOUT as T, normalizeAttenuationDistance } from '../EngineDefaults.js';
|
|
13
13
|
import { createLogger, fmt } from '../utils/Logger.js';
|
|
14
14
|
|
|
15
15
|
const log = createLogger( 'material' );
|
|
@@ -23,6 +23,32 @@ const TRI_BLOCKER_OFFSET = T.NORMAL_A_OFFSET + 3; // nA.w in shader (opaque-bloc
|
|
|
23
23
|
// Material properties that affect the shadow-ray opaque-blocker flag.
|
|
24
24
|
const BLOCKER_PROPS = new Set( [ 'transmission', 'transparent', 'opacity', 'alphaMode' ] );
|
|
25
25
|
|
|
26
|
+
// Scalar slots readable via getMaterialProperty().
|
|
27
|
+
const SCALAR_PROPERTY_OFFSETS = {
|
|
28
|
+
ior: M.IOR,
|
|
29
|
+
transmission: M.TRANSMISSION,
|
|
30
|
+
thickness: M.THICKNESS,
|
|
31
|
+
emissiveIntensity: M.EMISSIVE_INTENSITY,
|
|
32
|
+
attenuationDistance: M.ATTENUATION_DISTANCE,
|
|
33
|
+
opacity: M.OPACITY,
|
|
34
|
+
alphaTest: M.ALPHA_TEST,
|
|
35
|
+
metalness: M.METALNESS,
|
|
36
|
+
roughness: M.ROUGHNESS,
|
|
37
|
+
clearcoat: M.CLEARCOAT,
|
|
38
|
+
clearcoatRoughness: M.CLEARCOAT_ROUGHNESS,
|
|
39
|
+
dispersion: M.DISPERSION,
|
|
40
|
+
sheen: M.SHEEN,
|
|
41
|
+
sheenRoughness: M.SHEEN_ROUGHNESS,
|
|
42
|
+
specularIntensity: M.SPECULAR_INTENSITY,
|
|
43
|
+
iridescence: M.IRIDESCENCE,
|
|
44
|
+
iridescenceIOR: M.IRIDESCENCE_IOR,
|
|
45
|
+
subsurface: M.SUBSURFACE,
|
|
46
|
+
subsurfaceRadiusScale: M.SUBSURFACE_RADIUS_SCALE,
|
|
47
|
+
subsurfaceAnisotropy: M.SUBSURFACE_ANISOTROPY,
|
|
48
|
+
anisotropy: M.ANISOTROPY,
|
|
49
|
+
anisotropyRotation: M.ANISOTROPY_ROTATION, // radians, unlike the degrees hosts usually show
|
|
50
|
+
};
|
|
51
|
+
|
|
26
52
|
export class MaterialDataManager {
|
|
27
53
|
|
|
28
54
|
/**
|
|
@@ -179,6 +205,28 @@ export class MaterialDataManager {
|
|
|
179
205
|
|
|
180
206
|
// ===== MATERIAL PROPERTY UPDATES =====
|
|
181
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Read back a scalar material property from the storage buffer — the value the shader
|
|
210
|
+
* actually uses. Hosts need this because the engine resolves defaults the three.js
|
|
211
|
+
* material never carries (e.g. IOR on a MeshStandardMaterial), so a UI that falls back
|
|
212
|
+
* to its own default displays a number the renderer is not using.
|
|
213
|
+
* @param {number} materialIndex
|
|
214
|
+
* @param {string} property
|
|
215
|
+
* @returns {number|undefined} undefined if unavailable or not a scalar slot
|
|
216
|
+
*/
|
|
217
|
+
getMaterialProperty( materialIndex, property ) {
|
|
218
|
+
|
|
219
|
+
const data = this.materialStorageAttr?.array;
|
|
220
|
+
if ( ! data ) return undefined;
|
|
221
|
+
|
|
222
|
+
const offset = SCALAR_PROPERTY_OFFSETS[ property ];
|
|
223
|
+
if ( offset === undefined ) return undefined;
|
|
224
|
+
|
|
225
|
+
const index = materialIndex * M.FLOATS_PER_MATERIAL + offset;
|
|
226
|
+
return index < data.length ? data[ index ] : undefined;
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
|
|
182
230
|
/**
|
|
183
231
|
* Update a single material property in the storage buffer.
|
|
184
232
|
* @param {number} materialIndex
|
|
@@ -253,7 +301,7 @@ export class MaterialDataManager {
|
|
|
253
301
|
}
|
|
254
302
|
|
|
255
303
|
break;
|
|
256
|
-
case 'attenuationDistance': data[ stride + M.ATTENUATION_DISTANCE ] = value; break;
|
|
304
|
+
case 'attenuationDistance': data[ stride + M.ATTENUATION_DISTANCE ] = normalizeAttenuationDistance( value ); break;
|
|
257
305
|
case 'dispersion': data[ stride + M.DISPERSION ] = value; break;
|
|
258
306
|
case 'sheen': data[ stride + M.SHEEN ] = value; break;
|
|
259
307
|
case 'sheenRoughness': data[ stride + M.SHEEN_ROUGHNESS ] = value; break;
|
|
@@ -446,7 +494,7 @@ export class MaterialDataManager {
|
|
|
446
494
|
|
|
447
495
|
}
|
|
448
496
|
|
|
449
|
-
data[ stride + M.ATTENUATION_DISTANCE ] = materialData.attenuationDistance
|
|
497
|
+
data[ stride + M.ATTENUATION_DISTANCE ] = normalizeAttenuationDistance( materialData.attenuationDistance );
|
|
450
498
|
data[ stride + M.DISPERSION ] = materialData.dispersion ?? 0;
|
|
451
499
|
data[ stride + M.VISIBLE ] = 1; // Reserved slot (per-mesh visibility handled at BLAS-pointer level)
|
|
452
500
|
data[ stride + M.SHEEN ] = materialData.sheen ?? 0;
|