rayzee 7.22.8 → 7.22.9
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 +1058 -1033
- package/dist/rayzee.umd.js +30 -26
- package/package.json +1 -1
- package/src/Stages/NormalDepth.js +11 -2
- package/src/TSL/Debugger.js +5 -5
- package/src/TSL/ShadeKernel.js +11 -2
- package/src/TSL/TextureSampling.js +97 -8
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@ import { Ray, HitInfo, RayTracingMaterial, UVCache } from '../TSL/Struct.js';
|
|
|
8
8
|
import { traverseBVH } from '../TSL/BVHTraversal.js';
|
|
9
9
|
import { cameraRayDirection } from '../TSL/CameraRay.js';
|
|
10
10
|
import { getMaterial } from '../TSL/Common.js';
|
|
11
|
-
import { computeUVCache, processNormal, processBump, buildBucketTextureNodes, refreshBucketTextureNodes, setMaterialBucketTextures } from '../TSL/TextureSampling.js';
|
|
11
|
+
import { computeUVCache, processNormal, processBump, triangleUVTangent, buildBucketTextureNodes, refreshBucketTextureNodes, setMaterialBucketTextures } from '../TSL/TextureSampling.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* NormalDepth — primary-ray G-buffer for SVGF gates.
|
|
@@ -263,7 +263,16 @@ export class NormalDepth extends RenderStage {
|
|
|
263
263
|
getMaterial( hit.materialIndex, matStorage )
|
|
264
264
|
).toVar();
|
|
265
265
|
const uvCache = UVCache.wrap( computeUVCache( hit.uv, material ) ).toVar();
|
|
266
|
-
|
|
266
|
+
// Same UV tangent frame the Shade kernel uses, or the aux normal disagrees
|
|
267
|
+
// with the shading normal it is supposed to guide the denoiser with.
|
|
268
|
+
const uvTangent = vec4( 0.0 ).toVar();
|
|
269
|
+
If( material.normalMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
270
|
+
|
|
271
|
+
uvTangent.assign( triangleUVTangent( triStorage, hit.triangleIndex, hit.normal, material.normalTransform ) );
|
|
272
|
+
|
|
273
|
+
} );
|
|
274
|
+
|
|
275
|
+
const mapped = processNormal( hit.normal, material, uvCache, uvTangent ).toVar();
|
|
267
276
|
shadingNormal.assign( processBump( mapped, material, uvCache ) );
|
|
268
277
|
|
|
269
278
|
} );
|
package/src/TSL/Debugger.js
CHANGED
|
@@ -202,7 +202,7 @@ export const TraceDebugMode = Fn( ( [
|
|
|
202
202
|
|
|
203
203
|
// Sample all textures to get emissive
|
|
204
204
|
const matSamples = MaterialSamples.wrap( sampleAllMaterialTextures(
|
|
205
|
-
material, hitInfo.uv, hitInfo.normal,
|
|
205
|
+
material, hitInfo.uv, hitInfo.normal, vec4( 0.0 ),
|
|
206
206
|
) ).toVar();
|
|
207
207
|
|
|
208
208
|
const emissiveColor = matSamples.emissive.toVar();
|
|
@@ -246,7 +246,7 @@ export const TraceDebugMode = Fn( ( [
|
|
|
246
246
|
|
|
247
247
|
// Get material-mapped normal (same as what's used in main shader)
|
|
248
248
|
const matSamples = MaterialSamples.wrap( sampleAllMaterialTextures(
|
|
249
|
-
material, hitInfo.uv, hitInfo.normal,
|
|
249
|
+
material, hitInfo.uv, hitInfo.normal, vec4( 0.0 ),
|
|
250
250
|
) ).toVar();
|
|
251
251
|
|
|
252
252
|
const worldNormal = normalize( matSamples.normal );
|
|
@@ -292,7 +292,7 @@ export const TraceDebugMode = Fn( ( [
|
|
|
292
292
|
const material = RayTracingMaterial.wrap( getMaterial( hitInfo.materialIndex, materialBuffer ) ).toVar();
|
|
293
293
|
|
|
294
294
|
const matSamples = MaterialSamples.wrap( sampleAllMaterialTextures(
|
|
295
|
-
material, hitInfo.uv, hitInfo.normal,
|
|
295
|
+
material, hitInfo.uv, hitInfo.normal, vec4( 0.0 ),
|
|
296
296
|
) ).toVar();
|
|
297
297
|
|
|
298
298
|
const objectColor = matSamples.albedo.rgb;
|
|
@@ -318,7 +318,7 @@ export const TraceDebugMode = Fn( ( [
|
|
|
318
318
|
// Get primary surface material
|
|
319
319
|
const material = RayTracingMaterial.wrap( getMaterial( hitInfo.materialIndex, materialBuffer ) ).toVar();
|
|
320
320
|
const matSamples = MaterialSamples.wrap( sampleAllMaterialTextures(
|
|
321
|
-
material, hitInfo.uv, hitInfo.normal,
|
|
321
|
+
material, hitInfo.uv, hitInfo.normal, vec4( 0.0 ),
|
|
322
322
|
) ).toVar();
|
|
323
323
|
|
|
324
324
|
const albedoA = matSamples.albedo.rgb;
|
|
@@ -364,7 +364,7 @@ export const TraceDebugMode = Fn( ( [
|
|
|
364
364
|
// Bounce hit surface B — evaluate its contribution
|
|
365
365
|
const materialB = RayTracingMaterial.wrap( getMaterial( bounceHit.materialIndex, materialBuffer ) ).toVar();
|
|
366
366
|
const matSamplesB = MaterialSamples.wrap( sampleAllMaterialTextures(
|
|
367
|
-
materialB, bounceHit.uv, bounceHit.normal,
|
|
367
|
+
materialB, bounceHit.uv, bounceHit.normal, vec4( 0.0 ),
|
|
368
368
|
) ).toVar();
|
|
369
369
|
|
|
370
370
|
// Emissive contribution from surface B
|
package/src/TSL/ShadeKernel.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { sampleEnvironment, sampleEquirectProbability, sampleEquirect, groundProjectedEnvDir } from './Environment.js';
|
|
18
18
|
import { getMaterial, powerHeuristic, balanceHeuristic, classifyMaterial, REC709_LUMINANCE_COEFFICIENTS, PI_INV, EPSILON, diffuseGroundMaterial } from './Common.js';
|
|
19
19
|
import { cosineWeightedSample } from './MaterialSampling.js';
|
|
20
|
-
import { sampleAllMaterialTextures, processAnisotropyMap, applyExtensionMaps, getTransformedUV } from './TextureSampling.js';
|
|
20
|
+
import { sampleAllMaterialTextures, processAnisotropyMap, applyExtensionMaps, getTransformedUV, triangleUVTangent } from './TextureSampling.js';
|
|
21
21
|
import { evaluateMaterialResponse } from './MaterialEvaluation.js';
|
|
22
22
|
import { calculateDirectLightingUnified, calculateMaterialPDF } from './LightsSampling.js';
|
|
23
23
|
import { traceShadowRay, calculateRayOffset } from './LightsDirect.js';
|
|
@@ -616,8 +616,17 @@ export function buildShadeKernel( params ) {
|
|
|
616
616
|
}
|
|
617
617
|
);
|
|
618
618
|
|
|
619
|
+
// Normal-map tangent frame. Only paid for when there is a normal map: the arbitrary
|
|
620
|
+
// cross(up, N) fallback inside processNormal is what runs otherwise.
|
|
621
|
+
const uvTangent = vec4( 0.0 ).toVar();
|
|
622
|
+
If( material.normalMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
623
|
+
|
|
624
|
+
uvTangent.assign( triangleUVTangent( triangleBuffer, int( hitTriIdx ), N, material.normalTransform ) );
|
|
625
|
+
|
|
626
|
+
} );
|
|
627
|
+
|
|
619
628
|
const matSamples = MaterialSamples.wrap( sampleAllMaterialTextures(
|
|
620
|
-
material, samplingUV, N,
|
|
629
|
+
material, samplingUV, N, uvTangent,
|
|
621
630
|
) ).toVar();
|
|
622
631
|
|
|
623
632
|
// DDFA: snapshot the UNCLAMPED roughness (before the min-0.05 clamp below) for the specular↔diffuse
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fn, wgslFn, float, vec2, vec3, vec4, int, If, normalize, cross, abs, atan, mix, clamp, texture, textureSize } from 'three/tsl';
|
|
1
|
+
import { Fn, wgslFn, float, vec2, vec3, vec4, int, If, normalize, cross, dot, length, sign, abs, atan, mix, clamp, texture, textureSize } from 'three/tsl';
|
|
2
2
|
import { DataArrayTexture, LinearFilter } from 'three';
|
|
3
3
|
|
|
4
4
|
import {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
MaterialSamples,
|
|
7
7
|
ExtMapResult,
|
|
8
8
|
} from './Struct.js';
|
|
9
|
+
import { getDatafromStorageBuffer } from './Common.js';
|
|
9
10
|
import { TEXTURE_CONSTANTS } from '../EngineDefaults.js';
|
|
10
11
|
|
|
11
12
|
// ================================================================================
|
|
@@ -382,7 +383,80 @@ export const processMetalnessRoughness = Fn( ( [ material, uvCache ] ) => {
|
|
|
382
383
|
|
|
383
384
|
} );
|
|
384
385
|
|
|
385
|
-
|
|
386
|
+
// (t[1][1], t[0][1]) — the row of the inverse 2x2 linear part that maps dP/du onto dP/du',
|
|
387
|
+
// up to the determinant, which drops out under the normalize that follows.
|
|
388
|
+
const uvTransformJacobian = /*@__PURE__*/ wgslFn( `
|
|
389
|
+
fn uvTransformJacobian( t: mat3x3f ) -> vec2f {
|
|
390
|
+
return vec2f( t[1][1], t[0][1] );
|
|
391
|
+
}
|
|
392
|
+
` );
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Build the UV tangent for one triangle, as vec4( T.xyz, handedness ).
|
|
396
|
+
*
|
|
397
|
+
* Returned in the *transformed* UV space of `transform`, since that is the space the normal
|
|
398
|
+
* map is sampled in — the inverse of the transform's 2x2 linear part maps dP/du back onto
|
|
399
|
+
* dP/du'. A pure repeat/scale leaves the direction alone; a rotated transform does not.
|
|
400
|
+
* w == 0 signals a degenerate parameterisation, which processNormal treats as "no frame".
|
|
401
|
+
*
|
|
402
|
+
* @param {Node} triangleBuffer packed triangle storage (8 vec4 stride)
|
|
403
|
+
* @param {Node} triIndex absolute triangle index
|
|
404
|
+
* @param {Node} geometryNormal shading-space normal, for the handedness test
|
|
405
|
+
* @param {Node} transform the normal map's mat3 UV transform
|
|
406
|
+
*/
|
|
407
|
+
export const triangleUVTangent = Fn( ( [ triangleBuffer, triIndex, geometryNormal, transform ] ) => {
|
|
408
|
+
|
|
409
|
+
const S = int( 8 );
|
|
410
|
+
const pA = getDatafromStorageBuffer( triangleBuffer, triIndex, int( 0 ), S ).xyz;
|
|
411
|
+
const e1 = getDatafromStorageBuffer( triangleBuffer, triIndex, int( 1 ), S ).xyz.sub( pA );
|
|
412
|
+
const e2 = getDatafromStorageBuffer( triangleBuffer, triIndex, int( 2 ), S ).xyz.sub( pA );
|
|
413
|
+
|
|
414
|
+
const uvAB = getDatafromStorageBuffer( triangleBuffer, triIndex, int( 6 ), S );
|
|
415
|
+
const uvC = getDatafromStorageBuffer( triangleBuffer, triIndex, int( 7 ), S ).xy;
|
|
416
|
+
const d1 = uvAB.zw.sub( uvAB.xy );
|
|
417
|
+
const d2 = uvC.sub( uvAB.xy );
|
|
418
|
+
|
|
419
|
+
const det = d1.x.mul( d2.y ).sub( d1.y.mul( d2.x ) );
|
|
420
|
+
const result = vec4( 0.0 ).toVar();
|
|
421
|
+
|
|
422
|
+
If( abs( det ).greaterThan( 1e-12 ), () => {
|
|
423
|
+
|
|
424
|
+
const r = float( 1.0 ).div( det );
|
|
425
|
+
const T = e1.mul( d2.y ).sub( e2.mul( d1.y ) ).mul( r ).toVar();
|
|
426
|
+
const B = e2.mul( d1.x ).sub( e1.mul( d2.x ) ).mul( r ).toVar();
|
|
427
|
+
|
|
428
|
+
// Re-express in the map's transformed UV space (inverse of the 2x2 linear part).
|
|
429
|
+
const uvJ = uvTransformJacobian( { t: transform } );
|
|
430
|
+
const Tt = T.mul( uvJ.x ).sub( B.mul( uvJ.y ) ).toVar();
|
|
431
|
+
|
|
432
|
+
If( length( Tt ).greaterThan( 1e-12 ), () => {
|
|
433
|
+
|
|
434
|
+
T.assign( Tt );
|
|
435
|
+
|
|
436
|
+
} );
|
|
437
|
+
|
|
438
|
+
If( length( T ).greaterThan( 1e-12 ), () => {
|
|
439
|
+
|
|
440
|
+
result.assign( vec4( normalize( T ), sign( dot( cross( geometryNormal, T ), B ) ) ) );
|
|
441
|
+
|
|
442
|
+
} );
|
|
443
|
+
|
|
444
|
+
} );
|
|
445
|
+
|
|
446
|
+
return result;
|
|
447
|
+
|
|
448
|
+
} );
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Per-triangle tangent frame from the UV parameterisation.
|
|
452
|
+
*
|
|
453
|
+
* `uvTangent` is vec4( T.xyz, handedness ); w == 0 means "no usable frame" (degenerate or
|
|
454
|
+
* missing UVs) and falls back to the arbitrary cross(up, N) frame. A frame unrelated to the
|
|
455
|
+
* texture's U axis rotates the whole perturbation: on a vertical fluted-glass panel the
|
|
456
|
+
* arbitrary frame comes out 90 deg off, so the rib normals tilt up/down instead of across
|
|
457
|
+
* the ribs.
|
|
458
|
+
*/
|
|
459
|
+
export const processNormal = Fn( ( [ geometryNormal, material, uvCache, uvTangent ] ) => {
|
|
386
460
|
|
|
387
461
|
const result = geometryNormal.toVar();
|
|
388
462
|
|
|
@@ -393,10 +467,25 @@ export const processNormal = Fn( ( [ geometryNormal, material, uvCache ] ) => {
|
|
|
393
467
|
normalMap.x.mulAssign( material.normalScale.x );
|
|
394
468
|
normalMap.y.assign( normalMap.y.negate().mul( material.normalScale.x ) );
|
|
395
469
|
|
|
396
|
-
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
470
|
+
const tangent = vec3( 0.0 ).toVar();
|
|
471
|
+
const handedness = float( 1.0 ).toVar();
|
|
472
|
+
|
|
473
|
+
// Gram-Schmidt against the interpolated normal, which is not exactly triangle-planar.
|
|
474
|
+
const perp = uvTangent.xyz.sub( geometryNormal.mul( dot( geometryNormal, uvTangent.xyz ) ) ).toVar();
|
|
475
|
+
|
|
476
|
+
If( abs( uvTangent.w ).greaterThan( 0.5 ).and( length( perp ).greaterThan( 1e-6 ) ), () => {
|
|
477
|
+
|
|
478
|
+
tangent.assign( normalize( perp ) );
|
|
479
|
+
handedness.assign( uvTangent.w );
|
|
480
|
+
|
|
481
|
+
} ).Else( () => {
|
|
482
|
+
|
|
483
|
+
const up = abs( geometryNormal.z ).lessThan( 0.999 ).select( vec3( 0.0, 0.0, 1.0 ), vec3( 1.0, 0.0, 0.0 ) );
|
|
484
|
+
tangent.assign( normalize( cross( up, geometryNormal ) ) );
|
|
485
|
+
|
|
486
|
+
} );
|
|
487
|
+
|
|
488
|
+
const bitangent = cross( geometryNormal, tangent ).mul( handedness );
|
|
400
489
|
|
|
401
490
|
result.assign( normalize(
|
|
402
491
|
tangent.mul( normalMap.x ).add( bitangent.mul( normalMap.y ) ).add( geometryNormal.mul( normalMap.z ) )
|
|
@@ -563,7 +652,7 @@ export const processEmissive = Fn( ( [ material, uvCache ] ) => {
|
|
|
563
652
|
// MAIN BATCHED SAMPLING FUNCTION
|
|
564
653
|
// ================================================================================
|
|
565
654
|
|
|
566
|
-
export const sampleAllMaterialTextures = Fn( ( [ material, uv, geometryNormal ] ) => {
|
|
655
|
+
export const sampleAllMaterialTextures = Fn( ( [ material, uv, geometryNormal, uvTangent ] ) => {
|
|
567
656
|
|
|
568
657
|
const albedo = vec4( 0.0 ).toVar();
|
|
569
658
|
const emissive = vec3( 0.0 ).toVar();
|
|
@@ -591,7 +680,7 @@ export const sampleAllMaterialTextures = Fn( ( [ material, uv, geometryNormal ]
|
|
|
591
680
|
metalness.assign( metalRough.x );
|
|
592
681
|
roughness.assign( metalRough.y );
|
|
593
682
|
|
|
594
|
-
const currentNormal = processNormal( geometryNormal, material, uvCache ).toVar();
|
|
683
|
+
const currentNormal = processNormal( geometryNormal, material, uvCache, uvTangent ).toVar();
|
|
595
684
|
normal.assign( processBump( currentNormal, material, uvCache ) );
|
|
596
685
|
|
|
597
686
|
emissive.assign( processEmissive( material, uvCache ) );
|