rayzee 7.20.3 → 7.22.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 +75 -4
- package/dist/rayzee.es.js +2821 -2854
- package/dist/rayzee.umd.js +60 -58
- package/package.json +1 -1
- package/src/EngineDefaults.js +9 -2
- package/src/PathTracerApp.js +83 -0
- package/src/Pipeline/BindingAudit.js +178 -0
- package/src/Pipeline/RenderPipeline.js +5 -2
- package/src/Processor/BVHBuilder.js +1 -4
- package/src/Processor/CameraOptimizer.js +0 -5
- package/src/Processor/KernelManager.js +17 -70
- package/src/Processor/PackedRayBuffer.js +33 -8
- package/src/Processor/QueueManager.js +4 -3
- package/src/Processor/SceneProcessor.js +10 -4
- package/src/Processor/TreeletOptimizer.js +0 -7
- package/src/RenderSettings.js +41 -6
- package/src/Stages/ASVGF.js +10 -10
- package/src/Stages/BilateralFilter.js +70 -11
- package/src/Stages/EdgeFilter.js +44 -6
- package/src/Stages/NormalDepth.js +26 -15
- package/src/Stages/PathTracer.js +36 -34
- package/src/Stages/PathTracerStage.js +15 -46
- package/src/TSL/BVHTraversal.js +1 -67
- package/src/TSL/CameraRay.js +141 -0
- package/src/TSL/Common.js +1 -47
- package/src/TSL/DebugKernel.js +4 -5
- package/src/TSL/EmissiveSampling.js +40 -44
- package/src/TSL/ExtendKernel.js +11 -3
- package/src/TSL/FinalWriteKernel.js +1 -14
- package/src/TSL/GenerateKernel.js +11 -8
- package/src/TSL/LightsCore.js +3 -0
- package/src/TSL/LightsDirect.js +4 -4
- package/src/TSL/LightsSampling.js +138 -327
- package/src/TSL/PathTracerCore.js +2 -2
- package/src/TSL/Random.js +2 -2
- package/src/TSL/ShadeKernel.js +39 -17
- package/src/TSL/SortGlobalKernels.js +52 -7
- package/src/TSL/Struct.js +0 -10
- package/src/index.js +5 -0
- package/src/managers/DenoisingManager.js +13 -0
- package/src/managers/EnvironmentManager.js +6 -8
- package/src/managers/UniformManager.js +12 -2
|
@@ -545,61 +545,57 @@ export const calculateEmissiveTriangleContributionDebug = Fn( ( [
|
|
|
545
545
|
distance: float( 0.0 ),
|
|
546
546
|
} ).toVar();
|
|
547
547
|
|
|
548
|
-
//
|
|
549
|
-
|
|
548
|
+
// No rough-diffuse secondary-bounce skip: dropping NEE while the emissive-hit MIS still
|
|
549
|
+
// down-weights BSDF hits deletes emitter energy from deep GI.
|
|
550
550
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
triangleBuffer,
|
|
559
|
-
) );
|
|
560
|
-
|
|
561
|
-
If( emissiveSample.valid.and( emissiveSample.pdf.greaterThan( 0.0 ) ), () => {
|
|
551
|
+
// Sample emissive triangle (CDF importance-weighted)
|
|
552
|
+
const emissiveSample = EmissiveSample.wrap( sampleEmissiveTriangle(
|
|
553
|
+
hitPoint, normal, rngState,
|
|
554
|
+
pixelCoord, resolution, frame, dimBase,
|
|
555
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower,
|
|
556
|
+
triangleBuffer,
|
|
557
|
+
) );
|
|
562
558
|
|
|
563
|
-
|
|
564
|
-
result.emissionOnly.assign( emissiveSample.emission );
|
|
565
|
-
result.distance.assign( emissiveSample.distance );
|
|
559
|
+
If( emissiveSample.valid.and( emissiveSample.pdf.greaterThan( 0.0 ) ), () => {
|
|
566
560
|
|
|
567
|
-
|
|
568
|
-
|
|
561
|
+
result.hasEmissive.assign( true );
|
|
562
|
+
result.emissionOnly.assign( emissiveSample.emission );
|
|
563
|
+
result.distance.assign( emissiveSample.distance );
|
|
569
564
|
|
|
570
|
-
|
|
565
|
+
// Check geometric validity
|
|
566
|
+
const NoL = max( float( 0.0 ), dot( normal, emissiveSample.direction ) );
|
|
571
567
|
|
|
572
|
-
|
|
573
|
-
const rayOffset = calculateRayOffsetFn( hitPoint, normal, material );
|
|
574
|
-
const rayOrigin = hitPoint.add( rayOffset );
|
|
568
|
+
If( NoL.greaterThan( 0.0 ), () => {
|
|
575
569
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
570
|
+
// Calculate ray offset for shadow ray
|
|
571
|
+
const rayOffset = calculateRayOffsetFn( hitPoint, normal, material );
|
|
572
|
+
const rayOrigin = hitPoint.add( rayOffset );
|
|
579
573
|
|
|
580
|
-
|
|
574
|
+
// Trace shadow ray
|
|
575
|
+
const shadowDist = emissiveSample.distance.sub( 0.001 );
|
|
576
|
+
const visibility = traceShadowRayFn( rayOrigin, emissiveSample.direction, shadowDist );
|
|
581
577
|
|
|
582
|
-
|
|
583
|
-
// would otherwise run twice with identical inputs).
|
|
584
|
-
const dots = DotProducts.wrap( computeDotProductsAniso( normal, viewDir, emissiveSample.direction, material ) );
|
|
585
|
-
const brdfValue = evaluateMaterialResponseFromDots( material, dots );
|
|
586
|
-
const brdfPdf = calculateMaterialPDFFromDots( material, dots );
|
|
578
|
+
If( visibility.greaterThan( 0.0 ), () => {
|
|
587
579
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
);
|
|
580
|
+
// Share H + dot products between BRDF eval and PDF (computeDotProducts
|
|
581
|
+
// would otherwise run twice with identical inputs).
|
|
582
|
+
const dots = DotProducts.wrap( computeDotProductsAniso( normal, viewDir, emissiveSample.direction, material ) );
|
|
583
|
+
const brdfValue = evaluateMaterialResponseFromDots( material, dots );
|
|
584
|
+
const brdfPdf = calculateMaterialPDFFromDots( material, dots );
|
|
594
585
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
586
|
+
// MIS weight: balance light sampling vs BRDF sampling
|
|
587
|
+
const misWeight = select(
|
|
588
|
+
brdfPdf.greaterThan( 0.0 ),
|
|
589
|
+
powerHeuristic( { pdf1: emissiveSample.pdf, pdf2: brdfPdf } ),
|
|
590
|
+
float( 1.0 )
|
|
591
|
+
);
|
|
601
592
|
|
|
602
|
-
|
|
593
|
+
// MC estimator: Le * brdf * cos_surface / pdf_solidAngle
|
|
594
|
+
// emissiveBoost is an additional user-controlled intensity multiplier
|
|
595
|
+
result.contribution.assign(
|
|
596
|
+
emissiveSample.emission.mul( brdfValue ).mul( NoL )
|
|
597
|
+
.div( emissiveSample.pdf ).mul( visibility ).mul( emissiveBoost ).mul( misWeight )
|
|
598
|
+
);
|
|
603
599
|
|
|
604
600
|
} );
|
|
605
601
|
|
package/src/TSL/ExtendKernel.js
CHANGED
|
@@ -13,17 +13,17 @@ import {
|
|
|
13
13
|
import { traverseBVH } from './BVHTraversal.js';
|
|
14
14
|
import { Ray, HitInfo } from './Struct.js';
|
|
15
15
|
import {
|
|
16
|
-
readRayOrigin, readRayDirection, readMediumStack,
|
|
16
|
+
readRayOrigin, readRayDirection, readRayBounceFlags, readMediumStack,
|
|
17
17
|
writeHitPacked,
|
|
18
18
|
} from '../Processor/PackedRayBuffer.js';
|
|
19
|
-
import { COUNTER } from '../Processor/QueueManager.js';
|
|
19
|
+
import { COUNTER, RAY_FLAG } from '../Processor/QueueManager.js';
|
|
20
20
|
|
|
21
21
|
const WG_SIZE = 256;
|
|
22
22
|
|
|
23
23
|
export function buildExtendKernel( params ) {
|
|
24
24
|
|
|
25
25
|
const {
|
|
26
|
-
bvhBuffer, triangleBuffer,
|
|
26
|
+
bvhBuffer, triangleBuffer,
|
|
27
27
|
rayBufferRO,
|
|
28
28
|
hitBufferRW,
|
|
29
29
|
activeIndicesRO,
|
|
@@ -45,6 +45,14 @@ export function buildExtendKernel( params ) {
|
|
|
45
45
|
|
|
46
46
|
const rayID = activeIndicesRO.element( threadIdx );
|
|
47
47
|
|
|
48
|
+
// Parity with Shade's guard. Free — the flags share DIR_FLAGS.w with the direction read below.
|
|
49
|
+
// Only culls work on the pinned-dispatch path, whose identity list still holds dead rays.
|
|
50
|
+
If( readRayBounceFlags( rayBufferRO, rayID ).bitAnd( uint( RAY_FLAG.ACTIVE ) ).equal( uint( 0 ) ), () => {
|
|
51
|
+
|
|
52
|
+
Return();
|
|
53
|
+
|
|
54
|
+
} );
|
|
55
|
+
|
|
48
56
|
const origin = readRayOrigin( rayBufferRO, rayID ).toVar();
|
|
49
57
|
const direction = readRayDirection( rayBufferRO, rayID ).toVar();
|
|
50
58
|
|
|
@@ -54,7 +54,7 @@ export function buildFinalWriteKernel( params ) {
|
|
|
54
54
|
|
|
55
55
|
// Tier-2 per-pixel freeze: streakBufferRW = per-pixel freeze-candidate streak (stamped here);
|
|
56
56
|
// frozenMaskRO = dilated frozen mask from buildActivePixels (pass-through gates on it, not streak).
|
|
57
|
-
usePixelFreeze, pixelFreezeThreshold,
|
|
57
|
+
usePixelFreeze, pixelFreezeThreshold, streakBufferRW, frozenMaskRO,
|
|
58
58
|
} = params;
|
|
59
59
|
|
|
60
60
|
const auxOn = auxGBufferEnabled.greaterThan( uint( 0 ) );
|
|
@@ -184,25 +184,12 @@ export function buildFinalWriteKernel( params ) {
|
|
|
184
184
|
|
|
185
185
|
} );
|
|
186
186
|
|
|
187
|
-
If( wasFrozen, () => {
|
|
188
|
-
|
|
189
|
-
// Already frozen (passed through above) — count it.
|
|
190
|
-
atomicAdd( counters.element( uint( COUNTER.FROZEN_COUNT ) ), uint( 1 ) );
|
|
191
|
-
|
|
192
|
-
} );
|
|
193
|
-
|
|
194
187
|
If( wasFrozen.not().and( frame.greaterThan( uint( 0 ) ) ), () => {
|
|
195
188
|
|
|
196
189
|
const freezeCandidate = frame.greaterThanEqual( uint( adaptiveMinSamples ) )
|
|
197
190
|
.and( relErr.lessThan( pixelFreezeThreshold ) );
|
|
198
191
|
const newStreak = select( freezeCandidate, streakBufferRW.element( pixelId ).add( uint( 1 ) ), uint( 0 ) ).toVar();
|
|
199
192
|
streakBufferRW.element( pixelId ).assign( newStreak );
|
|
200
|
-
// Just reached K → frozen next frame; count it now so the frozen population is current.
|
|
201
|
-
If( newStreak.greaterThanEqual( uint( pixelFreezeStability ) ), () => {
|
|
202
|
-
|
|
203
|
-
atomicAdd( counters.element( uint( COUNTER.FROZEN_COUNT ) ), uint( 1 ) );
|
|
204
|
-
|
|
205
|
-
} );
|
|
206
193
|
|
|
207
194
|
} );
|
|
208
195
|
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
getStratifiedSample,
|
|
23
23
|
} from './Random.js';
|
|
24
24
|
|
|
25
|
-
import { generateRayFromCamera } from './
|
|
25
|
+
import { generateRayFromCamera } from './CameraRay.js';
|
|
26
26
|
import { Ray } from './Struct.js';
|
|
27
27
|
import { RAY_FLAG, COUNTER } from '../Processor/QueueManager.js';
|
|
28
28
|
import {
|
|
@@ -39,6 +39,7 @@ export function buildGenerateKernel( params ) {
|
|
|
39
39
|
rayBufferRW, rngBufferRW, gBufferRW,
|
|
40
40
|
resolution, frame,
|
|
41
41
|
cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
42
|
+
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon,
|
|
42
43
|
enableDOF, focalLength, aperture, focusDistance, sceneScale, apertureScale, anamorphicRatio,
|
|
43
44
|
renderWidth,
|
|
44
45
|
chunkRowBase, chunkRows, // row band offset (global first row) + row count for this chunk
|
|
@@ -56,9 +57,6 @@ export function buildGenerateKernel( params ) {
|
|
|
56
57
|
|
|
57
58
|
const pixelCoord = vec2( float( gx ).add( 0.5 ), float( gy ).add( 0.5 ) );
|
|
58
59
|
|
|
59
|
-
const screenPosition = pixelCoord.div( resolution ).mul( 2.0 ).sub( 1.0 ).toVar();
|
|
60
|
-
screenPosition.y.assign( screenPosition.y.negate() );
|
|
61
|
-
|
|
62
60
|
const baseSeed = getDecorrelatedSeed( { pixelCoord, rayIndex: int( 0 ), frame } ).toVar();
|
|
63
61
|
const seed = pcgHash( { state: baseSeed } ).toVar();
|
|
64
62
|
|
|
@@ -68,13 +66,18 @@ export function buildGenerateKernel( params ) {
|
|
|
68
66
|
// position from the first scatter direction (they were reading the identical cell).
|
|
69
67
|
const stratifiedJitter = getStratifiedSample( pixelCoord, int( 1 ), int( 1 ), seed, resolution, frame ).toVar();
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
69
|
+
// Y is subtracted because uv.y grows downward while the NDC this used to build grew upward —
|
|
70
|
+
// keeps the sub-pixel sample sequence bit-identical to the pre-panorama ray gen.
|
|
71
|
+
const jitterOffset = stratifiedJitter.sub( 0.5 );
|
|
72
|
+
const jitteredUV = vec2(
|
|
73
|
+
pixelCoord.x.add( jitterOffset.x ),
|
|
74
|
+
pixelCoord.y.sub( jitterOffset.y )
|
|
75
|
+
).div( resolution );
|
|
74
76
|
|
|
75
77
|
const ray = Ray.wrap( generateRayFromCamera(
|
|
76
|
-
|
|
78
|
+
jitteredUV, seed,
|
|
77
79
|
cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
80
|
+
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon,
|
|
78
81
|
enableDOF, focalLength, aperture, focusDistance, sceneScale, apertureScale, anamorphicRatio,
|
|
79
82
|
) );
|
|
80
83
|
|
package/src/TSL/LightsCore.js
CHANGED
|
@@ -83,6 +83,9 @@ export const LightSample = struct( {
|
|
|
83
83
|
distance: 'float',
|
|
84
84
|
lightType: 'int',
|
|
85
85
|
valid: 'bool',
|
|
86
|
+
// Reservoir denominator, carried out so the BSDF-hit MIS partner can rebuild the
|
|
87
|
+
// selection pdf without walking every light buffer a second time.
|
|
88
|
+
selectionTotalWeight: 'float',
|
|
86
89
|
} );
|
|
87
90
|
|
|
88
91
|
export const IndirectLightingResult = struct( {
|
package/src/TSL/LightsDirect.js
CHANGED
|
@@ -74,7 +74,7 @@ export const traceShadowRay = Fn( ( [
|
|
|
74
74
|
const rayOrigin = origin.toVar();
|
|
75
75
|
const remainingDist = float( maxDist ).toVar();
|
|
76
76
|
|
|
77
|
-
const MAX_SHADOW_TRANSMISSIONS =
|
|
77
|
+
const MAX_SHADOW_TRANSMISSIONS = 16;
|
|
78
78
|
|
|
79
79
|
Loop( { start: int( 0 ), end: int( MAX_SHADOW_TRANSMISSIONS ) }, () => {
|
|
80
80
|
|
|
@@ -160,7 +160,7 @@ export const traceShadowRay = Fn( ( [
|
|
|
160
160
|
const blendAlpha = clamp( shadowMaterial.color.a.mul( shadowMaterial.opacity ).mul( texAlpha ), 0.0, 1.0 );
|
|
161
161
|
transmittance.mulAssign( float( 1.0 ).sub( blendAlpha ) );
|
|
162
162
|
|
|
163
|
-
If( transmittance.lessThan(
|
|
163
|
+
If( transmittance.lessThan( 1e-4 ), () => {
|
|
164
164
|
|
|
165
165
|
transmittance.assign( 0.0 );
|
|
166
166
|
Break();
|
|
@@ -221,7 +221,7 @@ export const traceShadowRay = Fn( ( [
|
|
|
221
221
|
transmittance.mulAssign( matTransmittance );
|
|
222
222
|
|
|
223
223
|
// Early exit if almost no light passes through
|
|
224
|
-
If( transmittance.lessThan(
|
|
224
|
+
If( transmittance.lessThan( 1e-4 ), () => {
|
|
225
225
|
|
|
226
226
|
transmittance.assign( 0.0 );
|
|
227
227
|
Break();
|
|
@@ -237,7 +237,7 @@ export const traceShadowRay = Fn( ( [
|
|
|
237
237
|
// Handle transparent materials
|
|
238
238
|
transmittance.mulAssign( float( 1.0 ).sub( shadowMaterial.opacity ) );
|
|
239
239
|
|
|
240
|
-
If( transmittance.lessThan(
|
|
240
|
+
If( transmittance.lessThan( 1e-4 ), () => {
|
|
241
241
|
|
|
242
242
|
transmittance.assign( 0.0 );
|
|
243
243
|
Break();
|