rayzee 5.10.2 → 6.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.
Files changed (43) hide show
  1. package/README.md +82 -22
  2. package/dist/assets/AIUpscalerWorker-AXN-lKWN.js +2 -0
  3. package/dist/assets/AIUpscalerWorker-AXN-lKWN.js.map +1 -0
  4. package/dist/rayzee.es.js +1299 -1843
  5. package/dist/rayzee.es.js.map +1 -1
  6. package/dist/rayzee.umd.js +50 -74
  7. package/dist/rayzee.umd.js.map +1 -1
  8. package/package.json +1 -4
  9. package/src/AssetConfig.js +56 -0
  10. package/src/EngineDefaults.js +5 -3
  11. package/src/EngineEvents.js +1 -0
  12. package/src/Passes/AIUpscaler.js +44 -22
  13. package/src/Passes/OIDNDenoiser.js +4 -104
  14. package/src/PathTracerApp.js +59 -63
  15. package/src/Processor/AssetLoader.js +5 -2
  16. package/src/Processor/TextureCreator.js +42 -15
  17. package/src/Processor/Workers/AIUpscalerWorker.js +21 -6
  18. package/src/Stages/ASVGF.js +6 -27
  19. package/src/Stages/AdaptiveSampling.js +10 -26
  20. package/src/Stages/PathTracer.js +4 -5
  21. package/src/TSL/BVHTraversal.js +2 -18
  22. package/src/TSL/Clearcoat.js +1 -2
  23. package/src/TSL/Common.js +0 -13
  24. package/src/TSL/EmissiveSampling.js +0 -16
  25. package/src/TSL/Environment.js +0 -7
  26. package/src/TSL/LightsDirect.js +3 -379
  27. package/src/TSL/LightsSampling.js +0 -171
  28. package/src/TSL/MaterialEvaluation.js +3 -103
  29. package/src/TSL/MaterialProperties.js +1 -56
  30. package/src/TSL/MaterialSampling.js +2 -284
  31. package/src/TSL/MaterialTransmission.js +0 -93
  32. package/src/TSL/Random.js +0 -23
  33. package/src/TSL/Struct.js +0 -21
  34. package/src/TSL/TextureSampling.js +0 -69
  35. package/src/index.js +5 -2
  36. package/src/managers/DenoisingManager.js +13 -5
  37. package/src/managers/OverlayManager.js +14 -2
  38. package/src/managers/VideoRenderManager.js +4 -4
  39. package/dist/assets/AIUpscalerWorker-D58dcMrY.js +0 -2
  40. package/dist/assets/AIUpscalerWorker-D58dcMrY.js.map +0 -1
  41. package/src/Processor/createRenderTargetHelper.js +0 -521
  42. package/src/TSL/RayIntersection.js +0 -162
  43. package/src/managers/helpers/StatsHelper.js +0 -45
@@ -1,9 +1,9 @@
1
1
  import {
2
- Fn, float, vec3, int,
3
- If, max, min, dot, sqrt, clamp, mix, normalize, pow
2
+ Fn, float, vec3,
3
+ If, max, min, clamp, mix
4
4
  } from 'three/tsl';
5
5
 
6
- import { DotProducts, MaterialCache } from './Struct.js';
6
+ import { DotProducts } from './Struct.js';
7
7
  import {
8
8
  PI, PI_INV, EPSILON, MIN_CLEARCOAT_ROUGHNESS,
9
9
  computeDotProducts,
@@ -118,110 +118,10 @@ export const evaluateMaterialResponse = Fn( ( [ V, L, N, material ] ) => {
118
118
 
119
119
  } );
120
120
 
121
- // -----------------------------------------------------------------------------
122
- // Cached Material Response Evaluation (Optimized)
123
- // -----------------------------------------------------------------------------
124
-
125
- export const evaluateMaterialResponseCached = Fn( ( [ V, L, N, material, cache ] ) => {
126
-
127
- const result = vec3( 0.0 ).toVar();
128
-
129
- If( cache.isPurelyDiffuse, () => {
130
-
131
- result.assign( cache.diffuseColor );
132
-
133
- } ).Else( () => {
134
-
135
- const H = V.add( L ).toVar();
136
- const lenSq = dot( H, H );
137
- H.assign( lenSq.greaterThan( EPSILON ).select( H.div( sqrt( lenSq ) ), vec3( 0.0, 0.0, 1.0 ) ) );
138
- const NoL = max( dot( N, L ), EPSILON );
139
- const NoH = max( dot( N, H ), EPSILON );
140
- const VoH = max( dot( V, H ), EPSILON );
141
-
142
- const isTransmission = cache.NoV.mul( NoL ).lessThan( 0.0 );
143
- If( isTransmission.and( material.transmission.greaterThan( 0.0 ) ), () => {
144
-
145
- result.assign( evaluateMaterialResponse( V, L, N, material ) );
146
-
147
- } ).Else( () => {
148
-
149
- const F0 = cache.F0.toVar();
150
-
151
- // Iridescence
152
- If( material.iridescence.greaterThan( 0.0 ), () => {
153
-
154
- // Per glTF KHR_materials_iridescence spec: use max thickness when no texture
155
- const thickness = material.iridescenceThicknessRange.y;
156
- const iridescenceFresnel = evalIridescence( float( 1.0 ), material.iridescenceIOR, VoH, thickness, F0 );
157
- F0.assign( clamp( mix( F0, iridescenceFresnel, material.iridescence ), vec3( 0.0 ), vec3( 1.0 ) ) );
158
-
159
- } );
160
-
161
- // Use precomputed values
162
- const denom = NoH.mul( NoH ).mul( cache.alpha2.sub( 1.0 ) ).add( 1.0 );
163
- const D = cache.alpha2.div( max( float( PI ).mul( denom ).mul( denom ), EPSILON ) );
164
-
165
- const ggx1 = NoL.div( NoL.mul( float( 1.0 ).sub( cache.k ) ).add( cache.k ) );
166
- const ggx2 = cache.NoV.div( cache.NoV.mul( float( 1.0 ).sub( cache.k ) ).add( cache.k ) );
167
- const G = ggx1.mul( ggx2 );
168
-
169
- const F = fresnelSchlick( VoH, F0 ).toVar();
170
-
171
- // Single-scatter specular BRDF
172
- const specularDenom = max( float( 4.0 ).mul( cache.NoV ).mul( NoL ), EPSILON );
173
- const specularSS = D.mul( G ).mul( F ).div( specularDenom );
174
-
175
- // Kulla-Conty multiscatter energy compensation for rough surfaces
176
- const specular = specularSS.mul( multiscatterCompensation( F0, cache.NoV, material.roughness ) );
177
- // Diffuse energy budget from hemisphere-integrated specular albedo (includes multiscatter)
178
- const E_total = specularDirectionalAlbedo( F0, cache.NoV, material.roughness );
179
- const kD = vec3( 1.0 ).sub( E_total ).mul( float( 1.0 ).sub( material.metalness ) );
180
- const diffuse = kD.mul( material.color.rgb ).mul( PI_INV );
181
-
182
- const baseLayer = diffuse.add( specular ).toVar();
183
-
184
- // Sheen
185
- If( material.sheen.greaterThan( 0.0 ), () => {
186
-
187
- const sheenDist = SheenDistribution( NoH, material.sheenRoughness );
188
- const sheenTerm = material.sheenColor.mul( material.sheen ).mul( sheenDist ).mul( NoL );
189
- // Hemisphere-averaged sheen reflectance for energy-conserving base layer attenuation
190
- const avgSheenFactor = float( 1.0 ).sub( material.sheenRoughness ).mul( 0.5 ).add( 0.25 );
191
- const sheenReflectance = clamp( material.sheenColor.mul( material.sheen ).mul( avgSheenFactor ), vec3( 0.0 ), vec3( 1.0 ) );
192
- const sheenAttenuation = vec3( 1.0 ).sub( sheenReflectance );
193
-
194
- result.assign( baseLayer.mul( sheenAttenuation ).add( sheenTerm ) );
195
-
196
- } ).Else( () => {
197
-
198
- result.assign( baseLayer );
199
-
200
- } );
201
-
202
- } );
203
-
204
- } );
205
-
206
- return result;
207
-
208
- } );
209
-
210
121
  // -----------------------------------------------------------------------------
211
122
  // Layered BRDF Evaluation (for clearcoat)
212
123
  // -----------------------------------------------------------------------------
213
124
 
214
- // Helper function to calculate energy conservation for layered materials
215
- export const calculateLayerAttenuation = Fn( ( [ clearcoat, VoH ] ) => {
216
-
217
- // Fresnel term for clearcoat layer (using f0 = 0.04 for dielectric)
218
- const F = fresnelSchlickFloat( VoH, float( 0.04 ) );
219
- // Two-interface clearcoat attenuation: (1-F)² blended by clearcoat strength
220
- // = 1 - clearcoat * F * (2 - F)
221
- return float( 1.0 ).sub( clearcoat.mul( F ).mul( float( 2.0 ).sub( F ) ) );
222
-
223
- } );
224
-
225
125
  // Evaluate both clearcoat and base layer BRDFs
226
126
  export const evaluateLayeredBRDF = Fn( ( [ dots, material ] ) => {
227
127
 
@@ -324,64 +324,9 @@ export const calculateBRDFWeights = Fn( ( [ material, mc, cache ] ) => {
324
324
  } );
325
325
 
326
326
  // -----------------------------------------------------------------------------
327
- // Material Importance and Sampling Info
327
+ // Importance Sampling Info
328
328
  // -----------------------------------------------------------------------------
329
329
 
330
- export const getMaterialImportance = Fn( ( [ material, mc ] ) => {
331
-
332
- const result = float( 0.0 ).toVar();
333
-
334
- // Early out for specialized materials
335
- If( material.transmission.greaterThan( 0.0 ).or( material.clearcoat.greaterThan( 0.0 ) ), () => {
336
-
337
- result.assign( 0.95 );
338
-
339
- } ).Else( () => {
340
-
341
- // Base importance from complexity score
342
- const baseImportance = mc.complexityScore.toVar();
343
-
344
- // Enhanced emissive importance
345
- const emissiveImportance = float( 0.0 ).toVar();
346
- If( mc.isEmissive, () => {
347
-
348
- const emissiveLuminance = dot( material.emissive, REC709_LUMINANCE_COEFFICIENTS );
349
- emissiveImportance.assign( min( float( 0.6 ), emissiveLuminance.mul( material.emissiveIntensity ).mul( 0.25 ) ) );
350
-
351
- } );
352
-
353
- // Material-specific boosts
354
- const materialBoost = float( 0.0 ).toVar();
355
- If( mc.isMetallic.and( mc.isSmooth ), () => {
356
-
357
- materialBoost.addAssign( 0.25 );
358
-
359
- } ).ElseIf( mc.isMetallic, () => {
360
-
361
- materialBoost.addAssign( 0.15 );
362
-
363
- } );
364
-
365
- If( mc.isTransmissive, () => {
366
-
367
- materialBoost.addAssign( 0.2 );
368
-
369
- } );
370
- If( mc.hasClearcoat, () => {
371
-
372
- materialBoost.addAssign( 0.1 );
373
-
374
- } );
375
-
376
- const totalImportance = max( baseImportance.add( materialBoost ), emissiveImportance );
377
- result.assign( clamp( totalImportance, 0.0, 1.0 ) );
378
-
379
- } );
380
-
381
- return result;
382
-
383
- } );
384
-
385
330
  export const getImportanceSamplingInfo = Fn( ( [
386
331
  material, bounceIndex, mc,
387
332
  environmentIntensity, useEnvMapIS, enableEnvironmentLight
@@ -1,24 +1,9 @@
1
- import {
2
- Fn, wgslFn, float, vec3, If, max, min, abs, normalize, reflect, refract, dot, pow
3
- } from 'three/tsl';
4
-
5
- import {
6
- MultiLobeWeights, DirectionSample, MaterialCache, MaterialClassification
7
- } from './Struct.js';
8
-
9
- import {
10
- PI, PI_INV, MIN_PDF, classifyMaterial,
11
- } from './Common.js';
12
- import { dielectricF0 } from './Fresnel.js';
13
-
14
- import { calculateBRDFWeights, calculateGGXPDF } from './MaterialProperties.js';
15
- import { RandomValue } from './Random.js';
1
+ import { wgslFn } from 'three/tsl';
16
2
 
17
3
  // =============================================================================
18
4
  // MATERIAL SAMPLING
19
5
  // =============================================================================
20
- // This file contains importance sampling functions for various BRDF lobes
21
- // including GGX, cosine-weighted hemisphere, VNDF, and multi-lobe MIS.
6
+ // Importance sampling primitives: GGX, cosine-weighted hemisphere, VNDF.
22
7
 
23
8
  // -----------------------------------------------------------------------------
24
9
  // Basic Sampling Functions
@@ -63,12 +48,6 @@ export const cosineWeightedSample = /*@__PURE__*/ wgslFn( `
63
48
  }
64
49
  ` );
65
50
 
66
- export const cosineWeightedPDF = Fn( ( [ NoL ] ) => {
67
-
68
- return max( NoL, MIN_PDF ).mul( PI_INV );
69
-
70
- } );
71
-
72
51
  // -----------------------------------------------------------------------------
73
52
  // VNDF Sampling (Visible Normal Distribution Function)
74
53
  // -----------------------------------------------------------------------------
@@ -95,264 +74,3 @@ export const sampleGGXVNDF = /*@__PURE__*/ wgslFn( `
95
74
  return normalize( vec3f( alpha * Nh.x, alpha * Nh.y, max( 0.0f, Nh.z ) ) );
96
75
  }
97
76
  ` );
98
-
99
- // -----------------------------------------------------------------------------
100
- // Multi-Lobe MIS Sampling
101
- // -----------------------------------------------------------------------------
102
-
103
- // Enhanced sampling weights calculation for multi-lobe MIS
104
- export const calculateSamplingWeights = Fn( ( [ V, N, material ] ) => {
105
-
106
- // Get material classification for optimized calculations
107
- const mc = MaterialClassification.wrap( classifyMaterial( material ) );
108
-
109
- // Create temporary cache values
110
- const tempInvRoughness = float( 1.0 ).sub( material.roughness );
111
- const tempMetalFactor = float( 0.5 ).add( float( 0.5 ).mul( material.metalness ) );
112
- const tempIorFactor = min( float( 2.0 ).div( material.ior ), 1.0 );
113
- const tempMaxSheenColor = max( material.sheenColor.r, max( material.sheenColor.g, material.sheenColor.b ) );
114
-
115
- // Create temporary cache for calculations
116
- const tempCache = MaterialCache( {
117
- F0: dielectricF0( material.ior ),
118
- NoV: float( 0.5 ),
119
- diffuseColor: material.color.rgb,
120
- isPurelyDiffuse: false,
121
- alpha: material.roughness.mul( material.roughness ),
122
- k: material.roughness.add( 1.0 ).mul( material.roughness.add( 1.0 ) ).div( 8.0 ),
123
- alpha2: material.roughness.mul( material.roughness ).mul( material.roughness ).mul( material.roughness ),
124
- invRoughness: tempInvRoughness,
125
- metalFactor: tempMetalFactor,
126
- iorFactor: tempIorFactor,
127
- maxSheenColor: tempMaxSheenColor,
128
- } );
129
-
130
- // Calculate base BRDF weights
131
- const brdfWeights = BRDFWeights.wrap( calculateBRDFWeights( material, mc, tempCache ) );
132
-
133
- // Calculate view-dependent factors
134
- const NoV = max( dot( N, V ), 0.0 );
135
- const fresnelFactor = pow( float( 1.0 ).sub( NoV ), 5.0 );
136
-
137
- // Energy-conserving Fresnel redistribution: energy lost by diffuse transfers to specular
138
- // This preserves the total (diffuse + specular) weight while shifting toward specular at grazing angles
139
- const fresnelTransfer = brdfWeights.diffuse.mul( fresnelFactor );
140
- const diffuse = brdfWeights.diffuse.sub( fresnelTransfer ).toVar();
141
- const specular = brdfWeights.specular.add( fresnelTransfer ).toVar();
142
-
143
- // Other lobes remain unchanged — no artificial inflation
144
- const clearcoat = brdfWeights.clearcoat.toVar();
145
- const transmission = brdfWeights.transmission.mul( tempIorFactor ).toVar();
146
- const sheen = brdfWeights.sheen.toVar();
147
- const iridescence = brdfWeights.iridescence.toVar();
148
-
149
- // Calculate total weight for normalization
150
- const totalWeight = max(
151
- diffuse.add( specular ).add( clearcoat ).add( transmission ).add( sheen ).add( iridescence ),
152
- 1e-6
153
- ).toVar();
154
-
155
- // Normalize weights
156
- const invTotal = float( 1.0 ).div( totalWeight );
157
-
158
- return MultiLobeWeights( {
159
- diffuse: diffuse.mul( invTotal ),
160
- specular: specular.mul( invTotal ),
161
- clearcoat: clearcoat.mul( invTotal ),
162
- transmission: transmission.mul( invTotal ),
163
- sheen: sheen.mul( invTotal ),
164
- iridescence: iridescence.mul( invTotal ),
165
- totalWeight,
166
- } );
167
-
168
- } );
169
-
170
- // Calculate MIS weight considering all possible sampling strategies
171
- export const calculateMultiLobeMISWeight = Fn( ( [
172
- sampledDirection, V, N, material, weights, selectedPdf
173
- ] ) => {
174
-
175
- // Calculate PDFs for all possible sampling strategies
176
- const diffusePdf = float( 0.0 ).toVar();
177
- const specularPdf = float( 0.0 ).toVar();
178
- const clearcoatPdf = float( 0.0 ).toVar();
179
- const transmissionPdf = float( 0.0 ).toVar();
180
- const sheenPdf = float( 0.0 ).toVar();
181
-
182
- const NoL = dot( N, sampledDirection );
183
-
184
- // Diffuse PDF
185
- If( NoL.greaterThan( 0.0 ), () => {
186
-
187
- diffusePdf.assign( NoL.div( PI ) );
188
-
189
- } );
190
-
191
- // Specular PDF
192
- const H = normalize( V.add( sampledDirection ) ).toVar();
193
- const NoH = max( dot( N, H ), 0.0 );
194
- const VoH = max( dot( V, H ), 0.0 );
195
- const NoV = max( dot( N, V ), 0.0 );
196
-
197
- If( NoH.greaterThan( 0.0 ).and( VoH.greaterThan( 0.0 ) ).and( NoV.greaterThan( 0.0 ) ), () => {
198
-
199
- specularPdf.assign( calculateGGXPDF( NoH, VoH, material.roughness ) );
200
-
201
- // Clearcoat PDF (using clearcoat roughness)
202
- If( material.clearcoat.greaterThan( 0.0 ), () => {
203
-
204
- clearcoatPdf.assign( calculateGGXPDF( NoH, VoH, material.clearcoatRoughness ) );
205
-
206
- } );
207
-
208
- } );
209
-
210
- // Transmission PDF (simplified)
211
- If( material.transmission.greaterThan( 0.0 ).and( NoL.lessThan( 0.0 ) ), () => {
212
-
213
- // For transmission, we're sampling the opposite hemisphere
214
- transmissionPdf.assign( abs( NoL ).div( PI ) );
215
-
216
- } );
217
-
218
- // Sheen PDF (approximated as diffuse)
219
- If( material.sheen.greaterThan( 0.0 ).and( NoL.greaterThan( 0.0 ) ), () => {
220
-
221
- sheenPdf.assign( NoL.div( PI ) );
222
-
223
- } );
224
-
225
- // Calculate weighted PDFs for each lobe
226
- const weightedDiffusePdf = weights.diffuse.mul( diffusePdf );
227
- const weightedSpecularPdf = weights.specular.mul( specularPdf );
228
- const weightedClearcoatPdf = weights.clearcoat.mul( clearcoatPdf );
229
- const weightedTransmissionPdf = weights.transmission.mul( transmissionPdf );
230
- const weightedSheenPdf = weights.sheen.mul( sheenPdf );
231
- const weightedIridescencePdf = weights.iridescence.mul( diffusePdf );
232
-
233
- // Power heuristic (β=2): sum of squared weighted PDFs
234
- const sumSquaredPdfs = weightedDiffusePdf.mul( weightedDiffusePdf )
235
- .add( weightedSpecularPdf.mul( weightedSpecularPdf ) )
236
- .add( weightedClearcoatPdf.mul( weightedClearcoatPdf ) )
237
- .add( weightedTransmissionPdf.mul( weightedTransmissionPdf ) )
238
- .add( weightedSheenPdf.mul( weightedSheenPdf ) )
239
- .add( weightedIridescencePdf.mul( weightedIridescencePdf ) );
240
-
241
- // MIS weight: selectedPdf² / Σ(pdf_i²)
242
- const misWeight = float( 1.0 ).toVar();
243
-
244
- If( sumSquaredPdfs.greaterThan( 0.0 ).and( selectedPdf.greaterThan( 0.0 ) ), () => {
245
-
246
- const selectedPdfSquared = selectedPdf.mul( selectedPdf );
247
- misWeight.assign( selectedPdfSquared.div( sumSquaredPdfs ) );
248
-
249
- } );
250
-
251
- return misWeight;
252
-
253
- } );
254
-
255
- // Multi-lobe MIS for complex materials
256
- // Note: evaluateMaterialResponse is imported from MaterialEvaluation.js at usage site
257
- export const sampleMaterialWithMultiLobeMIS = Fn( ( [
258
- V, N, material, xi, rngState, evaluateMaterialResponse
259
- ] ) => {
260
-
261
- // Calculate individual lobe weights
262
- const weights = calculateSamplingWeights( V, N, material );
263
-
264
- // Multi-importance sampling across different lobes
265
- const rand = RandomValue( rngState );
266
- const cumulativeDiffuse = weights.diffuse;
267
- const cumulativeSpecular = cumulativeDiffuse.add( weights.specular );
268
- const cumulativeClearcoat = cumulativeSpecular.add( weights.clearcoat );
269
- const cumulativeTransmission = cumulativeClearcoat.add( weights.transmission );
270
-
271
- const sampledDirection = vec3( 0.0 ).toVar();
272
- const lobePdf = float( 0.0 ).toVar();
273
- const resultPdf = float( 0.0 ).toVar();
274
-
275
- If( rand.lessThan( cumulativeDiffuse ), () => {
276
-
277
- // Diffuse sampling
278
- sampledDirection.assign( ImportanceSampleCosine( { N, xi } ) );
279
- lobePdf.assign( max( dot( N, sampledDirection ), 0.0 ).div( PI ) );
280
- resultPdf.assign( lobePdf.mul( weights.diffuse ) );
281
-
282
- } ).ElseIf( rand.lessThan( cumulativeSpecular ), () => {
283
-
284
- // Specular sampling
285
- const H = ImportanceSampleGGX( { N, roughness: material.roughness, Xi: xi } ).toVar();
286
- sampledDirection.assign( reflect( V.negate(), H ) );
287
-
288
- If( dot( N, sampledDirection ).greaterThan( 0.0 ), () => {
289
-
290
- const NoH = max( dot( N, H ), 0.0 );
291
- const VoH = max( dot( V, H ), 0.0 );
292
- lobePdf.assign( calculateGGXPDF( NoH, VoH, material.roughness ) );
293
-
294
- } );
295
-
296
- resultPdf.assign( lobePdf.mul( weights.specular ) );
297
-
298
- } ).ElseIf( rand.lessThan( cumulativeClearcoat ).and( material.clearcoat.greaterThan( 0.0 ) ), () => {
299
-
300
- // Clearcoat sampling
301
- const H = ImportanceSampleGGX( { N, roughness: material.clearcoatRoughness, Xi: xi } ).toVar();
302
- sampledDirection.assign( reflect( V.negate(), H ) );
303
-
304
- If( dot( N, sampledDirection ).greaterThan( 0.0 ), () => {
305
-
306
- const NoH = max( dot( N, H ), 0.0 );
307
- const VoH = max( dot( V, H ), 0.0 );
308
- lobePdf.assign( calculateGGXPDF( NoH, VoH, material.clearcoatRoughness ) );
309
-
310
- } );
311
-
312
- resultPdf.assign( lobePdf.mul( weights.clearcoat ) );
313
-
314
- } ).ElseIf( rand.lessThan( cumulativeTransmission ).and( material.transmission.greaterThan( 0.0 ) ), () => {
315
-
316
- // Transmission sampling - simplified approach
317
- const H = ImportanceSampleGGX( { N, roughness: material.roughness, Xi: xi } ).toVar();
318
- const refractionDir = refract( V.negate(), H, float( 1.0 ).div( material.ior ) ).toVar();
319
-
320
- If( dot( refractionDir, refractionDir ).greaterThan( 0.001 ), () => {
321
-
322
- sampledDirection.assign( normalize( refractionDir ) );
323
- const NoH = max( dot( N, H ), 0.0 );
324
- const VoH = max( dot( V, H ), 0.0 );
325
- lobePdf.assign( calculateGGXPDF( NoH, VoH, material.roughness ) );
326
-
327
- } ).Else( () => {
328
-
329
- // Total internal reflection - fallback to specular
330
- sampledDirection.assign( reflect( V.negate(), H ) );
331
- lobePdf.assign( 0.1 );
332
-
333
- } );
334
-
335
- resultPdf.assign( lobePdf.mul( weights.transmission ) );
336
-
337
- } ).Else( () => {
338
-
339
- // Fallback to diffuse sampling for sheen/iridescence
340
- sampledDirection.assign( ImportanceSampleCosine( { N, xi } ) );
341
- lobePdf.assign( max( dot( N, sampledDirection ), 0.0 ).div( PI ) );
342
- resultPdf.assign( lobePdf.mul( weights.sheen.add( weights.iridescence ) ) );
343
-
344
- } );
345
-
346
- // Calculate MIS weight considering all possible sampling strategies
347
- const misWeight = calculateMultiLobeMISWeight( sampledDirection, V, N, material, weights, resultPdf );
348
-
349
- const resultValue = evaluateMaterialResponse( V, sampledDirection, N, material ).toVar();
350
- resultValue.mulAssign( misWeight );
351
-
352
- return DirectionSample( {
353
- direction: sampledDirection,
354
- value: resultValue,
355
- pdf: resultPdf,
356
- } );
357
-
358
- } );
@@ -103,103 +103,10 @@ export const MediumStack = struct( {
103
103
  depth: 'int',
104
104
  } );
105
105
 
106
- // ================================================================================
107
- // MEDIUM STACK HELPERS
108
- // ================================================================================
109
-
110
- export const getCurrentMediumIOR = Fn( ( [ mediumStack ] ) => {
111
-
112
- const result = float( 1.0 ).toVar();
113
-
114
- If( mediumStack.depth.greaterThan( int( 0 ) ), () => {
115
-
116
- // Read IOR from current depth
117
- If( mediumStack.depth.equal( int( 1 ) ), () => {
118
-
119
- result.assign( mediumStack.m1_ior );
120
-
121
- } );
122
- If( mediumStack.depth.equal( int( 2 ) ), () => {
123
-
124
- result.assign( mediumStack.m2_ior );
125
-
126
- } );
127
- If( mediumStack.depth.equal( int( 3 ) ), () => {
128
-
129
- result.assign( mediumStack.m3_ior );
130
-
131
- } );
132
-
133
- } );
134
-
135
- return result;
136
-
137
- } );
138
-
139
106
  // ================================================================================
140
107
  // DISPERSION
141
108
  // ================================================================================
142
109
 
143
- // Calculate wavelength-dependent IOR for dispersion using Cauchy dispersion equation
144
- export const calculateDispersiveIOR = /*@__PURE__*/ wgslFn( `
145
- fn calculateDispersiveIOR( baseIOR: f32, dispersionStrength: f32 ) -> vec3f {
146
- let B = dispersionStrength * 0.03f;
147
- // Standard CIE wavelengths for RGB (in micrometers)
148
- let wavelengths = vec3f( 0.7000f, 0.5461f, 0.4358f );
149
- // Apply Cauchy's equation: n(λ) = A + B/λ²
150
- let dispersiveIOR = baseIOR + B / ( wavelengths * wavelengths );
151
- return max( dispersiveIOR, vec3f( 1.001f ) );
152
- }
153
- ` );
154
-
155
- // Convert wavelength to RGB using spectral sensitivity curves
156
- export const wavelengthToRGB = /*@__PURE__*/ wgslFn( `
157
- fn wavelengthToRGB( wavelength: f32 ) -> vec3f {
158
- var color = vec3f( 0.0f );
159
- // Violet: 380-440
160
- if ( wavelength >= 380.0f && wavelength < 440.0f ) {
161
- let t = ( wavelength - 380.0f ) / 60.0f;
162
- color = vec3f( 0.6f + 0.4f * ( 1.0f - t ), 0.0f, 1.0f );
163
- }
164
- // Blue: 440-490
165
- if ( wavelength >= 440.0f && wavelength < 490.0f ) {
166
- let t = ( wavelength - 440.0f ) / 50.0f;
167
- color = vec3f( 0.6f * ( 1.0f - t ), 0.0f, 1.0f );
168
- }
169
- // Blue-Cyan: 490-510
170
- if ( wavelength >= 490.0f && wavelength < 510.0f ) {
171
- let t = ( wavelength - 490.0f ) / 20.0f;
172
- color = vec3f( 0.0f, t, 1.0f );
173
- }
174
- // Cyan-Green-Yellow: 510-580
175
- if ( wavelength >= 510.0f && wavelength < 580.0f ) {
176
- let t = ( wavelength - 510.0f ) / 70.0f;
177
- if ( t < 0.5f ) {
178
- color = vec3f( 0.0f, 1.0f, 1.0f - t * 2.0f );
179
- } else {
180
- color = vec3f( ( t - 0.5f ) * 2.0f, 1.0f, 0.0f );
181
- }
182
- }
183
- // Yellow-Orange-Red: 580-645
184
- if ( wavelength >= 580.0f && wavelength < 645.0f ) {
185
- let t = ( wavelength - 580.0f ) / 65.0f;
186
- color = vec3f( 1.0f, 1.0f - t, 0.0f );
187
- }
188
- // Red: 645-700
189
- if ( wavelength >= 645.0f && wavelength <= 700.0f ) {
190
- color = vec3f( 1.0f, 0.0f, 0.0f );
191
- }
192
- // Apply intensity falloff at spectrum edges
193
- if ( wavelength < 420.0f ) {
194
- color = color * ( ( wavelength - 380.0f ) / 40.0f );
195
- }
196
- if ( wavelength > 680.0f ) {
197
- color = color * ( ( 700.0f - wavelength ) / 20.0f );
198
- }
199
- return color;
200
- }
201
- ` );
202
-
203
110
  // Enhanced spectral sampling for realistic dispersion
204
111
  export const sampleWavelengthForDispersion = Fn( ( [ baseIOR, dispersionStrength, random ] ) => {
205
112
 
package/src/TSL/Random.js CHANGED
@@ -138,21 +138,6 @@ export const RandomValue = ( state ) => {
138
138
 
139
139
  };
140
140
 
141
- // Generate random float with better precision
142
-
143
- export const RandomValueHighPrecision = ( state ) => {
144
-
145
- // Capture s1 immediately (.toVar()) before advancing state, so it isn't
146
- // re-evaluated lazily after the second pcgHash advances state further.
147
- const s1 = pcgHash( { state } ).toVar();
148
- state.assign( s1 );
149
- const s2 = pcgHash( { state } ).toVar();
150
-
151
- // Combine two 24-bit values for 48-bit precision
152
- return float( s1.shiftRight( 8 ) ).add( float( s2.shiftRight( 8 ) ).mul( 1.0 / 16777216.0 ) ).mul( 1.0 / 16777216.0 );
153
-
154
- };
155
-
156
141
  // -----------------------------------------------------------------------------
157
142
  // Directional sampling functions
158
143
  // -----------------------------------------------------------------------------
@@ -198,14 +183,6 @@ const computeSTBNAtlasCoord = ( pixelCoords, sampleIndex, dimensionIndex, frame
198
183
 
199
184
  };
200
185
 
201
- // Sample 1D scalar STBN value in [0,1]
202
- export const sampleSTBNScalar = ( pixelCoords, sampleIndex, dimensionIndex, frame ) => {
203
-
204
- const coord = computeSTBNAtlasCoord( pixelCoords, sampleIndex, dimensionIndex, frame );
205
- return stbnScalarTextureNode.load( coord ).x;
206
-
207
- };
208
-
209
186
  // Sample decorrelated 2D STBN pair in [0,1]²
210
187
  export const sampleSTBN2D = ( pixelCoords, sampleIndex, dimensionPairIndex, frame ) => {
211
188
 
package/src/TSL/Struct.js CHANGED
@@ -216,22 +216,6 @@ export const MISStrategy = struct( {
216
216
  useEnvSampling: 'bool',
217
217
  } );
218
218
 
219
- // IMPROVEMENT: Multi-layer MIS type aliases and extensions
220
- // Use existing structs with clear naming for multi-lobe MIS
221
- // #define MaterialWeights BRDFWeights
222
- // #define SamplingResult DirectionSample
223
-
224
- // Enhanced material weights for multi-lobe sampling
225
- export const MultiLobeWeights = struct( {
226
- diffuse: 'float',
227
- specular: 'float',
228
- clearcoat: 'float',
229
- transmission: 'float',
230
- sheen: 'float',
231
- iridescence: 'float',
232
- totalWeight: 'float',
233
- } );
234
-
235
219
  // General rendering state (used across all rendering paths)
236
220
  export const RenderState = struct( {
237
221
  traversals: 'int', // Remaining general bounces
@@ -241,8 +225,3 @@ export const RenderState = struct( {
241
225
  actualBounceDepth: 'int', // True depth without manipulation
242
226
  } );
243
227
 
244
- export const pathTracerOutputStruct = struct( {
245
- gColor: 'vec4', // RGB + alpha
246
- gNormalDepth: 'vec4', // Normal(RGB) + depth(A)
247
- gAlbedo: 'vec4' // Albedo color + alpha
248
- } );