rayzee 7.10.3 → 7.11.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 +1 -1
- package/dist/rayzee.es.js +1591 -1321
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +69 -54
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/EngineDefaults.js +14 -5
- package/src/Processor/AssetLoader.js +11 -0
- package/src/Processor/GeometryExtractor.js +45 -13
- package/src/Processor/SceneProcessor.js +51 -0
- package/src/Processor/TextureCreator.js +21 -10
- package/src/TSL/Clearcoat.js +34 -10
- package/src/TSL/Common.js +80 -0
- package/src/TSL/EmissiveSampling.js +2 -2
- package/src/TSL/LightsDirect.js +3 -2
- package/src/TSL/LightsIndirect.js +4 -7
- package/src/TSL/LightsSampling.js +17 -6
- package/src/TSL/MaterialEvaluation.js +37 -9
- package/src/TSL/MaterialProperties.js +78 -2
- package/src/TSL/MaterialSampling.js +19 -0
- package/src/TSL/MaterialTransmission.js +3 -1
- package/src/TSL/PathTracerCore.js +35 -10
- package/src/TSL/ShadeKernel.js +31 -1
- package/src/TSL/Struct.js +39 -0
- package/src/TSL/TextureSampling.js +103 -1
- package/src/managers/MaterialDataManager.js +36 -3
package/package.json
CHANGED
package/src/EngineDefaults.js
CHANGED
|
@@ -390,8 +390,8 @@ export const TRIANGLE_DATA_LAYOUT = {
|
|
|
390
390
|
// Shared between CPU writers (TextureCreator, MaterialDataManager) and GPU readers (Common.js getMaterial).
|
|
391
391
|
export const MATERIAL_DATA_LAYOUT = {
|
|
392
392
|
|
|
393
|
-
SLOTS_PER_MATERIAL:
|
|
394
|
-
FLOATS_PER_MATERIAL:
|
|
393
|
+
SLOTS_PER_MATERIAL: 33, // vec4 slots per material
|
|
394
|
+
FLOATS_PER_MATERIAL: 132, // total floats per material (33 × 4)
|
|
395
395
|
|
|
396
396
|
// ── Flat float offsets (CPU side) ────────────────────────────────
|
|
397
397
|
// Used as: data[ materialIndex * FLOATS_PER_MATERIAL + offset ]
|
|
@@ -438,8 +438,14 @@ export const MATERIAL_DATA_LAYOUT = {
|
|
|
438
438
|
SUBSURFACE_COLOR: 108, SUBSURFACE: 111,
|
|
439
439
|
// Slot 28: subsurfaceRadius.rgb (mean free path) + radius scale
|
|
440
440
|
SUBSURFACE_RADIUS: 112, SUBSURFACE_RADIUS_SCALE: 115,
|
|
441
|
-
// Slot 29:
|
|
442
|
-
SUBSURFACE_ANISOTROPY: 116,
|
|
441
|
+
// Slot 29: subsurfaceAnisotropy g (116) + surface anisotropy (strength 117, rotation 118, map index 119)
|
|
442
|
+
SUBSURFACE_ANISOTROPY: 116, ANISOTROPY: 117, ANISOTROPY_ROTATION: 118, ANISOTROPY_MAP_INDEX: 119,
|
|
443
|
+
// Slot 30: extension-texture map indices A (transmission, clearcoat, clearcoatRoughness, sheenColor)
|
|
444
|
+
TRANSMISSION_MAP_INDEX: 120, CLEARCOAT_MAP_INDEX: 121, CLEARCOAT_ROUGHNESS_MAP_INDEX: 122, SHEEN_COLOR_MAP_INDEX: 123,
|
|
445
|
+
// Slot 31: extension-texture map indices B (sheenRoughness, iridescence, iridescenceThickness, specularIntensity)
|
|
446
|
+
SHEEN_ROUGHNESS_MAP_INDEX: 124, IRIDESCENCE_MAP_INDEX: 125, IRIDESCENCE_THICKNESS_MAP_INDEX: 126, SPECULAR_INTENSITY_MAP_INDEX: 127,
|
|
447
|
+
// Slot 32: extension-texture map indices C (specularColor + 3 reserved)
|
|
448
|
+
SPECULAR_COLOR_MAP_INDEX: 128,
|
|
443
449
|
|
|
444
450
|
// ── Vec4 slot indices (GPU/TSL side) ─────────────────────────────
|
|
445
451
|
// Used with getDatafromStorageBuffer( buf, matIdx, int(slot), int(SLOTS_PER_MATERIAL) )
|
|
@@ -466,7 +472,10 @@ export const MATERIAL_DATA_LAYOUT = {
|
|
|
466
472
|
DISPLACEMENT_TRANSFORM_A: 25, DISPLACEMENT_TRANSFORM_B: 26,
|
|
467
473
|
SUBSURFACE_A: 27, // subsurfaceColor.rgb, subsurface weight
|
|
468
474
|
SUBSURFACE_B: 28, // subsurfaceRadius.rgb, subsurfaceRadiusScale
|
|
469
|
-
SUBSURFACE_C: 29, // subsurfaceAnisotropy,
|
|
475
|
+
SUBSURFACE_C: 29, // subsurfaceAnisotropy g, anisotropy, anisotropyRotation, anisotropyMapIndex
|
|
476
|
+
EXT_MAP_INDICES_A: 30, // transmission, clearcoat, clearcoatRoughness, sheenColor map indices
|
|
477
|
+
EXT_MAP_INDICES_B: 31, // sheenRoughness, iridescence, iridescenceThickness, specularIntensity map indices
|
|
478
|
+
EXT_MAP_INDICES_C: 32, // specularColor map index + 3 reserved
|
|
470
479
|
},
|
|
471
480
|
|
|
472
481
|
};
|
|
@@ -1590,6 +1590,17 @@ export class AssetLoader extends EventDispatcher {
|
|
|
1590
1590
|
|
|
1591
1591
|
}
|
|
1592
1592
|
|
|
1593
|
+
// glTF punctual point/spot intensity is candela (W/sr); the engine's light
|
|
1594
|
+
// model is Blender-style Power (W) that LightSerializer divides by 4π. Convert
|
|
1595
|
+
// glTF candela → Power once at import (×4π) so it nets to the correct I/d².
|
|
1596
|
+
// Directional (lux ≈ irradiance) is used directly and needs no conversion.
|
|
1597
|
+
if ( ( object.isPointLight || object.isSpotLight ) && ! userData.__candelaConverted ) {
|
|
1598
|
+
|
|
1599
|
+
object.intensity *= 4 * Math.PI;
|
|
1600
|
+
userData.__candelaConverted = true;
|
|
1601
|
+
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1593
1604
|
// Process ceiling lights
|
|
1594
1605
|
if ( object.name.startsWith( 'RectAreaLightPlaceholder' ) &&
|
|
1595
1606
|
userData.name
|
|
@@ -292,7 +292,10 @@ export class GeometryExtractor {
|
|
|
292
292
|
subsurfaceColor: new Color( 0xffffff ),
|
|
293
293
|
subsurfaceRadius: [ 1.0, 0.2, 0.1 ], // skin-like: red travels furthest
|
|
294
294
|
subsurfaceRadiusScale: 1.0,
|
|
295
|
-
subsurfaceAnisotropy: 0.0
|
|
295
|
+
subsurfaceAnisotropy: 0.0,
|
|
296
|
+
// Surface specular anisotropy (native MeshPhysicalMaterial / KHR_materials_anisotropy)
|
|
297
|
+
anisotropy: 0.0,
|
|
298
|
+
anisotropyRotation: 0.0
|
|
296
299
|
};
|
|
297
300
|
|
|
298
301
|
}
|
|
@@ -399,7 +402,9 @@ export class GeometryExtractor {
|
|
|
399
402
|
emissiveIntensity: legacyMapping.emissiveIntensity ?? material.emissiveIntensity ?? defaults.emissiveIntensity,
|
|
400
403
|
|
|
401
404
|
// Surface properties
|
|
402
|
-
|
|
405
|
+
// Floor at 0.02 (the sampler's own VNDF-PDF clamp, MaterialProperties.js) rather than
|
|
406
|
+
// 0.05, so near-mirror metals stay sharp without entering a new firefly regime.
|
|
407
|
+
roughness: Math.max( 0.02, legacyMapping.roughness ?? material.roughness ?? defaults.roughness ),
|
|
403
408
|
metalness: legacyMapping.metalness ?? material.metalness ?? defaults.metalness,
|
|
404
409
|
|
|
405
410
|
// Optical properties
|
|
@@ -430,6 +435,10 @@ export class GeometryExtractor {
|
|
|
430
435
|
subsurfaceRadiusScale: material.subsurfaceRadiusScale ?? defaults.subsurfaceRadiusScale,
|
|
431
436
|
subsurfaceAnisotropy: material.subsurfaceAnisotropy ?? defaults.subsurfaceAnisotropy,
|
|
432
437
|
|
|
438
|
+
// Surface specular anisotropy (native MeshPhysicalMaterial / KHR_materials_anisotropy)
|
|
439
|
+
anisotropy: material.anisotropy ?? defaults.anisotropy,
|
|
440
|
+
anisotropyRotation: material.anisotropyRotation ?? defaults.anisotropyRotation,
|
|
441
|
+
|
|
433
442
|
// Specular properties (for compatibility)
|
|
434
443
|
specularIntensity: legacyMapping.specularIntensity ?? material.specularIntensity ?? defaults.specularIntensity,
|
|
435
444
|
specularColor: legacyMapping.specularColor ?? material.specularColor ?? defaults.specularColor,
|
|
@@ -456,18 +465,21 @@ export class GeometryExtractor {
|
|
|
456
465
|
metalnessMap: this.processTexture( material.metalnessMap, this.metalnessMaps ),
|
|
457
466
|
emissiveMap: this.processTexture( material.emissiveMap, this.emissiveMaps ),
|
|
458
467
|
displacementMap: this.processTexture( material.displacementMap, this.displacementMaps ),
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
468
|
+
anisotropyMap: this.processTexture( material.anisotropyMap, this.anisotropyMaps ),
|
|
469
|
+
|
|
470
|
+
// Advanced texture maps (MeshPhysicalMaterial only). Folded into their scalar factors
|
|
471
|
+
// in ShadeKernel (applyExtensionMaps). thicknessMap stays dropped — thickness has no
|
|
472
|
+
// render effect yet (see gap-plan Phase 4.4).
|
|
473
|
+
clearcoatMap: this.processTexture( material.clearcoatMap, this.clearcoatMaps ),
|
|
474
|
+
clearcoatRoughnessMap: this.processTexture( material.clearcoatRoughnessMap, this.clearcoatRoughnessMaps ),
|
|
475
|
+
transmissionMap: this.processTexture( material.transmissionMap, this.transmissionMaps ),
|
|
464
476
|
thicknessMap: this.processTexture( material.thicknessMap, [] ),
|
|
465
|
-
sheenColorMap: this.processTexture( material.sheenColorMap,
|
|
466
|
-
sheenRoughnessMap: this.processTexture( material.sheenRoughnessMap,
|
|
467
|
-
specularIntensityMap: this.processTexture( material.specularIntensityMap,
|
|
468
|
-
specularColorMap: this.processTexture( material.specularColorMap,
|
|
469
|
-
iridescenceMap: this.processTexture( material.iridescenceMap,
|
|
470
|
-
iridescenceThicknessMap: this.processTexture( material.iridescenceThicknessMap,
|
|
477
|
+
sheenColorMap: this.processTexture( material.sheenColorMap, this.sheenColorMaps ),
|
|
478
|
+
sheenRoughnessMap: this.processTexture( material.sheenRoughnessMap, this.sheenRoughnessMaps ),
|
|
479
|
+
specularIntensityMap: this.processTexture( material.specularIntensityMap, this.specularIntensityMaps ),
|
|
480
|
+
specularColorMap: this.processTexture( material.specularColorMap, this.specularColorMaps ),
|
|
481
|
+
iridescenceMap: this.processTexture( material.iridescenceMap, this.iridescenceMaps ),
|
|
482
|
+
iridescenceThicknessMap: this.processTexture( material.iridescenceThicknessMap, this.iridescenceThicknessMaps ),
|
|
471
483
|
|
|
472
484
|
// Texture transformation matrices
|
|
473
485
|
mapMatrix: this.getTextureMatrix( material.map ),
|
|
@@ -819,6 +831,16 @@ export class GeometryExtractor {
|
|
|
819
831
|
this.emissiveMaps = [];
|
|
820
832
|
this.roughnessMaps = [];
|
|
821
833
|
this.displacementMaps = [];
|
|
834
|
+
this.anisotropyMaps = [];
|
|
835
|
+
this.transmissionMaps = [];
|
|
836
|
+
this.clearcoatMaps = [];
|
|
837
|
+
this.clearcoatRoughnessMaps = [];
|
|
838
|
+
this.sheenColorMaps = [];
|
|
839
|
+
this.sheenRoughnessMaps = [];
|
|
840
|
+
this.iridescenceMaps = [];
|
|
841
|
+
this.iridescenceThicknessMaps = [];
|
|
842
|
+
this.specularIntensityMaps = [];
|
|
843
|
+
this.specularColorMaps = [];
|
|
822
844
|
this.directionalLights = [];
|
|
823
845
|
this.cameras = [];
|
|
824
846
|
|
|
@@ -857,6 +879,16 @@ export class GeometryExtractor {
|
|
|
857
879
|
emissiveMaps: this.emissiveMaps,
|
|
858
880
|
roughnessMaps: this.roughnessMaps,
|
|
859
881
|
displacementMaps: this.displacementMaps,
|
|
882
|
+
anisotropyMaps: this.anisotropyMaps,
|
|
883
|
+
transmissionMaps: this.transmissionMaps,
|
|
884
|
+
clearcoatMaps: this.clearcoatMaps,
|
|
885
|
+
clearcoatRoughnessMaps: this.clearcoatRoughnessMaps,
|
|
886
|
+
sheenColorMaps: this.sheenColorMaps,
|
|
887
|
+
sheenRoughnessMaps: this.sheenRoughnessMaps,
|
|
888
|
+
iridescenceMaps: this.iridescenceMaps,
|
|
889
|
+
iridescenceThicknessMaps: this.iridescenceThicknessMaps,
|
|
890
|
+
specularIntensityMaps: this.specularIntensityMaps,
|
|
891
|
+
specularColorMaps: this.specularColorMaps,
|
|
860
892
|
directionalLights: this.directionalLights,
|
|
861
893
|
cameras: this.cameras,
|
|
862
894
|
sceneFeatures: this.sceneFeatures // Scene-wide material feature flags
|
|
@@ -63,6 +63,16 @@ export class SceneProcessor {
|
|
|
63
63
|
this.metalnessMaps = [];
|
|
64
64
|
this.emissiveMaps = [];
|
|
65
65
|
this.displacementMaps = [];
|
|
66
|
+
this.anisotropyMaps = [];
|
|
67
|
+
this.transmissionMaps = [];
|
|
68
|
+
this.clearcoatMaps = [];
|
|
69
|
+
this.clearcoatRoughnessMaps = [];
|
|
70
|
+
this.sheenColorMaps = [];
|
|
71
|
+
this.sheenRoughnessMaps = [];
|
|
72
|
+
this.iridescenceMaps = [];
|
|
73
|
+
this.iridescenceThicknessMaps = [];
|
|
74
|
+
this.specularIntensityMaps = [];
|
|
75
|
+
this.specularColorMaps = [];
|
|
66
76
|
this.directionalLights = [];
|
|
67
77
|
this.cameras = [];
|
|
68
78
|
this.spheres = [];
|
|
@@ -320,6 +330,16 @@ export class SceneProcessor {
|
|
|
320
330
|
this.metalnessMaps = extractedData.metalnessMaps;
|
|
321
331
|
this.emissiveMaps = extractedData.emissiveMaps;
|
|
322
332
|
this.displacementMaps = extractedData.displacementMaps;
|
|
333
|
+
this.anisotropyMaps = extractedData.anisotropyMaps;
|
|
334
|
+
this.transmissionMaps = extractedData.transmissionMaps;
|
|
335
|
+
this.clearcoatMaps = extractedData.clearcoatMaps;
|
|
336
|
+
this.clearcoatRoughnessMaps = extractedData.clearcoatRoughnessMaps;
|
|
337
|
+
this.sheenColorMaps = extractedData.sheenColorMaps;
|
|
338
|
+
this.sheenRoughnessMaps = extractedData.sheenRoughnessMaps;
|
|
339
|
+
this.iridescenceMaps = extractedData.iridescenceMaps;
|
|
340
|
+
this.iridescenceThicknessMaps = extractedData.iridescenceThicknessMaps;
|
|
341
|
+
this.specularIntensityMaps = extractedData.specularIntensityMaps;
|
|
342
|
+
this.specularColorMaps = extractedData.specularColorMaps;
|
|
323
343
|
this.directionalLights = extractedData.directionalLights;
|
|
324
344
|
this.cameras = extractedData.cameras;
|
|
325
345
|
this.sceneFeatures = extractedData.sceneFeatures; // Store material feature flags for shader optimization
|
|
@@ -883,6 +903,17 @@ export class SceneProcessor {
|
|
|
883
903
|
roughness: remapType( this.roughnessMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
884
904
|
metalness: remapType( this.metalnessMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
885
905
|
displacement: remapType( this.displacementMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
906
|
+
anisotropy: remapType( this.anisotropyMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
907
|
+
// Extension maps — data maps → linear pool; color maps (sheenColor, specularColor) → sRGB pool.
|
|
908
|
+
transmission: remapType( this.transmissionMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
909
|
+
clearcoat: remapType( this.clearcoatMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
910
|
+
clearcoatRoughness: remapType( this.clearcoatRoughnessMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
911
|
+
sheenColor: remapType( this.sheenColorMaps, srgbLists, srgbDedup, this._srgbTexPacked ),
|
|
912
|
+
sheenRoughness: remapType( this.sheenRoughnessMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
913
|
+
iridescence: remapType( this.iridescenceMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
914
|
+
iridescenceThickness: remapType( this.iridescenceThicknessMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
915
|
+
specularIntensity: remapType( this.specularIntensityMaps, linearLists, linearDedup, this._linearTexPacked ),
|
|
916
|
+
specularColor: remapType( this.specularColorMaps, srgbLists, srgbDedup, this._srgbTexPacked ),
|
|
886
917
|
};
|
|
887
918
|
|
|
888
919
|
return { srgbLists, linearLists, remap };
|
|
@@ -907,6 +938,16 @@ export class SceneProcessor {
|
|
|
907
938
|
mat.roughnessMap = fix( mat.roughnessMap, remap.roughness );
|
|
908
939
|
mat.metalnessMap = fix( mat.metalnessMap, remap.metalness );
|
|
909
940
|
mat.displacementMap = fix( mat.displacementMap, remap.displacement );
|
|
941
|
+
mat.anisotropyMap = fix( mat.anisotropyMap, remap.anisotropy );
|
|
942
|
+
mat.transmissionMap = fix( mat.transmissionMap, remap.transmission );
|
|
943
|
+
mat.clearcoatMap = fix( mat.clearcoatMap, remap.clearcoat );
|
|
944
|
+
mat.clearcoatRoughnessMap = fix( mat.clearcoatRoughnessMap, remap.clearcoatRoughness );
|
|
945
|
+
mat.sheenColorMap = fix( mat.sheenColorMap, remap.sheenColor );
|
|
946
|
+
mat.sheenRoughnessMap = fix( mat.sheenRoughnessMap, remap.sheenRoughness );
|
|
947
|
+
mat.iridescenceMap = fix( mat.iridescenceMap, remap.iridescence );
|
|
948
|
+
mat.iridescenceThicknessMap = fix( mat.iridescenceThicknessMap, remap.iridescenceThickness );
|
|
949
|
+
mat.specularIntensityMap = fix( mat.specularIntensityMap, remap.specularIntensity );
|
|
950
|
+
mat.specularColorMap = fix( mat.specularColorMap, remap.specularColor );
|
|
910
951
|
|
|
911
952
|
}
|
|
912
953
|
|
|
@@ -984,6 +1025,16 @@ export class SceneProcessor {
|
|
|
984
1025
|
this.metalnessMaps = [];
|
|
985
1026
|
this.emissiveMaps = [];
|
|
986
1027
|
this.displacementMaps = [];
|
|
1028
|
+
this.anisotropyMaps = [];
|
|
1029
|
+
this.transmissionMaps = [];
|
|
1030
|
+
this.clearcoatMaps = [];
|
|
1031
|
+
this.clearcoatRoughnessMaps = [];
|
|
1032
|
+
this.sheenColorMaps = [];
|
|
1033
|
+
this.sheenRoughnessMaps = [];
|
|
1034
|
+
this.iridescenceMaps = [];
|
|
1035
|
+
this.iridescenceThicknessMaps = [];
|
|
1036
|
+
this.specularIntensityMaps = [];
|
|
1037
|
+
this.specularColorMaps = [];
|
|
987
1038
|
this.directionalLights = [];
|
|
988
1039
|
this.cameras = [];
|
|
989
1040
|
this.spheres = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataArrayTexture, RGBAFormat, LinearFilter, UnsignedByteType, SRGBColorSpace } from "three";
|
|
1
|
+
import { DataArrayTexture, RGBAFormat, LinearFilter, UnsignedByteType, SRGBColorSpace, RepeatWrapping } from "three";
|
|
2
2
|
import { TEXTURE_CONSTANTS, MEMORY_CONSTANTS, DEFAULT_TEXTURE_MATRIX, MATERIAL_DATA_LAYOUT } from '../EngineDefaults.js';
|
|
3
3
|
import { fetchAsWorker } from './Workers/fetchAsWorker.js';
|
|
4
4
|
import TEXTURES_WORKER_URL from './Workers/TexturesWorker.js?worker&url';
|
|
@@ -983,25 +983,31 @@ export class TextureCreator {
|
|
|
983
983
|
// Slot 12: displacement
|
|
984
984
|
mat.bumpScale, mat.displacementScale, mat.displacementMap, 0,
|
|
985
985
|
mapMatrix[ 0 ], mapMatrix[ 1 ], mapMatrix[ 2 ], mapMatrix[ 3 ],
|
|
986
|
-
mapMatrix[ 4 ], mapMatrix[ 5 ], mapMatrix[ 6 ],
|
|
986
|
+
mapMatrix[ 4 ], mapMatrix[ 5 ], mapMatrix[ 6 ], mapMatrix[ 7 ],
|
|
987
987
|
normalMapMatrices[ 0 ], normalMapMatrices[ 1 ], normalMapMatrices[ 2 ], normalMapMatrices[ 3 ],
|
|
988
|
-
normalMapMatrices[ 4 ], normalMapMatrices[ 5 ], normalMapMatrices[ 6 ],
|
|
988
|
+
normalMapMatrices[ 4 ], normalMapMatrices[ 5 ], normalMapMatrices[ 6 ], normalMapMatrices[ 7 ],
|
|
989
989
|
roughnessMapMatrices[ 0 ], roughnessMapMatrices[ 1 ], roughnessMapMatrices[ 2 ], roughnessMapMatrices[ 3 ],
|
|
990
|
-
roughnessMapMatrices[ 4 ], roughnessMapMatrices[ 5 ], roughnessMapMatrices[ 6 ],
|
|
990
|
+
roughnessMapMatrices[ 4 ], roughnessMapMatrices[ 5 ], roughnessMapMatrices[ 6 ], roughnessMapMatrices[ 7 ],
|
|
991
991
|
metalnessMapMatrices[ 0 ], metalnessMapMatrices[ 1 ], metalnessMapMatrices[ 2 ], metalnessMapMatrices[ 3 ],
|
|
992
|
-
metalnessMapMatrices[ 4 ], metalnessMapMatrices[ 5 ], metalnessMapMatrices[ 6 ],
|
|
992
|
+
metalnessMapMatrices[ 4 ], metalnessMapMatrices[ 5 ], metalnessMapMatrices[ 6 ], metalnessMapMatrices[ 7 ],
|
|
993
993
|
emissiveMapMatrices[ 0 ], emissiveMapMatrices[ 1 ], emissiveMapMatrices[ 2 ], emissiveMapMatrices[ 3 ],
|
|
994
|
-
emissiveMapMatrices[ 4 ], emissiveMapMatrices[ 5 ], emissiveMapMatrices[ 6 ],
|
|
994
|
+
emissiveMapMatrices[ 4 ], emissiveMapMatrices[ 5 ], emissiveMapMatrices[ 6 ], emissiveMapMatrices[ 7 ],
|
|
995
995
|
bumpMapMatrices[ 0 ], bumpMapMatrices[ 1 ], bumpMapMatrices[ 2 ], bumpMapMatrices[ 3 ],
|
|
996
|
-
bumpMapMatrices[ 4 ], bumpMapMatrices[ 5 ], bumpMapMatrices[ 6 ],
|
|
996
|
+
bumpMapMatrices[ 4 ], bumpMapMatrices[ 5 ], bumpMapMatrices[ 6 ], bumpMapMatrices[ 7 ],
|
|
997
997
|
displacementMapMatrices[ 0 ], displacementMapMatrices[ 1 ], displacementMapMatrices[ 2 ], displacementMapMatrices[ 3 ],
|
|
998
|
-
displacementMapMatrices[ 4 ], displacementMapMatrices[ 5 ], displacementMapMatrices[ 6 ],
|
|
998
|
+
displacementMapMatrices[ 4 ], displacementMapMatrices[ 5 ], displacementMapMatrices[ 6 ], displacementMapMatrices[ 7 ],
|
|
999
999
|
// Slot 27: subsurface (subsurfaceColor.rgb, subsurface weight)
|
|
1000
1000
|
mat.subsurfaceColor?.r ?? 1, mat.subsurfaceColor?.g ?? 1, mat.subsurfaceColor?.b ?? 1, mat.subsurface ?? 0,
|
|
1001
1001
|
// Slot 28: subsurface (subsurfaceRadius.rgb, subsurfaceRadiusScale)
|
|
1002
1002
|
mat.subsurfaceRadius?.[ 0 ] ?? 1, mat.subsurfaceRadius?.[ 1 ] ?? 0.2, mat.subsurfaceRadius?.[ 2 ] ?? 0.1, mat.subsurfaceRadiusScale ?? 1,
|
|
1003
|
-
// Slot 29:
|
|
1004
|
-
mat.subsurfaceAnisotropy ?? 0, 0, 0,
|
|
1003
|
+
// Slot 29: subsurfaceAnisotropy g + surface anisotropy (strength, rotation, map index)
|
|
1004
|
+
mat.subsurfaceAnisotropy ?? 0, mat.anisotropy ?? 0, mat.anisotropyRotation ?? 0, mat.anisotropyMap ?? - 1,
|
|
1005
|
+
// Slot 30: extension map indices A (transmission, clearcoat, clearcoatRoughness, sheenColor)
|
|
1006
|
+
mat.transmissionMap ?? - 1, mat.clearcoatMap ?? - 1, mat.clearcoatRoughnessMap ?? - 1, mat.sheenColorMap ?? - 1,
|
|
1007
|
+
// Slot 31: extension map indices B (sheenRoughness, iridescence, iridescenceThickness, specularIntensity)
|
|
1008
|
+
mat.sheenRoughnessMap ?? - 1, mat.iridescenceMap ?? - 1, mat.iridescenceThicknessMap ?? - 1, mat.specularIntensityMap ?? - 1,
|
|
1009
|
+
// Slot 32: extension map indices C (specularColor + 3 reserved)
|
|
1010
|
+
mat.specularColorMap ?? - 1, 0, 0, 0,
|
|
1005
1011
|
];
|
|
1006
1012
|
|
|
1007
1013
|
data.set( materialData, stride );
|
|
@@ -1314,6 +1320,11 @@ export class TextureCreator {
|
|
|
1314
1320
|
|
|
1315
1321
|
texture.minFilter = LinearFilter;
|
|
1316
1322
|
texture.magFilter = LinearFilter;
|
|
1323
|
+
// glTF's default sampler wrap is REPEAT; array layers are independent (not an atlas),
|
|
1324
|
+
// so per-layer repeat is safe and lets tiling UVs (outside [0,1]) tile instead of
|
|
1325
|
+
// clamping. MIRRORED_REPEAT / per-texture wrap is a follow-up (not stored per-slot yet).
|
|
1326
|
+
texture.wrapS = RepeatWrapping;
|
|
1327
|
+
texture.wrapT = RepeatWrapping;
|
|
1317
1328
|
texture.format = RGBAFormat;
|
|
1318
1329
|
texture.type = UnsignedByteType;
|
|
1319
1330
|
texture.needsUpdate = true;
|
package/src/TSL/Clearcoat.js
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
Fn,
|
|
3
3
|
vec3,
|
|
4
4
|
float,
|
|
5
|
+
dot,
|
|
5
6
|
normalize,
|
|
6
7
|
reflect,
|
|
7
8
|
max,
|
|
@@ -10,10 +11,10 @@ import {
|
|
|
10
11
|
|
|
11
12
|
import { struct } from './patches.js';
|
|
12
13
|
|
|
13
|
-
import { DotProducts } from './Struct.js';
|
|
14
|
-
import { PI, MIN_CLEARCOAT_ROUGHNESS,
|
|
15
|
-
import { DistributionGGX } from './MaterialProperties.js';
|
|
16
|
-
import { ImportanceSampleGGX, ImportanceSampleCosine } from './MaterialSampling.js';
|
|
14
|
+
import { AnisoFrame, DotProducts } from './Struct.js';
|
|
15
|
+
import { PI, MIN_CLEARCOAT_ROUGHNESS, computeDotProductsAniso, anisoTangentFrame } from './Common.js';
|
|
16
|
+
import { DistributionGGX, computeAnisoAlphas, calculateVNDFPDFAniso } from './MaterialProperties.js';
|
|
17
|
+
import { ImportanceSampleGGX, ImportanceSampleCosine, sampleGGXVNDFAniso } from './MaterialSampling.js';
|
|
17
18
|
import { evaluateLayeredBRDF } from './MaterialEvaluation.js';
|
|
18
19
|
import { RandomValue } from './Random.js';
|
|
19
20
|
|
|
@@ -62,8 +63,20 @@ export const sampleClearcoat = Fn( ( [
|
|
|
62
63
|
|
|
63
64
|
} ).ElseIf( rand.lessThan( clearcoatWeight.add( specularWeight ) ), () => {
|
|
64
65
|
|
|
65
|
-
// Sample base specular
|
|
66
|
-
|
|
66
|
+
// Sample base specular (anisotropic VNDF when anisotropy > 0)
|
|
67
|
+
If( material.anisotropy.greaterThan( 0.0 ), () => {
|
|
68
|
+
|
|
69
|
+
const f = AnisoFrame.wrap( anisoTangentFrame( N, material.anisotropyRotation ) );
|
|
70
|
+
const localV = vec3( dot( V, f.Ta ), dot( V, f.Ba ), dot( V, N ) );
|
|
71
|
+
const a = computeAnisoAlphas( material.roughness, material.anisotropy );
|
|
72
|
+
const localH = sampleGGXVNDFAniso( { V: localV, alphaX: a.x, alphaY: a.y, Xi: randomSample } );
|
|
73
|
+
H.assign( f.Ta.mul( localH.x ).add( f.Ba.mul( localH.y ) ).add( N.mul( localH.z ) ) );
|
|
74
|
+
|
|
75
|
+
} ).Else( () => {
|
|
76
|
+
|
|
77
|
+
H.assign( ImportanceSampleGGX( { N, roughness: baseRoughness, Xi: randomSample } ) );
|
|
78
|
+
|
|
79
|
+
} );
|
|
67
80
|
L.assign( reflect( V.negate(), H ) );
|
|
68
81
|
|
|
69
82
|
} ).Else( () => {
|
|
@@ -74,12 +87,23 @@ export const sampleClearcoat = Fn( ( [
|
|
|
74
87
|
|
|
75
88
|
} );
|
|
76
89
|
|
|
77
|
-
// Calculate dot products
|
|
78
|
-
const dots = DotProducts.wrap(
|
|
90
|
+
// Calculate dot products (aniso-aware: also projects onto the anisotropy frame)
|
|
91
|
+
const dots = DotProducts.wrap( computeDotProductsAniso( N, V, L, material ) );
|
|
79
92
|
|
|
80
|
-
// Calculate individual PDFs
|
|
93
|
+
// Calculate individual PDFs. Clearcoat layer is always isotropic; the base specular
|
|
94
|
+
// matches its sampler — VNDF-aniso when anisotropy>0, else the half-vector GGX pdf.
|
|
81
95
|
const clearcoatPDF = DistributionGGX( dots.NoH, clearcoatRoughness ).mul( dots.NoH ).div( float( 4.0 ).mul( dots.VoH ) ).mul( clearcoatWeight );
|
|
82
|
-
const specularPDF =
|
|
96
|
+
const specularPDF = float( 0.0 ).toVar();
|
|
97
|
+
If( material.anisotropy.greaterThan( 0.0 ), () => {
|
|
98
|
+
|
|
99
|
+
const a = computeAnisoAlphas( material.roughness, material.anisotropy );
|
|
100
|
+
specularPDF.assign( calculateVNDFPDFAniso( a.x, a.y, dots.NoH, dots.ToH, dots.BoH, dots.NoV, dots.ToV, dots.BoV ).mul( specularWeight ) );
|
|
101
|
+
|
|
102
|
+
} ).Else( () => {
|
|
103
|
+
|
|
104
|
+
specularPDF.assign( DistributionGGX( dots.NoH, baseRoughness ).mul( dots.NoH ).div( float( 4.0 ).mul( dots.VoH ) ).mul( specularWeight ) );
|
|
105
|
+
|
|
106
|
+
} );
|
|
83
107
|
const diffusePDF = dots.NoL.div( PI ).mul( diffuseWeight );
|
|
84
108
|
|
|
85
109
|
// Combined PDF using MIS
|
package/src/TSL/Common.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Fn, wgslFn, float, vec2, vec3, vec4, int, mat3, If, max, dot, clamp, bool as tslBool } from 'three/tsl';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
AnisoFrame,
|
|
4
5
|
DotProducts,
|
|
5
6
|
MaterialClassification,
|
|
6
7
|
MISStrategy,
|
|
@@ -155,6 +156,58 @@ export const computeDotProducts = Fn( ( [ N, V, L ] ) => {
|
|
|
155
156
|
NoH: max( dot( N, H ), 0.001 ),
|
|
156
157
|
VoH: max( dot( V, H ), 0.001 ),
|
|
157
158
|
LoH: max( dot( L, H ), 0.001 ),
|
|
159
|
+
ToH: float( 0.0 ), BoH: float( 0.0 ),
|
|
160
|
+
ToV: float( 0.0 ), BoV: float( 0.0 ),
|
|
161
|
+
ToL: float( 0.0 ), BoL: float( 0.0 ),
|
|
162
|
+
} );
|
|
163
|
+
|
|
164
|
+
} );
|
|
165
|
+
|
|
166
|
+
// Anisotropy tangent frame: arbitrary ONB from N (matching constructTBN + normal mapping),
|
|
167
|
+
// rotated by anisotropyRotation. Single source of truth for sampler AND eval/PDF so their
|
|
168
|
+
// frames are bit-identical (required for MIS consistency).
|
|
169
|
+
export const anisoTangentFrame = Fn( ( [ N, rotation ] ) => {
|
|
170
|
+
|
|
171
|
+
const majorAxis = N.x.abs().lessThan( 0.999 ).select( vec3( 1.0, 0.0, 0.0 ), vec3( 0.0, 1.0, 0.0 ) );
|
|
172
|
+
const T0 = N.cross( majorAxis ).normalize();
|
|
173
|
+
const B0 = N.cross( T0 ).normalize();
|
|
174
|
+
const c = rotation.cos();
|
|
175
|
+
const s = rotation.sin();
|
|
176
|
+
return AnisoFrame( { Ta: T0.mul( c ).add( B0.mul( s ) ), Ba: B0.mul( c ).sub( T0.mul( s ) ) } );
|
|
177
|
+
|
|
178
|
+
} );
|
|
179
|
+
|
|
180
|
+
// Anisotropy-aware dot products: computeDotProducts + tangent-frame projections of H/V/L
|
|
181
|
+
// (0 for isotropic materials, so aniso branches gated on anisotropy>0 are a no-op).
|
|
182
|
+
export const computeDotProductsAniso = Fn( ( [ N, V, L, material ] ) => {
|
|
183
|
+
|
|
184
|
+
const H = V.add( L ).toVar();
|
|
185
|
+
const lenSq = dot( H, H ).toVar();
|
|
186
|
+
H.assign( lenSq.greaterThan( EPSILON ).select( H.div( lenSq.sqrt() ), vec3( 0.0, 0.0, 1.0 ) ) );
|
|
187
|
+
|
|
188
|
+
const ToH = float( 0.0 ).toVar();
|
|
189
|
+
const BoH = float( 0.0 ).toVar();
|
|
190
|
+
const ToV = float( 0.0 ).toVar();
|
|
191
|
+
const BoV = float( 0.0 ).toVar();
|
|
192
|
+
const ToL = float( 0.0 ).toVar();
|
|
193
|
+
const BoL = float( 0.0 ).toVar();
|
|
194
|
+
|
|
195
|
+
If( material.anisotropy.greaterThan( 0.0 ), () => {
|
|
196
|
+
|
|
197
|
+
const f = AnisoFrame.wrap( anisoTangentFrame( N, material.anisotropyRotation ) );
|
|
198
|
+
ToH.assign( dot( f.Ta, H ) ); BoH.assign( dot( f.Ba, H ) );
|
|
199
|
+
ToV.assign( dot( f.Ta, V ) ); BoV.assign( dot( f.Ba, V ) );
|
|
200
|
+
ToL.assign( dot( f.Ta, L ) ); BoL.assign( dot( f.Ba, L ) );
|
|
201
|
+
|
|
202
|
+
} );
|
|
203
|
+
|
|
204
|
+
return DotProducts( {
|
|
205
|
+
NoL: max( dot( N, L ), 0.001 ),
|
|
206
|
+
NoV: max( dot( N, V ), 0.001 ),
|
|
207
|
+
NoH: max( dot( N, H ), 0.001 ),
|
|
208
|
+
VoH: max( dot( V, H ), 0.001 ),
|
|
209
|
+
LoH: max( dot( L, H ), 0.001 ),
|
|
210
|
+
ToH, BoH, ToV, BoV, ToL, BoL,
|
|
158
211
|
} );
|
|
159
212
|
|
|
160
213
|
} );
|
|
@@ -345,6 +398,9 @@ export const getMaterial = Fn( ( [ materialIndex, materialBuffer ] ) => {
|
|
|
345
398
|
const data27 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.SUBSURFACE_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
346
399
|
const data28 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.SUBSURFACE_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
347
400
|
const data29 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.SUBSURFACE_C ), int( MATERIAL_SLOTS ) ).toVar();
|
|
401
|
+
const data30 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.EXT_MAP_INDICES_A ), int( MATERIAL_SLOTS ) ).toVar();
|
|
402
|
+
const data31 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.EXT_MAP_INDICES_B ), int( MATERIAL_SLOTS ) ).toVar();
|
|
403
|
+
const data32 = getDatafromStorageBuffer( materialBuffer, materialIndex, int( S.EXT_MAP_INDICES_C ), int( MATERIAL_SLOTS ) ).toVar();
|
|
348
404
|
|
|
349
405
|
return RayTracingMaterial( {
|
|
350
406
|
color: vec4( data0.rgb, 1.0 ),
|
|
@@ -371,6 +427,18 @@ export const getMaterial = Fn( ( [ materialIndex, materialBuffer ] ) => {
|
|
|
371
427
|
subsurfaceRadius: data28.rgb,
|
|
372
428
|
subsurfaceRadiusScale: data28.a,
|
|
373
429
|
subsurfaceAnisotropy: data29.r,
|
|
430
|
+
anisotropy: data29.g,
|
|
431
|
+
anisotropyRotation: data29.b,
|
|
432
|
+
anisotropyMapIndex: int( data29.a ),
|
|
433
|
+
transmissionMapIndex: int( data30.r ),
|
|
434
|
+
clearcoatMapIndex: int( data30.g ),
|
|
435
|
+
clearcoatRoughnessMapIndex: int( data30.b ),
|
|
436
|
+
sheenColorMapIndex: int( data30.a ),
|
|
437
|
+
sheenRoughnessMapIndex: int( data31.r ),
|
|
438
|
+
iridescenceMapIndex: int( data31.g ),
|
|
439
|
+
iridescenceThicknessMapIndex: int( data31.b ),
|
|
440
|
+
specularIntensityMapIndex: int( data31.a ),
|
|
441
|
+
specularColorMapIndex: int( data32.r ),
|
|
374
442
|
albedoMapIndex: int( data8.r ),
|
|
375
443
|
normalMapIndex: int( data8.g ),
|
|
376
444
|
roughnessMapIndex: int( data8.b ),
|
|
@@ -458,6 +526,18 @@ export const diffuseGroundMaterial = Fn( () => {
|
|
|
458
526
|
subsurfaceRadius: vec3( 1.0, 0.2, 0.1 ),
|
|
459
527
|
subsurfaceRadiusScale: float( 1.0 ),
|
|
460
528
|
subsurfaceAnisotropy: float( 0.0 ),
|
|
529
|
+
anisotropy: float( 0.0 ),
|
|
530
|
+
anisotropyRotation: float( 0.0 ),
|
|
531
|
+
anisotropyMapIndex: int( - 1 ),
|
|
532
|
+
transmissionMapIndex: int( - 1 ),
|
|
533
|
+
clearcoatMapIndex: int( - 1 ),
|
|
534
|
+
clearcoatRoughnessMapIndex: int( - 1 ),
|
|
535
|
+
sheenColorMapIndex: int( - 1 ),
|
|
536
|
+
sheenRoughnessMapIndex: int( - 1 ),
|
|
537
|
+
iridescenceMapIndex: int( - 1 ),
|
|
538
|
+
iridescenceThicknessMapIndex: int( - 1 ),
|
|
539
|
+
specularIntensityMapIndex: int( - 1 ),
|
|
540
|
+
specularColorMapIndex: int( - 1 ),
|
|
461
541
|
} );
|
|
462
542
|
|
|
463
543
|
} );
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from 'three/tsl';
|
|
27
27
|
|
|
28
28
|
import { struct } from './patches.js';
|
|
29
|
-
import { MIN_PDF, getDatafromStorageBuffer, powerHeuristic, MATERIAL_SLOTS, MATERIAL_SLOT,
|
|
29
|
+
import { MIN_PDF, getDatafromStorageBuffer, powerHeuristic, MATERIAL_SLOTS, MATERIAL_SLOT, computeDotProductsAniso } from './Common.js';
|
|
30
30
|
import { RandomValue } from './Random.js';
|
|
31
31
|
import { calculateMaterialPDFFromDots } from './LightsSampling.js';
|
|
32
32
|
import { evaluateMaterialResponseFromDots } from './MaterialEvaluation.js';
|
|
@@ -573,7 +573,7 @@ export const calculateEmissiveTriangleContributionDebug = Fn( ( [
|
|
|
573
573
|
|
|
574
574
|
// Share H + dot products between BRDF eval and PDF (computeDotProducts
|
|
575
575
|
// would otherwise run twice with identical inputs).
|
|
576
|
-
const dots = DotProducts.wrap(
|
|
576
|
+
const dots = DotProducts.wrap( computeDotProductsAniso( normal, viewDir, emissiveSample.direction, material ) );
|
|
577
577
|
const brdfValue = evaluateMaterialResponseFromDots( material, dots );
|
|
578
578
|
const brdfPdf = calculateMaterialPDFFromDots( material, dots );
|
|
579
579
|
|
package/src/TSL/LightsDirect.js
CHANGED
|
@@ -144,8 +144,9 @@ export const traceShadowRay = Fn( ( [
|
|
|
144
144
|
|
|
145
145
|
If( shadowMaterial.alphaMode.equal( int( 1 ) ), () => {
|
|
146
146
|
|
|
147
|
-
// MASK mode: binary alpha cutout
|
|
148
|
-
|
|
147
|
+
// MASK mode: binary alpha cutout. Include opacity (=baseColorFactor.a) so
|
|
148
|
+
// factor-only MASK cuts out; mirrors the BLEND branch and the camera path.
|
|
149
|
+
const effectiveAlpha = shadowMaterial.color.a.mul( texAlpha ).mul( shadowMaterial.opacity );
|
|
149
150
|
const cutoff = select( shadowMaterial.alphaTest.greaterThan( 0.0 ), shadowMaterial.alphaTest, float( 0.5 ) );
|
|
150
151
|
If( effectiveAlpha.lessThan( cutoff ), () => {
|
|
151
152
|
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
abs,
|
|
26
26
|
sqrt,
|
|
27
27
|
dot,
|
|
28
|
-
normalize,
|
|
29
28
|
If,
|
|
30
29
|
select,
|
|
31
30
|
} from 'three/tsl';
|
|
@@ -41,7 +40,7 @@ import {
|
|
|
41
40
|
EPSILON,
|
|
42
41
|
MIN_PDF,
|
|
43
42
|
} from './Common.js';
|
|
44
|
-
import { DistributionGGX, calculateVNDFPDF } from './MaterialProperties.js';
|
|
43
|
+
import { DistributionGGX, calculateVNDFPDF, specularVNDFPDFForDir } from './MaterialProperties.js';
|
|
45
44
|
import { evaluateMaterialResponse } from './MaterialEvaluation.js';
|
|
46
45
|
import { RandomValue } from './Random.js';
|
|
47
46
|
import { sampleMicrofacetTransmission, MicrofacetTransmissionResult } from './MaterialTransmission.js';
|
|
@@ -342,11 +341,9 @@ export const calculateIndirectLighting = Fn( ( [
|
|
|
342
341
|
|
|
343
342
|
If( weights.useSpecular, () => {
|
|
344
343
|
|
|
345
|
-
// Evaluate specular PDF at sampleDir (not brdfSampleDirection which may differ)
|
|
346
|
-
|
|
347
|
-
const
|
|
348
|
-
const NoV_spec = max( dot( N, V ), 0.001 );
|
|
349
|
-
const specPdfAtSampleDir = calculateVNDFPDF( NoH_spec, NoV_spec, material.roughness );
|
|
344
|
+
// Evaluate specular PDF at sampleDir (not brdfSampleDirection which may differ);
|
|
345
|
+
// auto-selects iso/aniso to stay consistent with the BRDF sampler.
|
|
346
|
+
const specPdfAtSampleDir = specularVNDFPDFForDir( material, N, V, sampleDir );
|
|
350
347
|
combinedPdf.addAssign( weights.specularWeight.mul( specPdfAtSampleDir ) );
|
|
351
348
|
|
|
352
349
|
} );
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
|
|
73
73
|
import { traverseBVHShadow } from './BVHTraversal.js';
|
|
74
74
|
import { evaluateMaterialResponseFromDots } from './MaterialEvaluation.js';
|
|
75
|
-
import { calculateVNDFPDF } from './MaterialProperties.js';
|
|
75
|
+
import { calculateVNDFPDF, calculateVNDFPDFAniso, computeAnisoAlphas } from './MaterialProperties.js';
|
|
76
76
|
import { RandomValue } from './Random.js';
|
|
77
77
|
import {
|
|
78
78
|
selectOptimalMISStrategy,
|
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
EPSILON,
|
|
82
82
|
powerHeuristic,
|
|
83
83
|
balanceHeuristic,
|
|
84
|
-
|
|
84
|
+
computeDotProductsAniso,
|
|
85
85
|
} from './Common.js';
|
|
86
86
|
import {
|
|
87
87
|
sampleEquirectProbability,
|
|
@@ -737,7 +737,18 @@ export const calculateMaterialPDFFromDots = Fn( ( [ material, dots ] ) => {
|
|
|
737
737
|
If( specularWeight.greaterThan( 0.0 ).and( NoL.greaterThan( 0.0 ) ), () => {
|
|
738
738
|
|
|
739
739
|
const roughness = max( material.roughness, 0.02 );
|
|
740
|
-
|
|
740
|
+
const specPdf = float( 0.0 ).toVar();
|
|
741
|
+
If( material.anisotropy.greaterThan( 0.0 ), () => {
|
|
742
|
+
|
|
743
|
+
const a = computeAnisoAlphas( material.roughness, material.anisotropy );
|
|
744
|
+
specPdf.assign( calculateVNDFPDFAniso( a.x, a.y, dots.NoH, dots.ToH, dots.BoH, dots.NoV, dots.ToV, dots.BoV ) );
|
|
745
|
+
|
|
746
|
+
} ).Else( () => {
|
|
747
|
+
|
|
748
|
+
specPdf.assign( calculateVNDFPDF( NoH, NoV, roughness ) );
|
|
749
|
+
|
|
750
|
+
} );
|
|
751
|
+
pdf.addAssign( specularWeight.mul( specPdf ) );
|
|
741
752
|
|
|
742
753
|
} );
|
|
743
754
|
|
|
@@ -751,7 +762,7 @@ export const calculateMaterialPDFFromDots = Fn( ( [ material, dots ] ) => {
|
|
|
751
762
|
// already have dots; otherwise prefer calculateMaterialPDFFromDots.
|
|
752
763
|
export const calculateMaterialPDF = Fn( ( [ viewDir, lightDir, normal, material ] ) => {
|
|
753
764
|
|
|
754
|
-
const dots = DotProducts.wrap(
|
|
765
|
+
const dots = DotProducts.wrap( computeDotProductsAniso( normal, viewDir, lightDir, material ) );
|
|
755
766
|
return calculateMaterialPDFFromDots( material, dots );
|
|
756
767
|
|
|
757
768
|
} );
|
|
@@ -985,7 +996,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
985
996
|
|
|
986
997
|
// Share H + dot products between BRDF eval and PDF — otherwise each
|
|
987
998
|
// would recompute normalize(V+L) + 5 dot products independently.
|
|
988
|
-
const sharedDots = DotProducts.wrap(
|
|
999
|
+
const sharedDots = DotProducts.wrap( computeDotProductsAniso( hitNormal, viewDir, lightSample.direction, material ) );
|
|
989
1000
|
const brdfValue = evaluateMaterialResponseFromDots( material, sharedDots );
|
|
990
1001
|
const bPdf = calculateMaterialPDFFromDots( material, sharedDots ).toVar();
|
|
991
1002
|
|
|
@@ -1187,7 +1198,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
1187
1198
|
|
|
1188
1199
|
// Share H + dots between env BRDF/PDF — same redundancy fix as the
|
|
1189
1200
|
// discrete-light path above.
|
|
1190
|
-
const envDots = DotProducts.wrap(
|
|
1201
|
+
const envDots = DotProducts.wrap( computeDotProductsAniso( hitNormal, viewDir, envDirection, material ) );
|
|
1191
1202
|
const brdfValue = evaluateMaterialResponseFromDots( material, envDots );
|
|
1192
1203
|
const bPdf = calculateMaterialPDFFromDots( material, envDots ).toVar();
|
|
1193
1204
|
|