rayzee 5.1.1 → 5.2.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 +2709 -2569
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +49 -49
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/EngineDefaults.js +77 -2
- package/src/PathTracerApp.js +1 -0
- package/src/Processor/ShaderBuilder.js +9 -0
- package/src/Processor/TextureCreator.js +25 -10
- package/src/RenderSettings.js +1 -0
- package/src/TSL/BVHTraversal.js +9 -3
- package/src/TSL/Common.js +62 -28
- package/src/TSL/Debugger.js +1 -2
- package/src/TSL/EmissiveSampling.js +3 -4
- package/src/TSL/LightsCore.js +1 -1
- package/src/TSL/LightsDirect.js +112 -15
- package/src/TSL/LightsSampling.js +2 -3
- package/src/TSL/PathTracerCore.js +6 -5
- package/src/TSL/Struct.js +16 -0
- package/src/managers/MaterialDataManager.js +138 -150
- package/src/managers/UniformManager.js +1 -0
package/package.json
CHANGED
package/src/EngineDefaults.js
CHANGED
|
@@ -80,6 +80,7 @@ export const ENGINE_DEFAULTS = {
|
|
|
80
80
|
renderLimitMode: 'frames',
|
|
81
81
|
renderTimeLimit: 30,
|
|
82
82
|
renderMode: 0,
|
|
83
|
+
enableAlphaShadows: false,
|
|
83
84
|
tiles: 3,
|
|
84
85
|
tilesHelper: false,
|
|
85
86
|
showLightHelper: false,
|
|
@@ -337,6 +338,80 @@ export const TRIANGLE_DATA_LAYOUT = {
|
|
|
337
338
|
UV_C_MAT_OFFSET: 28
|
|
338
339
|
};
|
|
339
340
|
|
|
341
|
+
// Material data layout constants — single source of truth for material buffer offsets.
|
|
342
|
+
// Shared between CPU writers (TextureCreator, MaterialDataManager) and GPU readers (Common.js getMaterial).
|
|
343
|
+
export const MATERIAL_DATA_LAYOUT = {
|
|
344
|
+
|
|
345
|
+
SLOTS_PER_MATERIAL: 27, // vec4 slots per material
|
|
346
|
+
FLOATS_PER_MATERIAL: 108, // total floats per material (27 × 4)
|
|
347
|
+
|
|
348
|
+
// ── Flat float offsets (CPU side) ────────────────────────────────
|
|
349
|
+
// Used as: data[ materialIndex * FLOATS_PER_MATERIAL + offset ]
|
|
350
|
+
// Ordered for cache-line coherence: shadow/culling → BxDF core → maps → extended → transforms
|
|
351
|
+
|
|
352
|
+
// Slot 0: ior + transmission + thickness + emissiveIntensity [shadow]
|
|
353
|
+
IOR: 0, TRANSMISSION: 1, THICKNESS: 2, EMISSIVE_INTENSITY: 3,
|
|
354
|
+
// Slot 1: attenuationColor.rgb + attenuationDistance [shadow]
|
|
355
|
+
ATTENUATION_COLOR: 4, ATTENUATION_DISTANCE: 7,
|
|
356
|
+
// Slot 2: opacity + side + transparent + alphaTest [shadow + culling]
|
|
357
|
+
OPACITY: 8, SIDE: 9, TRANSPARENT: 10, ALPHA_TEST: 11,
|
|
358
|
+
// Slot 3: alphaMode + depthWrite + normalScale [shadow]
|
|
359
|
+
ALPHA_MODE: 12, DEPTH_WRITE: 13, NORMAL_SCALE: 14,
|
|
360
|
+
// Slot 4: color.rgb + metalness [BxDF core]
|
|
361
|
+
COLOR: 16, METALNESS: 19,
|
|
362
|
+
// Slot 5: emissive.rgb + roughness [BxDF core]
|
|
363
|
+
EMISSIVE: 20, ROUGHNESS: 23,
|
|
364
|
+
// Slot 6: map indices (albedo, normal, roughness, metalness) [maps]
|
|
365
|
+
ALBEDO_MAP_INDEX: 24, NORMAL_MAP_INDEX: 25, ROUGHNESS_MAP_INDEX: 26, METALNESS_MAP_INDEX: 27,
|
|
366
|
+
// Slot 7: map indices (emissive, bump) + clearcoat [maps]
|
|
367
|
+
EMISSIVE_MAP_INDEX: 28, BUMP_MAP_INDEX: 29, CLEARCOAT: 30, CLEARCOAT_ROUGHNESS: 31,
|
|
368
|
+
// Slot 8: dispersion + visible + sheen + sheenRoughness [extended BxDF]
|
|
369
|
+
DISPERSION: 32, VISIBLE: 33, SHEEN: 34, SHEEN_ROUGHNESS: 35,
|
|
370
|
+
// Slot 9: sheenColor.rgb + (reserved) [extended BxDF]
|
|
371
|
+
SHEEN_COLOR: 36,
|
|
372
|
+
// Slot 10: specularIntensity + specularColor.rgb [extended BxDF]
|
|
373
|
+
SPECULAR_INTENSITY: 40, SPECULAR_COLOR: 41,
|
|
374
|
+
// Slot 11: iridescence + iridescenceIOR + iridescenceThicknessRange [extended BxDF]
|
|
375
|
+
IRIDESCENCE: 44, IRIDESCENCE_IOR: 45, IRIDESCENCE_THICKNESS_RANGE: 46,
|
|
376
|
+
// Slot 12: bumpScale + displacementScale + displacementMapIndex + (padding)
|
|
377
|
+
BUMP_SCALE: 48, DISPLACEMENT_SCALE: 49, DISPLACEMENT_MAP_INDEX: 50,
|
|
378
|
+
|
|
379
|
+
// ── Transform float offsets (8 floats each: 7 matrix values + 1 padding) ──
|
|
380
|
+
ALBEDO_TRANSFORM: 52,
|
|
381
|
+
NORMAL_TRANSFORM: 60,
|
|
382
|
+
ROUGHNESS_TRANSFORM: 68,
|
|
383
|
+
METALNESS_TRANSFORM: 76,
|
|
384
|
+
EMISSIVE_TRANSFORM: 84,
|
|
385
|
+
BUMP_TRANSFORM: 92,
|
|
386
|
+
DISPLACEMENT_TRANSFORM: 100,
|
|
387
|
+
|
|
388
|
+
// ── Vec4 slot indices (GPU/TSL side) ─────────────────────────────
|
|
389
|
+
// Used with getDatafromStorageBuffer( buf, matIdx, int(slot), int(SLOTS_PER_MATERIAL) )
|
|
390
|
+
SLOT: {
|
|
391
|
+
IOR_TRANSMISSION: 0, // [shadow] ior, transmission, thickness, emissiveIntensity
|
|
392
|
+
ATTENUATION: 1, // [shadow] attenuationColor, attenuationDistance
|
|
393
|
+
OPACITY_ALPHA: 2, // [shadow+culling] opacity, side, transparent, alphaTest
|
|
394
|
+
ALPHA_MODE: 3, // [shadow] alphaMode, depthWrite, normalScale
|
|
395
|
+
COLOR_METALNESS: 4, // [BxDF] color.rgb, metalness
|
|
396
|
+
EMISSIVE_ROUGHNESS: 5, // [BxDF] emissive.rgb, roughness
|
|
397
|
+
MAP_INDICES_A: 6, // [maps] albedo, normal, roughness, metalness
|
|
398
|
+
MAP_INDICES_B: 7, // [maps] emissive, bump, clearcoat, clearcoatRoughness
|
|
399
|
+
DISPERSION_SHEEN: 8, // [extended] dispersion, visible, sheen, sheenRoughness
|
|
400
|
+
SHEEN_COLOR: 9, // [extended] sheenColor, reserved
|
|
401
|
+
SPECULAR: 10, // [extended] specularIntensity, specularColor
|
|
402
|
+
IRIDESCENCE: 11, // [extended] iridescence, iridescenceIOR, iridescenceThicknessRange
|
|
403
|
+
BUMP_DISPLACEMENT: 12, // bumpScale, displacementScale, displacementMapIndex
|
|
404
|
+
ALBEDO_TRANSFORM_A: 13, ALBEDO_TRANSFORM_B: 14,
|
|
405
|
+
NORMAL_TRANSFORM_A: 15, NORMAL_TRANSFORM_B: 16,
|
|
406
|
+
ROUGHNESS_TRANSFORM_A: 17, ROUGHNESS_TRANSFORM_B: 18,
|
|
407
|
+
METALNESS_TRANSFORM_A: 19, METALNESS_TRANSFORM_B: 20,
|
|
408
|
+
EMISSIVE_TRANSFORM_A: 21, EMISSIVE_TRANSFORM_B: 22,
|
|
409
|
+
BUMP_TRANSFORM_A: 23, BUMP_TRANSFORM_B: 24,
|
|
410
|
+
DISPLACEMENT_TRANSFORM_A: 25, DISPLACEMENT_TRANSFORM_B: 26,
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
};
|
|
414
|
+
|
|
340
415
|
// BVH node leaf markers
|
|
341
416
|
export const BVH_LEAF_MARKERS = {
|
|
342
417
|
TRIANGLE_LEAF: - 1, // Leaf containing triangle references
|
|
@@ -364,14 +439,14 @@ export const DEFAULT_TEXTURE_MATRIX = [ 0, 0, 1, 1, 0, 0, 0, 1 ];
|
|
|
364
439
|
// Render mode configurations
|
|
365
440
|
export const FINAL_RENDER_CONFIG = {
|
|
366
441
|
maxSamples: 30, bounces: 20, transmissiveBounces: 8, samplesPerPixel: 1,
|
|
367
|
-
renderMode: 1, tiles: 3, tilesHelper: false,
|
|
442
|
+
renderMode: 1, enableAlphaShadows: true, tiles: 3, tilesHelper: false,
|
|
368
443
|
enableOIDN: true, oidnQuality: 'balance',
|
|
369
444
|
interactionModeEnabled: false,
|
|
370
445
|
};
|
|
371
446
|
|
|
372
447
|
export const PREVIEW_RENDER_CONFIG = {
|
|
373
448
|
maxSamples: ENGINE_DEFAULTS.maxSamples, bounces: ENGINE_DEFAULTS.bounces,
|
|
374
|
-
samplesPerPixel: ENGINE_DEFAULTS.samplesPerPixel, renderMode: ENGINE_DEFAULTS.renderMode,
|
|
449
|
+
samplesPerPixel: ENGINE_DEFAULTS.samplesPerPixel, renderMode: ENGINE_DEFAULTS.renderMode, enableAlphaShadows: ENGINE_DEFAULTS.enableAlphaShadows,
|
|
375
450
|
transmissiveBounces: ENGINE_DEFAULTS.transmissiveBounces,
|
|
376
451
|
tiles: ENGINE_DEFAULTS.tiles, tilesHelper: ENGINE_DEFAULTS.tilesHelper,
|
|
377
452
|
enableOIDN: false, oidnQuality: 'fast',
|
package/src/PathTracerApp.js
CHANGED
|
@@ -730,6 +730,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
730
730
|
}, { silent: true } );
|
|
731
731
|
|
|
732
732
|
this.stages.pathTracer?.setUniform( 'renderMode', parseInt( config.renderMode ) );
|
|
733
|
+
this.stages.pathTracer?.setUniform( 'enableAlphaShadows', config.enableAlphaShadows ?? false );
|
|
733
734
|
this.stages.pathTracer?.tileManager?.setTileCount( config.tiles );
|
|
734
735
|
|
|
735
736
|
const tileHelper = this.overlayManager?.getHelper( 'tiles' );
|
|
@@ -17,6 +17,7 @@ import { TextureNode } from 'three/webgpu';
|
|
|
17
17
|
import { LinearFilter, DataArrayTexture } from 'three';
|
|
18
18
|
import { pathTracerMain } from '../TSL/PathTracer.js';
|
|
19
19
|
import { setMeshVisibilityBuffer } from '../TSL/BVHTraversal.js';
|
|
20
|
+
import { setShadowAlbedoMaps, setAlphaShadowsUniform } from '../TSL/LightsDirect.js';
|
|
20
21
|
import { BuildTimer } from './BuildTimer.js';
|
|
21
22
|
|
|
22
23
|
const WG_SIZE = 8;
|
|
@@ -192,6 +193,9 @@ export class ShaderBuilder {
|
|
|
192
193
|
// Set per-mesh visibility buffer (module-level in BVHTraversal.js, read during graph construction)
|
|
193
194
|
setMeshVisibilityBuffer( stage.meshVisibilityStorageNode );
|
|
194
195
|
|
|
196
|
+
// Set alpha-shadow uniform (module-level in LightsDirect.js, read at runtime)
|
|
197
|
+
setAlphaShadowsUniform( stage.uniforms.get( 'enableAlphaShadows' ) );
|
|
198
|
+
|
|
195
199
|
const envTex = texture( stage.environment.environmentTexture );
|
|
196
200
|
|
|
197
201
|
// Adaptive sampling texture
|
|
@@ -228,6 +232,11 @@ export class ShaderBuilder {
|
|
|
228
232
|
const emissiveMapsTex = mat.emissiveMaps ? texture( mat.emissiveMaps ) : createArrayPlaceholder();
|
|
229
233
|
const displacementMapsTex = mat.displacementMaps ? texture( mat.displacementMaps ) : createArrayPlaceholder();
|
|
230
234
|
|
|
235
|
+
// Set albedo texture array for alpha-aware shadow rays (module-level in LightsDirect.js).
|
|
236
|
+
// Always pass the texture node (real or placeholder) so alpha-cutout code is emitted
|
|
237
|
+
// into the shader at graph construction time. Runtime albedoMapIndex >= 0 guards sampling.
|
|
238
|
+
setShadowAlbedoMaps( albedoMapsTex );
|
|
239
|
+
|
|
231
240
|
const result = {
|
|
232
241
|
triStorage, bvhStorage, matStorage, emissiveTriStorage, lightBVHStorage,
|
|
233
242
|
envTex, adaptiveSamplingTex, marginalCDFStorage, conditionalCDFStorage,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DataArrayTexture, RGBAFormat, LinearFilter, UnsignedByteType, SRGBColorSpace } from "three";
|
|
2
|
-
import { TEXTURE_CONSTANTS, MEMORY_CONSTANTS, DEFAULT_TEXTURE_MATRIX } from '../EngineDefaults.js';
|
|
2
|
+
import { TEXTURE_CONSTANTS, MEMORY_CONSTANTS, DEFAULT_TEXTURE_MATRIX, MATERIAL_DATA_LAYOUT } from '../EngineDefaults.js';
|
|
3
3
|
|
|
4
4
|
// Canvas pooling for efficient reuse of canvas elements
|
|
5
5
|
class CanvasPool {
|
|
@@ -858,9 +858,9 @@ export class TextureCreator {
|
|
|
858
858
|
*/
|
|
859
859
|
createMaterialRawData( materials ) {
|
|
860
860
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
const dataLengthPerMaterial =
|
|
861
|
+
// Layout is defined by MATERIAL_DATA_LAYOUT in EngineDefaults.js.
|
|
862
|
+
// The inline array below must match that layout exactly (positional order = canonical layout).
|
|
863
|
+
const dataLengthPerMaterial = MATERIAL_DATA_LAYOUT.FLOATS_PER_MATERIAL;
|
|
864
864
|
const totalMaterials = materials.length;
|
|
865
865
|
|
|
866
866
|
const size = totalMaterials * dataLengthPerMaterial;
|
|
@@ -879,19 +879,34 @@ export class TextureCreator {
|
|
|
879
879
|
const bumpMapMatrices = mat.bumpMapMatrices ?? DEFAULT_TEXTURE_MATRIX;
|
|
880
880
|
const displacementMapMatrices = mat.displacementMapMatrices ?? DEFAULT_TEXTURE_MATRIX;
|
|
881
881
|
|
|
882
|
+
// Slot order: shadow/culling → BxDF core → maps → extended → displacement → transforms
|
|
883
|
+
// Must match MATERIAL_DATA_LAYOUT in EngineDefaults.js exactly.
|
|
882
884
|
const materialData = [
|
|
883
|
-
|
|
884
|
-
mat.emissive.r, mat.emissive.g, mat.emissive.b, mat.roughness,
|
|
885
|
+
// Slot 0: shadow core (ior, transmission, thickness, emissiveIntensity)
|
|
885
886
|
mat.ior, mat.transmission, mat.thickness, mat.emissiveIntensity,
|
|
887
|
+
// Slot 1: shadow (attenuationColor, attenuationDistance)
|
|
886
888
|
mat.attenuationColor.r, mat.attenuationColor.g, mat.attenuationColor.b, mat.attenuationDistance,
|
|
889
|
+
// Slot 2: shadow + culling (opacity, side, transparent, alphaTest)
|
|
890
|
+
mat.opacity, mat.side, mat.transparent, mat.alphaTest,
|
|
891
|
+
// Slot 3: shadow (alphaMode, depthWrite, normalScale)
|
|
892
|
+
mat.alphaMode, mat.depthWrite, mat.normalScale?.x ?? 1, mat.normalScale?.y ?? 1,
|
|
893
|
+
// Slot 4: BxDF core (color, metalness)
|
|
894
|
+
mat.color.r, mat.color.g, mat.color.b, mat.metalness,
|
|
895
|
+
// Slot 5: BxDF core (emissive, roughness)
|
|
896
|
+
mat.emissive.r, mat.emissive.g, mat.emissive.b, mat.roughness,
|
|
897
|
+
// Slot 6: map indices A (albedo, normal, roughness, metalness)
|
|
898
|
+
mat.map, mat.normalMap, mat.roughnessMap, mat.metalnessMap,
|
|
899
|
+
// Slot 7: map indices B (emissive, bump, clearcoat, clearcoatRoughness)
|
|
900
|
+
mat.emissiveMap, mat.bumpMap, mat.clearcoat, mat.clearcoatRoughness,
|
|
901
|
+
// Slot 8: extended BxDF (dispersion, visible, sheen, sheenRoughness)
|
|
887
902
|
mat.dispersion, mat.visible, mat.sheen, mat.sheenRoughness,
|
|
903
|
+
// Slot 9: extended BxDF (sheenColor, reserved)
|
|
888
904
|
mat.sheenColor.r, mat.sheenColor.g, mat.sheenColor.b, 1,
|
|
905
|
+
// Slot 10: extended BxDF (specularIntensity, specularColor)
|
|
889
906
|
mat.specularIntensity, mat.specularColor.r, mat.specularColor.g, mat.specularColor.b,
|
|
907
|
+
// Slot 11: extended BxDF (iridescence)
|
|
890
908
|
mat.iridescence, mat.iridescenceIOR, mat.iridescenceThicknessRange[ 0 ], mat.iridescenceThicknessRange[ 1 ],
|
|
891
|
-
|
|
892
|
-
mat.emissiveMap, mat.bumpMap, mat.clearcoat, mat.clearcoatRoughness,
|
|
893
|
-
mat.opacity, mat.side, mat.transparent, mat.alphaTest,
|
|
894
|
-
mat.alphaMode, mat.depthWrite, mat.normalScale?.x ?? 1, mat.normalScale?.y ?? 1,
|
|
909
|
+
// Slot 12: displacement
|
|
895
910
|
mat.bumpScale, mat.displacementScale, mat.displacementMap, 0,
|
|
896
911
|
mapMatrix[ 0 ], mapMatrix[ 1 ], mapMatrix[ 2 ], mapMatrix[ 3 ],
|
|
897
912
|
mapMatrix[ 4 ], mapMatrix[ 5 ], mapMatrix[ 6 ], 1,
|
package/src/RenderSettings.js
CHANGED
|
@@ -31,6 +31,7 @@ const SETTING_ROUTES = {
|
|
|
31
31
|
anamorphicRatio: { uniform: 'anamorphicRatio', reset: true },
|
|
32
32
|
samplingTechnique: { uniform: 'samplingTechnique', reset: true },
|
|
33
33
|
fireflyThreshold: { uniform: 'fireflyThreshold', reset: true },
|
|
34
|
+
enableAlphaShadows: { uniform: 'enableAlphaShadows', reset: true },
|
|
34
35
|
enableEmissiveTriangleSampling: { uniform: 'enableEmissiveTriangleSampling', reset: true },
|
|
35
36
|
emissiveBoost: { uniform: 'emissiveBoost', reset: true },
|
|
36
37
|
visMode: { uniform: 'visMode', reset: true },
|
package/src/TSL/BVHTraversal.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from 'three/tsl';
|
|
27
27
|
|
|
28
28
|
import { Ray, HitInfo } from './Struct.js';
|
|
29
|
-
import { getDatafromStorageBuffer, MATERIAL_SLOTS } from './Common.js';
|
|
29
|
+
import { getDatafromStorageBuffer, MATERIAL_SLOTS, MATERIAL_SLOT } from './Common.js';
|
|
30
30
|
import { RandomPointInCircle } from './Random.js';
|
|
31
31
|
|
|
32
32
|
// ================================================================================
|
|
@@ -136,7 +136,7 @@ const fastRayAABBDst = wgslFn( `
|
|
|
136
136
|
// Per-mesh visibility handled at BLAS-pointer level; material visibility always 1.
|
|
137
137
|
export const passesSideCulling = Fn( ( [ materialIndex, rayDirection, normal, materialBuffer ] ) => {
|
|
138
138
|
|
|
139
|
-
const sideData = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
139
|
+
const sideData = getDatafromStorageBuffer( materialBuffer, materialIndex, int( MATERIAL_SLOT.OPACITY_ALPHA ), int( MATERIAL_SLOTS ) );
|
|
140
140
|
const side = int( sideData.g );
|
|
141
141
|
const rayDotNormal = rayDirection.dot( normal );
|
|
142
142
|
const doubleSide = side.equal( int( 2 ) );
|
|
@@ -268,7 +268,7 @@ export const traverseBVH = Fn( ( [
|
|
|
268
268
|
} );
|
|
269
269
|
|
|
270
270
|
// If we found a very close hit, we can terminate early
|
|
271
|
-
If( closestHit.didHit.and( closestHit.dst.lessThan(
|
|
271
|
+
If( closestHit.didHit.and( closestHit.dst.lessThan( 0.001 ) ), () => {
|
|
272
272
|
|
|
273
273
|
Break();
|
|
274
274
|
|
|
@@ -451,6 +451,12 @@ export const traverseBVHShadow = Fn( ( [
|
|
|
451
451
|
closestHit.hitPoint.assign( ray.origin.add( ray.direction.mul( triResult.x ) ) );
|
|
452
452
|
closestHit.normal.assign( normalize( cross( pB.sub( pA ), pC.sub( pA ) ) ) );
|
|
453
453
|
|
|
454
|
+
// Store barycentrics + triangle index for deferred UV computation.
|
|
455
|
+
// Actual UV interpolation happens in traceShadowRay only when
|
|
456
|
+
// the material needs alpha testing — zero overhead for opaque hits.
|
|
457
|
+
closestHit.uv.assign( vec2( triResult.y, triResult.z ) );
|
|
458
|
+
closestHit.triangleIndex.assign( triIndex );
|
|
459
|
+
|
|
454
460
|
// Shadow ray only needs any hit — skip remaining triangles in leaf
|
|
455
461
|
Break();
|
|
456
462
|
|
package/src/TSL/Common.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
MaterialClassification,
|
|
6
6
|
MISStrategy,
|
|
7
7
|
RayTracingMaterial,
|
|
8
|
+
ShadowMaterial,
|
|
8
9
|
} from './Struct.js';
|
|
9
10
|
|
|
10
11
|
export const PI = 3.14159;
|
|
@@ -16,7 +17,11 @@ export const MIN_CLEARCOAT_ROUGHNESS = 0.089;
|
|
|
16
17
|
export const MAX_ROUGHNESS = 1.0;
|
|
17
18
|
export const MIN_PDF = 0.001;
|
|
18
19
|
export const REC709_LUMINANCE_COEFFICIENTS = vec3( 0.2126, 0.7152, 0.0722 );
|
|
19
|
-
|
|
20
|
+
import { MATERIAL_DATA_LAYOUT } from '../EngineDefaults.js';
|
|
21
|
+
|
|
22
|
+
export const MATERIAL_SLOTS = MATERIAL_DATA_LAYOUT.SLOTS_PER_MATERIAL;
|
|
23
|
+
export const MATERIAL_SLOT = MATERIAL_DATA_LAYOUT.SLOT;
|
|
24
|
+
const S = MATERIAL_SLOT;
|
|
20
25
|
|
|
21
26
|
// XYZ to sRGB color space conversion matrix
|
|
22
27
|
export const XYZ_TO_REC709 = mat3(
|
|
@@ -313,33 +318,33 @@ export const arrayToMat3 = wgslFn( `
|
|
|
313
318
|
|
|
314
319
|
export const getMaterial = Fn( ( [ materialIndex, materialBuffer ] ) => {
|
|
315
320
|
|
|
316
|
-
const data0 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
317
|
-
const data1 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
318
|
-
const data2 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
319
|
-
const data3 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
320
|
-
const data4 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
321
|
-
const data5 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
322
|
-
const data6 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
323
|
-
const data7 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
324
|
-
const data8 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
325
|
-
const data9 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
326
|
-
const data10 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
327
|
-
const data11 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
328
|
-
const data12 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
329
|
-
const data13 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
330
|
-
const data14 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
331
|
-
const data15 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
332
|
-
const data16 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
333
|
-
const data17 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
334
|
-
const data18 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
335
|
-
const data19 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
336
|
-
const data20 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
337
|
-
const data21 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
338
|
-
const data22 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
339
|
-
const data23 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
340
|
-
const data24 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
341
|
-
const data25 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
342
|
-
const data26 = getDatafromStorageBuffer( materialBuffer, materialIndex, int(
|
|
321
|
+
const data0 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.COLOR_METALNESS ), int( MATERIAL_SLOTS ) ).toVar();
|
|
322
|
+
const data1 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.EMISSIVE_ROUGHNESS ), int( MATERIAL_SLOTS ) ).toVar();
|
|
323
|
+
const data2 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.IOR_TRANSMISSION ), int( MATERIAL_SLOTS ) ).toVar();
|
|
324
|
+
const data3 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ATTENUATION ), int( MATERIAL_SLOTS ) ).toVar();
|
|
325
|
+
const data4 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.DISPERSION_SHEEN ), int( MATERIAL_SLOTS ) ).toVar();
|
|
326
|
+
const data5 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.SHEEN_COLOR ), int( MATERIAL_SLOTS ) ).toVar();
|
|
327
|
+
const data6 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.SPECULAR ), int( MATERIAL_SLOTS ) ).toVar();
|
|
328
|
+
const data7 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.IRIDESCENCE ), int( MATERIAL_SLOTS ) ).toVar();
|
|
329
|
+
const data8 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.MAP_INDICES_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
330
|
+
const data9 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.MAP_INDICES_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
331
|
+
const data10 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.OPACITY_ALPHA ), int( MATERIAL_SLOTS ) ).toVar();
|
|
332
|
+
const data11 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ALPHA_MODE ), int( MATERIAL_SLOTS ) ).toVar();
|
|
333
|
+
const data12 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.BUMP_DISPLACEMENT ), int( MATERIAL_SLOTS ) ).toVar();
|
|
334
|
+
const data13 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ALBEDO_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
335
|
+
const data14 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ALBEDO_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
336
|
+
const data15 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.NORMAL_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
337
|
+
const data16 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.NORMAL_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
338
|
+
const data17 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ROUGHNESS_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
339
|
+
const data18 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ROUGHNESS_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
340
|
+
const data19 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.METALNESS_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
341
|
+
const data20 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.METALNESS_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
342
|
+
const data21 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.EMISSIVE_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
343
|
+
const data22 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.EMISSIVE_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
344
|
+
const data23 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.BUMP_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
345
|
+
const data24 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.BUMP_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
346
|
+
const data25 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.DISPLACEMENT_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
347
|
+
const data26 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.DISPLACEMENT_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
343
348
|
|
|
344
349
|
return RayTracingMaterial( {
|
|
345
350
|
color: vec4( data0.rgb, 1.0 ),
|
|
@@ -390,6 +395,35 @@ export const getMaterial = Fn( ( [ materialIndex, materialBuffer ] ) => {
|
|
|
390
395
|
|
|
391
396
|
} );
|
|
392
397
|
|
|
398
|
+
// ── Shadow material thin reader (7 slot reads instead of 27) ─────────────
|
|
399
|
+
// Only fetches fields needed by traceShadowRay: alpha, transmission, attenuation, albedo transform.
|
|
400
|
+
|
|
401
|
+
export const getShadowMaterial = Fn( ( [ materialIndex, materialBuffer ] ) => {
|
|
402
|
+
|
|
403
|
+
const data2 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.IOR_TRANSMISSION ), int( MATERIAL_SLOTS ) ).toVar();
|
|
404
|
+
const data3 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ATTENUATION ), int( MATERIAL_SLOTS ) ).toVar();
|
|
405
|
+
const data8 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.MAP_INDICES_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
406
|
+
const data10 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.OPACITY_ALPHA ), int( MATERIAL_SLOTS ) ).toVar();
|
|
407
|
+
const data11 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ALPHA_MODE ), int( MATERIAL_SLOTS ) ).toVar();
|
|
408
|
+
const data13 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ALBEDO_TRANSFORM_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
409
|
+
const data14 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.ALBEDO_TRANSFORM_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
410
|
+
|
|
411
|
+
return ShadowMaterial( {
|
|
412
|
+
color: vec4( 1.0 ), // Shadow path never samples full textures; color.a is always 1.0
|
|
413
|
+
ior: data2.r,
|
|
414
|
+
transmission: data2.g,
|
|
415
|
+
attenuationColor: data3.rgb,
|
|
416
|
+
attenuationDistance: data3.a,
|
|
417
|
+
albedoMapIndex: int( data8.r ),
|
|
418
|
+
opacity: data10.r,
|
|
419
|
+
transparent: data10.b,
|
|
420
|
+
alphaTest: data10.a,
|
|
421
|
+
alphaMode: int( data11.r ),
|
|
422
|
+
albedoTransform: arrayToMat3( { data1: data13, data2: data14 } ),
|
|
423
|
+
} );
|
|
424
|
+
|
|
425
|
+
} );
|
|
426
|
+
|
|
393
427
|
// ── Edge-stopping weight (normal + depth) ──────────────────────────────────
|
|
394
428
|
// Used by ASVGF and SSRC for temporal/spatial reprojection edge-stopping.
|
|
395
429
|
|
package/src/TSL/Debugger.js
CHANGED
|
@@ -356,8 +356,7 @@ export const TraceDebugMode = Fn( ( [
|
|
|
356
356
|
const bounceDir = cosineWeightedSample( { N: normalA, xi } ).toVar();
|
|
357
357
|
|
|
358
358
|
// Trace secondary ray from the hit point (offset along normal to avoid self-intersection)
|
|
359
|
-
const
|
|
360
|
-
const bounceOrigin = hitInfo.hitPoint.add( normalA.mul( debugEps ) ).toVar();
|
|
359
|
+
const bounceOrigin = hitInfo.hitPoint.add( normalA.mul( 0.001 ) ).toVar();
|
|
361
360
|
const bounceRay = Ray( { origin: bounceOrigin, direction: bounceDir } );
|
|
362
361
|
|
|
363
362
|
const bounceHit = HitInfo.wrap( traverseBVH(
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
} from 'three/tsl';
|
|
29
29
|
|
|
30
30
|
import { struct } from './structProxy.js';
|
|
31
|
-
import { MIN_PDF, getDatafromStorageBuffer, powerHeuristic } from './Common.js';
|
|
31
|
+
import { MIN_PDF, getDatafromStorageBuffer, powerHeuristic, MATERIAL_SLOTS, MATERIAL_SLOT } from './Common.js';
|
|
32
32
|
import { RandomValue } from './Random.js';
|
|
33
33
|
import { calculateMaterialPDF } from './LightsSampling.js';
|
|
34
34
|
|
|
@@ -326,9 +326,8 @@ export const calculateEmissiveLightPdf = Fn( ( [
|
|
|
326
326
|
const area = triangleArea( triData.v0, triData.v1, triData.v2 );
|
|
327
327
|
|
|
328
328
|
// Targeted material read: only fetch emissive data (2 vec4s instead of full 27)
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
const matData2 = getDatafromStorageBuffer( materialBuffer, triData.materialIndex, int( 2 ), MATERIAL_SLOTS );
|
|
329
|
+
const matData1 = getDatafromStorageBuffer( materialBuffer, triData.materialIndex, int( MATERIAL_SLOT.EMISSIVE_ROUGHNESS ), MATERIAL_SLOTS );
|
|
330
|
+
const matData2 = getDatafromStorageBuffer( materialBuffer, triData.materialIndex, int( MATERIAL_SLOT.IOR_TRANSMISSION ), MATERIAL_SLOTS );
|
|
332
331
|
const avgEmissive = matData1.x.add( matData1.y ).add( matData1.z ).div( 3.0 );
|
|
333
332
|
const power = max( avgEmissive.mul( matData2.a ).mul( area ), float( 1e-10 ) );
|
|
334
333
|
const selectionPdf = power.div( max( emissiveTotalPower, float( 1e-10 ) ) );
|
package/src/TSL/LightsCore.js
CHANGED
|
@@ -257,7 +257,7 @@ export const intersectAreaLight = Fn( ( [ light, rayOrigin, rayDirection ] ) =>
|
|
|
257
257
|
const t = dot( light.position.sub( rayOrigin ), normal ).mul( invDenom ).toVar();
|
|
258
258
|
|
|
259
259
|
// Skip intersections behind the ray
|
|
260
|
-
If( t.greaterThan(
|
|
260
|
+
If( t.greaterThan( 0.001 ), () => {
|
|
261
261
|
|
|
262
262
|
// Optimized rectangle test using vector rejection
|
|
263
263
|
const hitPoint = rayOrigin.add( rayDirection.mul( t ) );
|
package/src/TSL/LightsDirect.js
CHANGED
|
@@ -25,10 +25,11 @@ import {
|
|
|
25
25
|
clamp,
|
|
26
26
|
smoothstep,
|
|
27
27
|
select,
|
|
28
|
+
texture,
|
|
28
29
|
} from 'three/tsl';
|
|
29
30
|
|
|
30
|
-
import { Ray,
|
|
31
|
-
import { PI, TWO_PI, EPSILON, REC709_LUMINANCE_COEFFICIENTS, powerHeuristic,
|
|
31
|
+
import { Ray, ShadowMaterial, HitInfo, DirectionSample, MaterialCache } from './Struct.js';
|
|
32
|
+
import { PI, TWO_PI, EPSILON, REC709_LUMINANCE_COEFFICIENTS, powerHeuristic, getShadowMaterial, getDatafromStorageBuffer } from './Common.js';
|
|
32
33
|
import { fresnelSchlickFloat } from './Fresnel.js';
|
|
33
34
|
import { iorToFresnel0 } from './Fresnel.js';
|
|
34
35
|
import {
|
|
@@ -37,6 +38,33 @@ import {
|
|
|
37
38
|
} from './LightsCore.js';
|
|
38
39
|
import { calculateBeerLawAbsorption, calculateShadowTransmittance } from './MaterialTransmission.js';
|
|
39
40
|
import { RandomValue } from './Random.js';
|
|
41
|
+
import { getTransformedUV } from './TextureSampling.js';
|
|
42
|
+
|
|
43
|
+
// Module-level state for alpha-cutout shadow testing.
|
|
44
|
+
// Set by ShaderBuilder before graph construction (same pattern as _meshVisibilityBuffer in BVHTraversal.js).
|
|
45
|
+
let _shadowAlbedoMaps = null;
|
|
46
|
+
let _enableAlphaShadows = null;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Set the albedo texture array node for alpha-aware shadow rays.
|
|
50
|
+
* Must be called before the shader graph is constructed.
|
|
51
|
+
* @param {TextureNode} maps - TSL texture node for the albedo array
|
|
52
|
+
*/
|
|
53
|
+
export function setShadowAlbedoMaps( maps ) {
|
|
54
|
+
|
|
55
|
+
_shadowAlbedoMaps = maps;
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Set the runtime uniform node that toggles alpha-cutout shadows.
|
|
61
|
+
* @param {UniformNode} node - TSL int uniform (0 = disabled, 1 = enabled)
|
|
62
|
+
*/
|
|
63
|
+
export function setAlphaShadowsUniform( node ) {
|
|
64
|
+
|
|
65
|
+
_enableAlphaShadows = node;
|
|
66
|
+
|
|
67
|
+
}
|
|
40
68
|
|
|
41
69
|
// ================================================================================
|
|
42
70
|
// SHADOW RAY MATERIAL TRANSPARENCY
|
|
@@ -102,11 +130,82 @@ export const traceShadowRay = Fn( ( [
|
|
|
102
130
|
|
|
103
131
|
} );
|
|
104
132
|
|
|
105
|
-
// Fetch material for the hit surface
|
|
106
|
-
const shadowMaterial =
|
|
133
|
+
// Fetch material for the hit surface (thin reader: 7 slots instead of 27)
|
|
134
|
+
const shadowMaterial = ShadowMaterial.wrap( getShadowMaterial( shadowHit.materialIndex, materialBuffer ) );
|
|
135
|
+
|
|
136
|
+
// ---------------------------------------------------------------
|
|
137
|
+
// Alpha-cutout handling (MASK / BLEND with albedo texture alpha)
|
|
138
|
+
// Gated by runtime uniform + alphaMode check — zero overhead for opaque materials.
|
|
139
|
+
// UV computation deferred here from BVH traversal: barycentrics stored in shadowHit.uv,
|
|
140
|
+
// triangle index in shadowHit.triangleIndex. Actual UV interpolation only when needed.
|
|
141
|
+
// ---------------------------------------------------------------
|
|
142
|
+
const alphaCutout = tslBool( false ).toVar();
|
|
143
|
+
|
|
144
|
+
if ( _enableAlphaShadows ) If( _enableAlphaShadows.equal( int( 1 ) ), () => {
|
|
145
|
+
|
|
146
|
+
// Sample texture alpha once (shared by MASK and BLEND paths).
|
|
147
|
+
// Deferred UV: barycentrics in shadowHit.uv, triangle index in shadowHit.triangleIndex.
|
|
148
|
+
const texAlpha = float( 1.0 ).toVar();
|
|
149
|
+
|
|
150
|
+
if ( _shadowAlbedoMaps ) {
|
|
151
|
+
|
|
152
|
+
If( shadowMaterial.albedoMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
153
|
+
|
|
154
|
+
const baryU = shadowHit.uv.x;
|
|
155
|
+
const baryV = shadowHit.uv.y;
|
|
156
|
+
const baryW = float( 1.0 ).sub( baryU ).sub( baryV );
|
|
157
|
+
const TRI_STRIDE = int( 8 );
|
|
158
|
+
const uvData1 = getDatafromStorageBuffer( triangleBuffer, shadowHit.triangleIndex, int( 6 ), TRI_STRIDE );
|
|
159
|
+
const uvData2 = getDatafromStorageBuffer( triangleBuffer, shadowHit.triangleIndex, int( 7 ), TRI_STRIDE );
|
|
160
|
+
const hitUV = uvData1.xy.mul( baryW ).add( uvData1.zw.mul( baryU ) ).add( uvData2.xy.mul( baryV ) );
|
|
161
|
+
const albedoUV = getTransformedUV( { uv: hitUV, transform: shadowMaterial.albedoTransform } );
|
|
162
|
+
texAlpha.assign( texture( _shadowAlbedoMaps, albedoUV ).depth( int( shadowMaterial.albedoMapIndex ) ).a );
|
|
163
|
+
|
|
164
|
+
} );
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
If( shadowMaterial.alphaMode.equal( int( 1 ) ), () => {
|
|
169
|
+
|
|
170
|
+
// MASK mode: binary alpha cutout
|
|
171
|
+
const effectiveAlpha = shadowMaterial.color.a.mul( texAlpha );
|
|
172
|
+
const cutoff = select( shadowMaterial.alphaTest.greaterThan( 0.0 ), shadowMaterial.alphaTest, float( 0.5 ) );
|
|
173
|
+
If( effectiveAlpha.lessThan( cutoff ), () => {
|
|
174
|
+
|
|
175
|
+
alphaCutout.assign( true );
|
|
176
|
+
|
|
177
|
+
} );
|
|
178
|
+
|
|
179
|
+
} ).ElseIf( shadowMaterial.alphaMode.equal( int( 2 ) ), () => {
|
|
180
|
+
|
|
181
|
+
// BLEND mode: modulate transmittance by alpha
|
|
182
|
+
const blendAlpha = clamp( shadowMaterial.color.a.mul( shadowMaterial.opacity ).mul( texAlpha ), 0.0, 1.0 );
|
|
183
|
+
transmittance.mulAssign( float( 1.0 ).sub( blendAlpha ) );
|
|
184
|
+
|
|
185
|
+
If( transmittance.lessThan( 0.005 ), () => {
|
|
186
|
+
|
|
187
|
+
transmittance.assign( 0.0 );
|
|
188
|
+
Break();
|
|
189
|
+
|
|
190
|
+
} );
|
|
191
|
+
|
|
192
|
+
alphaCutout.assign( true );
|
|
193
|
+
|
|
194
|
+
} );
|
|
195
|
+
|
|
196
|
+
} );
|
|
197
|
+
|
|
198
|
+
// ---------------------------------------------------------------
|
|
199
|
+
// Surface interaction: alpha-skip, transmission, transparent, or opaque
|
|
200
|
+
// ---------------------------------------------------------------
|
|
201
|
+
If( alphaCutout, () => {
|
|
202
|
+
|
|
203
|
+
// Alpha-transparent surface — advance ray past it
|
|
204
|
+
const alphaEps = max( float( 1e-5 ), length( shadowHit.hitPoint ).mul( 1e-6 ) );
|
|
205
|
+
rayOrigin.assign( shadowHit.hitPoint.add( dir.mul( alphaEps ) ) );
|
|
206
|
+
remainingDist.subAssign( shadowHit.dst.add( alphaEps ) );
|
|
107
207
|
|
|
108
|
-
|
|
109
|
-
If( shadowMaterial.transmission.greaterThan( 0.0 ), () => {
|
|
208
|
+
} ).ElseIf( shadowMaterial.transmission.greaterThan( 0.0 ), () => {
|
|
110
209
|
|
|
111
210
|
const entering = dot( dir, shadowHit.normal ).lessThan( 0.0 );
|
|
112
211
|
const N = select( entering, shadowHit.normal, shadowHit.normal.negate() );
|
|
@@ -142,9 +241,8 @@ export const traceShadowRay = Fn( ( [
|
|
|
142
241
|
} );
|
|
143
242
|
|
|
144
243
|
// Continue ray past transmissive surface
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
remainingDist.subAssign( shadowHit.dst.add( transEps ) );
|
|
244
|
+
rayOrigin.assign( shadowHit.hitPoint.add( dir.mul( 0.001 ) ) );
|
|
245
|
+
remainingDist.subAssign( shadowHit.dst.add( 0.001 ) );
|
|
148
246
|
|
|
149
247
|
} ).ElseIf( shadowMaterial.transparent, () => {
|
|
150
248
|
|
|
@@ -159,9 +257,8 @@ export const traceShadowRay = Fn( ( [
|
|
|
159
257
|
} );
|
|
160
258
|
|
|
161
259
|
// Continue ray past transparent surface
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
remainingDist.subAssign( shadowHit.dst.add( alphaEps ) );
|
|
260
|
+
rayOrigin.assign( shadowHit.hitPoint.add( dir.mul( 0.001 ) ) );
|
|
261
|
+
remainingDist.subAssign( shadowHit.dst.add( 0.001 ) );
|
|
165
262
|
|
|
166
263
|
} ).Else( () => {
|
|
167
264
|
|
|
@@ -259,7 +356,7 @@ export const estimateLightImportance = Fn( ( [ light, hitPoint, normal, material
|
|
|
259
356
|
|
|
260
357
|
If( lightFacing.greaterThan( 0.0 ), () => {
|
|
261
358
|
|
|
262
|
-
const solidAngle = light.area.div( max( distSq,
|
|
359
|
+
const solidAngle = light.area.div( max( distSq, 0.1 ) );
|
|
263
360
|
const power = light.intensity.mul( dot( light.color, REC709_LUMINANCE_COEFFICIENTS ) ).mul( light.area );
|
|
264
361
|
|
|
265
362
|
// Material-aware weighting
|
|
@@ -661,7 +758,7 @@ export const calculatePointLightContribution = Fn( ( [
|
|
|
661
758
|
const rayOffset = calculateRayOffset( hitPoint, normal, material );
|
|
662
759
|
const rayOrigin = hitPoint.add( rayOffset );
|
|
663
760
|
|
|
664
|
-
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.
|
|
761
|
+
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.sub( 0.001 ), rngState );
|
|
665
762
|
|
|
666
763
|
If( visibility.greaterThan( 0.0 ), () => {
|
|
667
764
|
|
|
@@ -713,7 +810,7 @@ export const calculateSpotLightContribution = Fn( ( [
|
|
|
713
810
|
const rayOffset = calculateRayOffset( hitPoint, normal, material );
|
|
714
811
|
const rayOrigin = hitPoint.add( rayOffset );
|
|
715
812
|
|
|
716
|
-
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.
|
|
813
|
+
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.sub( 0.001 ), rngState );
|
|
717
814
|
|
|
718
815
|
If( visibility.greaterThan( 0.0 ), () => {
|
|
719
816
|
|
|
@@ -71,7 +71,6 @@ import {
|
|
|
71
71
|
calculatePointLightImportance,
|
|
72
72
|
calculateSpotLightImportance,
|
|
73
73
|
traceShadowRay,
|
|
74
|
-
calculateRayOffset,
|
|
75
74
|
} from './LightsDirect.js';
|
|
76
75
|
|
|
77
76
|
import { traverseBVHShadow } from './BVHTraversal.js';
|
|
@@ -941,7 +940,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
941
940
|
] ) => {
|
|
942
941
|
|
|
943
942
|
const totalContribution = vec3( 0.0 ).toVar();
|
|
944
|
-
const rayOrigin = hitPoint.add(
|
|
943
|
+
const rayOrigin = hitPoint.add( hitNormal.mul( 0.001 ) ).toVar();
|
|
945
944
|
|
|
946
945
|
// Early exit for highly emissive surfaces
|
|
947
946
|
If( material.emissiveIntensity.lessThanEqual( 10.0 ), () => {
|
|
@@ -1042,7 +1041,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
1042
1041
|
|
|
1043
1042
|
If( NoL.greaterThan( 0.0 ).and( lightImportance.mul( NoL ).greaterThan( importanceThreshold ) ).and( isDirectionValid( { direction: lightSample.direction, surfaceNormal: hitNormal } ) ), () => {
|
|
1044
1043
|
|
|
1045
|
-
const shadowDistance = min( lightSample.distance.
|
|
1044
|
+
const shadowDistance = min( lightSample.distance.sub( 0.001 ), float( 1000.0 ) ).toVar();
|
|
1046
1045
|
const visibility = traceShadowRay(
|
|
1047
1046
|
rayOrigin, lightSample.direction, shadowDistance, rngState,
|
|
1048
1047
|
traverseBVHShadow,
|