rayzee 10.0.0 → 11.1.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 +252 -44
- package/dist/ActiveColor-YvuQq44O.js +13 -0
- package/dist/ArchiveImporter-Hn35o6Z5.js +5145 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-CBw8hkeu.js +946 -0
- package/dist/BufferLayout-D_IBo2ci.js +150 -0
- package/dist/ColorManagement-oeEk7oSu.js +1488 -0
- package/dist/EngineEvents-Ci8dVWCP.js +73 -0
- package/dist/EngineIssues-CIZnXHsF.js +72 -0
- package/dist/FileFormats-sPGJeCRc.js +102 -0
- package/dist/Logger-dDDGj9Av.js +97 -0
- package/dist/{NeuralRetouch-CYgkQY8Z.js → NeuralRetouch-BzNpiVHZ.js} +8 -6
- package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-Bk7bHg2B.js} +55 -120
- package/dist/PathTracer-72XufKAr.js +29976 -0
- package/dist/PhysicalSky-BgjdV88k.js +1219 -0
- package/dist/RayzeeRenderer-1QRO97eq.js +3551 -0
- package/dist/SolarLimb-CPaeZVwz.js +721 -0
- package/dist/ToneMapGPU-CjU3osDd.js +177 -0
- package/dist/ViewTransforms-CYN7bq2w.js +255 -0
- package/dist/WorkingMatrix-C6y233hT.js +27 -0
- package/dist/ZipReader-gDSWr0I5.js +98 -0
- package/dist/addons/archives.es.js +3 -0
- package/dist/addons/bidirectional.es.js +2 -0
- package/dist/addons/color.es.js +3 -0
- package/dist/addons/formats.es.js +2 -0
- package/dist/addons/physical-sky.es.js +2 -0
- package/dist/addons/storage.es.js +3 -0
- package/dist/archiveFormats-tnAoUL1j.js +94 -0
- package/dist/identity-DrQsGT2o.js +39 -0
- package/dist/openStorage-DwcBRUj7.js +820 -0
- package/dist/rayzee-core.es.js +12 -0
- package/dist/rayzee.es.js +2551 -44024
- package/dist/rayzee.umd.js +528 -487
- package/dist/sceneCachePolicy-C67jbci-.js +443 -0
- package/dist/shared-BGBcSxBQ.js +17 -0
- package/package.json +23 -2
- package/src/Color/ActiveColor.js +34 -0
- package/src/Color/BasicColor.js +147 -0
- package/src/Color/ColorManagement.js +7 -31
- package/src/Color/ViewTransforms.js +5 -1
- package/src/EngineDefaults.js +62 -1029
- package/src/EngineEvents.js +2 -0
- package/src/EngineIssues.js +2 -0
- package/src/Headless.js +6 -5
- package/src/Passes/AIUpscaler.js +58 -141
- package/src/Passes/OIDNDenoiser.js +92 -65
- package/src/Passes/OIDNTemporalHistory.js +1 -1
- package/src/PathTracerApp.js +620 -4026
- package/src/Pipeline/PipelineContext.js +0 -4
- package/src/Platform.js +36 -0
- package/src/Processor/ArchiveCache.js +20 -7
- package/src/Processor/ArchiveImporter.js +1265 -0
- package/src/Processor/ArchiveReader.js +22 -4
- package/src/Processor/AssetLoader.js +327 -1763
- package/src/Processor/AtmosphereModel.js +1 -2
- package/src/Processor/BVHBuilder.js +14 -126
- package/src/Processor/BVHLeafFold.js +4 -6
- package/src/Processor/BVHRefitter.js +67 -46
- package/src/Processor/BufferLayout.js +291 -0
- package/src/Processor/EmissiveTriangleBuilder.js +1 -1
- package/src/Processor/EnvironmentExactTable.js +187 -0
- package/src/Processor/EquirectHDRInfo.js +30 -223
- package/src/Processor/FileFormats.js +116 -0
- package/src/Processor/GLTFDecoders.js +85 -0
- package/src/Processor/GLTFDiffuseTransmission.js +63 -0
- package/src/Processor/GeometryExtractor.js +15 -5
- package/src/Processor/HostMemory.js +7 -1
- package/src/Processor/IESParser.js +47 -35
- package/src/Processor/InstanceTable.js +1 -1
- package/src/Processor/KernelManager.js +35 -2
- package/src/Processor/MaterialPacking.js +10 -8
- package/src/Processor/PBRT/PBRTMaterials.js +254 -42
- package/src/Processor/PBRT/PBRTParser.js +49 -19
- package/src/Processor/PBRT/PBRTScattering.js +93 -0
- package/src/Processor/PBRT/PBRTSceneBuilder.js +1050 -75
- package/src/Processor/PBRT/PBRTTextureBake.js +179 -0
- package/src/Processor/PBRT/PFM.js +59 -0
- package/src/Processor/PackedRayBuffer.js +116 -9
- package/src/Processor/ParallelBVHBuilder.js +3 -6
- package/src/Processor/PhysicalSky.js +5 -4
- package/src/Processor/PlatformImageLoader.js +50 -6
- package/src/Processor/QueueManager.js +39 -5
- package/src/Processor/ReinsertionOptimizer.js +2 -2
- package/src/Processor/SceneMetadata.js +30 -5
- package/src/Processor/SceneProcessor.js +53 -62
- package/src/Processor/ShaderBuilder.js +6 -16
- package/src/Processor/SimpleSky.js +1 -62
- package/src/Processor/SolarLimb.js +3 -0
- package/src/Processor/SplitBLAS.js +1 -1
- package/src/Processor/StorageTexturePool.js +22 -1
- package/src/Processor/TLASBuilder.js +1 -3
- package/src/Processor/TextureBuckets.js +237 -0
- package/src/Processor/TextureCreator.js +181 -8
- package/src/Processor/ToneMapGPU.js +64 -15
- package/src/Processor/Workers/BVHRefitWorker.js +5 -2
- package/src/Processor/Workers/BVHSubtreeWorker.js +1 -34
- package/src/Processor/Workers/BVHWorker.js +5 -18
- package/src/Processor/Workers/CDFWorker.js +6 -183
- package/src/Processor/Workers/TexturesWorker.js +103 -18
- package/src/Processor/archiveFormats.js +7 -0
- package/src/Processor/utils.js +2 -1
- package/src/RayzeeRenderer.js +3900 -0
- package/src/RenderSettings.js +68 -62
- package/src/Stages/ASVGF.js +13 -14
- package/src/Stages/AutoExposure.js +17 -17
- package/src/Stages/BilateralFilter.js +2 -1
- package/src/Stages/Compositor.js +8 -23
- package/src/Stages/DenoiserSettings.js +182 -0
- package/src/Stages/EdgeFilter.js +2 -1
- package/src/Stages/MotionVector.js +1 -1
- package/src/Stages/NRD.js +11 -5
- package/src/Stages/NormalDepth.js +12 -8
- package/src/Stages/PathTracer.js +336 -43
- package/src/Stages/PathTracerStage.js +69 -66
- package/src/Stages/Variance.js +1 -1
- package/src/Storage/BLASCache.js +1 -1
- package/src/Storage/CDFCache.js +18 -17
- package/src/Storage/DownloadCache.js +1 -1
- package/src/Storage/SceneGraphCodec.js +46 -3
- package/src/Storage/SpillStore.js +1 -1
- package/src/Storage/StorageManager.js +45 -9
- package/src/Storage/areas.js +4 -0
- package/src/TSL/BVHTraversal.js +50 -25
- package/src/TSL/Bidirectional.js +208 -0
- package/src/TSL/BidirectionalLamps.js +132 -0
- package/src/TSL/Clearcoat.js +15 -6
- package/src/TSL/Common.js +20 -15
- package/src/TSL/ConnectKernel.js +167 -0
- package/src/TSL/Debugger.js +1 -1
- package/src/TSL/Displacement.js +4 -3
- package/src/TSL/EmissiveSampling.js +65 -18
- package/src/TSL/Environment.js +77 -106
- package/src/TSL/EnvironmentCDF.js +85 -39
- package/src/TSL/ExtendKernel.js +8 -3
- package/src/TSL/FinalWriteKernel.js +4 -4
- package/src/TSL/GenerateKernel.js +18 -4
- package/src/TSL/HitFacet.js +35 -5
- package/src/TSL/LightBVHSampling.js +40 -9
- package/src/TSL/LightGenerateKernel.js +293 -0
- package/src/TSL/LightGuide.js +198 -0
- package/src/TSL/LightSplatKernel.js +180 -0
- package/src/TSL/LightVisibility.js +111 -0
- package/src/TSL/LightsCore.js +13 -38
- package/src/TSL/LightsDirect.js +28 -29
- package/src/TSL/LightsIndirect.js +3 -1
- package/src/TSL/LightsSampling.js +239 -51
- package/src/TSL/MaterialEvaluation.js +113 -31
- package/src/TSL/MaterialProperties.js +44 -17
- package/src/TSL/MaterialTransmission.js +52 -47
- package/src/TSL/MergeKernel.js +224 -0
- package/src/TSL/PathTracerCore.js +65 -29
- package/src/TSL/Random.js +5 -1
- package/src/TSL/SceneResources.js +51 -0
- package/src/TSL/ShadeKernel.js +985 -101
- package/src/TSL/Struct.js +10 -0
- package/src/TSL/Sun.js +1 -1
- package/src/TSL/TextureSampling.js +66 -61
- package/src/addons/archives.js +14 -0
- package/src/addons/bidirectional.js +13 -0
- package/src/addons/color.js +32 -0
- package/src/addons/formats.js +16 -0
- package/src/addons/physicalSky.js +14 -0
- package/src/addons/storage.js +19 -0
- package/src/core.js +31 -0
- package/src/index.js +13 -23
- package/src/integrators/BidirectionalIntegrator.js +838 -0
- package/src/managers/AnimationManager.js +88 -6
- package/src/managers/CameraManager.js +103 -46
- package/src/managers/DenoisingManager.js +14 -10
- package/src/managers/EnvironmentManager.js +125 -103
- package/src/managers/GoboManager.js +9 -0
- package/src/managers/MaterialDataManager.js +48 -37
- package/src/managers/UniformManager.js +32 -10
- package/dist/ToneMapGPU-B6XIe3DU.js +0 -544
- package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
- package/src/Processor/TreeletOptimizer.js +0 -574
|
@@ -2,11 +2,11 @@ import { Fn, float, int, uint, vec2, vec4, If, Loop, Return, instanceIndex, max,
|
|
|
2
2
|
|
|
3
3
|
import { REC709_LUMINANCE_COEFFICIENTS } from './Common.js';
|
|
4
4
|
|
|
5
|
-
/** Floats per row of the packed table: width + 1 texels, padded to the 256 bytes a buffer→texture copy needs. */
|
|
6
|
-
export const cdfRowStride = width => Math.ceil( ( width + 1 ) *
|
|
5
|
+
/** Floats per row of the packed table: width + 1 RGBA texels, padded to the 256 bytes a buffer→texture copy needs. */
|
|
6
|
+
export const cdfRowStride = width => Math.ceil( ( width + 1 ) * 16 / 256 ) * 64;
|
|
7
7
|
|
|
8
|
-
// First index in [0, n) whose value is
|
|
9
|
-
function
|
|
8
|
+
// First index in [0, n) whose value is above target, n − 1 when none is — as the CPU builder's cutpoints.
|
|
9
|
+
function firstAbove( n, valueAt, target ) {
|
|
10
10
|
|
|
11
11
|
const lo = int( 0 ).toVar();
|
|
12
12
|
const hi = int( n - 1 ).toVar();
|
|
@@ -15,7 +15,7 @@ function lowerBound( n, valueAt, target ) {
|
|
|
15
15
|
If( lo.lessThan( hi ), () => {
|
|
16
16
|
|
|
17
17
|
const mid = lo.add( hi ).div( 2 ).toVar();
|
|
18
|
-
If( valueAt( mid ).
|
|
18
|
+
If( valueAt( mid ).lessThanEqual( target ), () => {
|
|
19
19
|
|
|
20
20
|
lo.assign( mid.add( 1 ) );
|
|
21
21
|
|
|
@@ -36,13 +36,16 @@ function lowerBound( n, valueAt, target ) {
|
|
|
36
36
|
// against the row total it ends on.
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* The GPU twin of `
|
|
40
|
-
*
|
|
39
|
+
* The GPU twin of `buildExactEnvironmentTable`, in packExactTable's (width + 1) × height RGBA layout (one cell a
|
|
40
|
+
* texel, compensated by the same mean, without its neighbour weighting: the sky has no sharp texel).
|
|
41
|
+
* `stats[ 1 ]` ends as ( totalSum, compensationDelta, compensated, 0 ).
|
|
41
42
|
* @returns {Array} kernels, dispatched in order
|
|
42
43
|
*/
|
|
43
44
|
export function buildEnvironmentCDFKernels( { pixels, rows, prefix, stats, cdf, width, height } ) {
|
|
44
45
|
|
|
45
46
|
const stride = cdfRowStride( width );
|
|
47
|
+
// Channel c of texel ( x, y ).
|
|
48
|
+
const at = ( x, y, c ) => uint( y ).mul( uint( stride ) ).add( uint( x ).mul( uint( 4 ) ) ).add( uint( c ) );
|
|
46
49
|
const sinTheta = y => sin( float( y ).add( 0.5 ).mul( Math.PI / height ) );
|
|
47
50
|
const weight = ( y, x, sinT ) => dot( pixels.element( y.mul( width ).add( x ) ).xyz, REC709_LUMINANCE_COEFFICIENTS ).mul( sinT );
|
|
48
51
|
const firstThreadOnly = () => If( instanceIndex.greaterThan( uint( 0 ) ), () => {
|
|
@@ -109,7 +112,7 @@ export function buildEnvironmentCDFKernels( { pixels, rows, prefix, stats, cdf,
|
|
|
109
112
|
|
|
110
113
|
} )().compute( height, [ 64 ] );
|
|
111
114
|
|
|
112
|
-
const
|
|
115
|
+
const totals = Fn( () => {
|
|
113
116
|
|
|
114
117
|
firstThreadOnly();
|
|
115
118
|
const compensatedTotal = float( 0 ).toVar();
|
|
@@ -118,59 +121,102 @@ export function buildEnvironmentCDFKernels( { pixels, rows, prefix, stats, cdf,
|
|
|
118
121
|
compensatedTotal.addAssign( rows.element( i ).y );
|
|
119
122
|
|
|
120
123
|
} );
|
|
121
|
-
const
|
|
124
|
+
const s = stats.element( 0 ).toVar();
|
|
125
|
+
stats.element( 1 ).assign( select( compensatedTotal.greaterThan( 0 ), vec4( compensatedTotal, s.y, 1, 0 ), vec4( s.x, 0, 0, 0 ) ) );
|
|
122
126
|
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
} )().compute( 1, [ 1 ] );
|
|
128
|
+
|
|
129
|
+
// buildExactEnvironmentTable's floor: a share of the mean weight in every cell.
|
|
130
|
+
const exactFloor = () => stats.element( 0 ).x.mul( 1e-4 / ( width * height ) );
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
const exactRows = Fn( () => {
|
|
133
|
+
|
|
134
|
+
const y = instanceIndex;
|
|
135
|
+
If( y.greaterThanEqual( uint( height ) ), () => {
|
|
136
|
+
|
|
137
|
+
Return();
|
|
129
138
|
|
|
130
139
|
} );
|
|
131
140
|
|
|
132
|
-
const
|
|
133
|
-
stats.element( 1 ).
|
|
141
|
+
const floor = exactFloor().toVar();
|
|
142
|
+
const compensated = stats.element( 1 ).z.greaterThan( 0 ).toVar();
|
|
143
|
+
const r = rows.element( y ).toVar();
|
|
144
|
+
const rowSum = select( compensated, r.y, r.x ).add( floor.mul( width ) ).toVar();
|
|
145
|
+
const below = float( 0 ).toVar();
|
|
146
|
+
Loop( { start: int( 0 ), end: int( width ), type: 'int', condition: '<' }, ( { i } ) => {
|
|
147
|
+
|
|
148
|
+
const p = prefix.element( y.mul( width ).add( uint( i ) ) ).toVar();
|
|
149
|
+
const c = select( compensated, p.y, p.x ).add( floor.mul( float( i ).add( 1 ) ) ).div( max( rowSum, 1e-30 ) );
|
|
150
|
+
const sum = select( rowSum.greaterThan( 0 ), select( i.equal( int( width - 1 ) ), float( 1 ), c ), float( 0 ) ).toVar();
|
|
151
|
+
cdf.element( at( i, y, 0 ) ).assign( sum );
|
|
152
|
+
cdf.element( at( i, y, 1 ) ).assign( below );
|
|
153
|
+
below.assign( sum );
|
|
154
|
+
|
|
155
|
+
} );
|
|
156
|
+
|
|
157
|
+
} )().compute( height, [ 64 ] );
|
|
158
|
+
|
|
159
|
+
const exactMarginal = Fn( () => {
|
|
134
160
|
|
|
135
|
-
|
|
161
|
+
firstThreadOnly();
|
|
162
|
+
const floor = exactFloor().mul( width ).toVar();
|
|
163
|
+
const compensated = stats.element( 1 ).z.greaterThan( 0 ).toVar();
|
|
164
|
+
const rowSum = ( i ) => {
|
|
136
165
|
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
166
|
+
const r = rows.element( i ); return select( compensated, r.y, r.x ).add( floor );
|
|
167
|
+
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const total = float( 0 ).toVar();
|
|
171
|
+
Loop( { start: int( 0 ), end: int( height ), type: 'int', condition: '<' }, ( { i } ) => {
|
|
172
|
+
|
|
173
|
+
total.addAssign( rowSum( i ) );
|
|
174
|
+
|
|
175
|
+
} );
|
|
176
|
+
const cumulative = float( 0 ).toVar();
|
|
177
|
+
const below = float( 0 ).toVar();
|
|
178
|
+
Loop( { start: int( 0 ), end: int( height ), type: 'int', condition: '<' }, ( { i } ) => {
|
|
179
|
+
|
|
180
|
+
cumulative.addAssign( rowSum( i ) );
|
|
181
|
+
const c = select( i.equal( int( height - 1 ) ), float( 1 ), cumulative.div( max( total, 1e-30 ) ) );
|
|
182
|
+
const sum = select( total.greaterThan( 0 ), c, float( 0 ) ).toVar();
|
|
183
|
+
cdf.element( at( width, i, 0 ) ).assign( sum );
|
|
184
|
+
cdf.element( at( width, i, 1 ) ).assign( below );
|
|
185
|
+
below.assign( sum );
|
|
143
186
|
|
|
144
187
|
} );
|
|
145
188
|
|
|
146
189
|
} )().compute( 1, [ 1 ] );
|
|
147
190
|
|
|
148
|
-
|
|
191
|
+
// GUIDES_PER_ENTRY (2) guides an entry, in its texel's z and w: the rows' in columns [0, width), the marginal's in
|
|
192
|
+
// column width.
|
|
193
|
+
const rowGuides = 2 * width * height;
|
|
194
|
+
const guides = Fn( () => {
|
|
149
195
|
|
|
150
196
|
const idx = instanceIndex;
|
|
151
|
-
If( idx.greaterThanEqual( uint(
|
|
197
|
+
If( idx.greaterThanEqual( uint( rowGuides + 2 * height ) ), () => {
|
|
152
198
|
|
|
153
199
|
Return();
|
|
154
200
|
|
|
155
201
|
} );
|
|
156
202
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const k = lowerBound( width, j => {
|
|
203
|
+
If( idx.lessThan( uint( rowGuides ) ), () => {
|
|
204
|
+
|
|
205
|
+
const g = idx.mod( 2 * width ).toVar();
|
|
206
|
+
const y = idx.div( 2 * width ).toVar();
|
|
207
|
+
const x = firstAbove( width, j => cdf.element( at( j, y, 0 ) ), float( g ).div( 2 * width ) );
|
|
208
|
+
cdf.element( at( g.shiftRight( uint( 1 ) ), y, uint( 2 ).add( g.bitAnd( uint( 1 ) ) ) ) ).assign( float( x ) );
|
|
164
209
|
|
|
165
|
-
|
|
166
|
-
return select( useCompensated, p.y, p.x );
|
|
210
|
+
} ).Else( () => {
|
|
167
211
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
212
|
+
const g = idx.sub( uint( rowGuides ) ).toVar();
|
|
213
|
+
const y = firstAbove( height, j => cdf.element( at( width, j, 0 ) ), float( g ).div( 2 * height ) );
|
|
214
|
+
cdf.element( at( width, g.shiftRight( uint( 1 ) ), uint( 2 ).add( g.bitAnd( uint( 1 ) ) ) ) ).assign( float( y ) );
|
|
215
|
+
|
|
216
|
+
} );
|
|
171
217
|
|
|
172
|
-
} )().compute(
|
|
218
|
+
} )().compute( rowGuides + 2 * height, [ 64 ] );
|
|
173
219
|
|
|
174
|
-
return [ rowTotals, mean, prefixSums,
|
|
220
|
+
return [ rowTotals, mean, prefixSums, totals, exactRows, exactMarginal, guides ];
|
|
175
221
|
|
|
176
222
|
}
|
package/src/TSL/ExtendKernel.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
Fn, uint, int,
|
|
7
|
-
If,
|
|
6
|
+
Fn, uint, int, float,
|
|
7
|
+
If, dot, abs, select,
|
|
8
8
|
instanceIndex,
|
|
9
9
|
atomicLoad,
|
|
10
10
|
Return,
|
|
@@ -76,9 +76,14 @@ export function buildExtendKernel( params ) {
|
|
|
76
76
|
didHit: hitInfo.didHit, liftEnabled: shadowTerminatorOffset.greaterThan( 0.0 ),
|
|
77
77
|
} );
|
|
78
78
|
|
|
79
|
+
// origin + t · direction sits off a large triangle by t's own error, which grows with the triangle's size: the
|
|
80
|
+
// distance stored is moved along the ray onto the triangle's plane (not where it grazes the plane).
|
|
81
|
+
const cosToPlane = dot( direction, facet.faceN ).toVar();
|
|
82
|
+
const planeDst = hitInfo.dst.add( select( abs( cosToPlane ).greaterThan( 1e-3 ), facet.surfaceOffset.div( cosToPlane ), float( 0.0 ) ) );
|
|
83
|
+
|
|
79
84
|
writeHitPacked(
|
|
80
85
|
hitBufferRW, rayID,
|
|
81
|
-
|
|
86
|
+
planeDst,
|
|
82
87
|
uint( hitInfo.triangleIndex ),
|
|
83
88
|
hitInfo.uv.x, hitInfo.uv.y,
|
|
84
89
|
hitInfo.normal,
|
|
@@ -46,7 +46,7 @@ export function buildFinalWriteKernel( params ) {
|
|
|
46
46
|
visMode,
|
|
47
47
|
// Aux MRT (normalDepth + albedo) feeds only the denoiser/OIDN. Gated by a live uniform (1 = denoiser
|
|
48
48
|
// on): when off, skip the G-buffer decode, the prev-frame aux mix, and the two aux stores.
|
|
49
|
-
auxGBufferEnabled,
|
|
49
|
+
auxGBufferEnabled, gBuffer = true, // compiled in only when requested (PathTracer.requestOutput( 'gBuffer' ))
|
|
50
50
|
// Clean-aux normal (1 = temporally accumulate + renormalize the aux normal). On only for clean-aux
|
|
51
51
|
// OIDN models (calb_cnrm/high, alb_nrm/balanced); off for fast/ASVGF which want the bump normal.
|
|
52
52
|
cleanAuxNormalEnabled,
|
|
@@ -98,7 +98,7 @@ export function buildFinalWriteKernel( params ) {
|
|
|
98
98
|
const finalAlbedo = vec4( 0.0 ).xyz.toVar();
|
|
99
99
|
// Albedo .w carries the hit distance — OIDN reads albedo as 3 channels, so it is free.
|
|
100
100
|
const finalHitDist = float( 0.0 ).toVar();
|
|
101
|
-
If( auxOn, () => {
|
|
101
|
+
if ( gBuffer ) If( auxOn, () => {
|
|
102
102
|
|
|
103
103
|
const gbuf = readGBuffer( gBufferRO, rayID );
|
|
104
104
|
finalNormalDepth.assign( gbDecodeNormalDepth( gbuf ) );
|
|
@@ -118,7 +118,7 @@ export function buildFinalWriteKernel( params ) {
|
|
|
118
118
|
|
|
119
119
|
// Frozen pixels pass prev colour through unchanged (stale sample); active pixels accumulate.
|
|
120
120
|
finalColor.assign( select( wasFrozen, prevAccumSample.xyz, mix( prevAccumSample.xyz, sampleColor.xyz, accumulationAlpha ) ) );
|
|
121
|
-
If( auxOn.and( hasPreviousAux ), () => {
|
|
121
|
+
if ( gBuffer ) If( auxOn.and( hasPreviousAux ), () => {
|
|
122
122
|
|
|
123
123
|
// Albedo averages cleanly (it's a colour); so does the normalized hit distance in .w.
|
|
124
124
|
const prevAlbedoSample = texture( prevAlbedoTexture, prevUV, 0 ).toVar();
|
|
@@ -253,7 +253,7 @@ export function buildFinalWriteKernel( params ) {
|
|
|
253
253
|
|
|
254
254
|
const uintCoord = uvec2( uint( gx ), uint( gy ) );
|
|
255
255
|
textureStore( writeColorTex, uintCoord, vec4( finalColor, outputAlpha ) ).toWriteOnly();
|
|
256
|
-
If( auxOn, () => {
|
|
256
|
+
if ( gBuffer ) If( auxOn, () => {
|
|
257
257
|
|
|
258
258
|
textureStore( writeNDTex, uintCoord, finalNormalDepth ).toWriteOnly();
|
|
259
259
|
textureStore( writeAlbedoTex, uintCoord, vec4( finalAlbedo, finalHitDist ) ).toWriteOnly();
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import {
|
|
14
14
|
Fn, float, vec2, vec3, vec4, int, uint,
|
|
15
15
|
If, instanceIndex, atomicLoad,
|
|
16
|
-
localId, workgroupId,
|
|
16
|
+
localId, workgroupId, dot, max, select,
|
|
17
17
|
} from 'three/tsl';
|
|
18
18
|
|
|
19
19
|
import {
|
|
@@ -28,7 +28,7 @@ import { RAY_FLAG, COUNTER } from '../Processor/QueueManager.js';
|
|
|
28
28
|
import {
|
|
29
29
|
writeRayOriginMeta, writeRayDirFlags, writeRayThroughputPdf,
|
|
30
30
|
writeRayRadiance, writeGBuffer,
|
|
31
|
-
writeMediumStack, writeFeatureThroughput, writeRngState,
|
|
31
|
+
writeMediumStack, writeFeatureThroughput, writeRngState, writeRngMis,
|
|
32
32
|
} from '../Processor/PackedRayBuffer.js';
|
|
33
33
|
|
|
34
34
|
const WG_SIZE = 16;
|
|
@@ -45,8 +45,10 @@ export function buildGenerateKernel( params ) {
|
|
|
45
45
|
chunkRowBase, chunkRows, // row band offset (global first row) + row count for this chunk
|
|
46
46
|
transmissiveBounces, // per-ray refraction budget (megakernel parity: PathTracerCore.js:606)
|
|
47
47
|
auxGBufferEnabled, // live uniform: 1 = init the per-pixel G-buffer (denoiser on), 0 = skip it
|
|
48
|
+
gBuffer = true, // compiled in only when requested (PathTracer.requestOutput( 'gBuffer' ))
|
|
48
49
|
// listDriven: 1D dispatch over the active-pixel list (activeIndicesRO[tid] = LOCAL slot) instead of 2D.
|
|
49
50
|
listDriven = false, activeIndicesRO = null, counters = null,
|
|
51
|
+
bidirectional: bdpt = null,
|
|
50
52
|
} = params;
|
|
51
53
|
|
|
52
54
|
const auxOn = auxGBufferEnabled.greaterThan( uint( 0 ) );
|
|
@@ -89,7 +91,7 @@ export function buildGenerateKernel( params ) {
|
|
|
89
91
|
// tell subject from background. Output is unaffected: FinalWrite forces alpha 1 when transparent-bg is off.
|
|
90
92
|
writeRayRadiance( rayBufferRW, rayID, vec4( vec3( 0.0 ), float( 1.0 ) ) );
|
|
91
93
|
|
|
92
|
-
If( auxOn, () => {
|
|
94
|
+
if ( gBuffer ) If( auxOn, () => {
|
|
93
95
|
|
|
94
96
|
// default: normal +Z, depth 1 (far), black albedo (background/miss). Per-CHUNK G-buffer → LOCAL slot.
|
|
95
97
|
writeGBuffer( gBufferRW, rayID, vec3( 0.0, 0.0, 1.0 ), float( 1.0 ), vec3( 0.0 ), float( 0.0 ) );
|
|
@@ -100,7 +102,19 @@ export function buildGenerateKernel( params ) {
|
|
|
100
102
|
|
|
101
103
|
writeMediumStack( rayBufferRW, rayID, uint( 0 ), uint( transmissiveBounces ), float( 1.0 ), float( 1.0 ), float( 1.0 ) );
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
if ( bdpt ) {
|
|
106
|
+
|
|
107
|
+
// Georgiev (31): light tracing's N_L samples over this ray's density 1 / (A_pixel cos³θ).
|
|
108
|
+
const cosCamera = max( dot( ray.direction, bdpt.cameraForward ), 1e-4 );
|
|
109
|
+
const dVCM = select( bdpt.lightTrace.greaterThan( uint( 0 ) ),
|
|
110
|
+
bdpt.lib.mis( float( bdpt.lightPaths ).mul( bdpt.pixelArea ).mul( cosCamera ).mul( cosCamera ).mul( cosCamera ) ), float( 0.0 ) );
|
|
111
|
+
writeRngMis( hitBufferRW, rayID, seed, dVCM, float( 0.0 ) );
|
|
112
|
+
|
|
113
|
+
} else {
|
|
114
|
+
|
|
115
|
+
writeRngState( hitBufferRW, rayID, seed );
|
|
116
|
+
|
|
117
|
+
}
|
|
104
118
|
|
|
105
119
|
};
|
|
106
120
|
|
package/src/TSL/HitFacet.js
CHANGED
|
@@ -15,18 +15,20 @@ import {
|
|
|
15
15
|
packHalf2x16, unpackHalf2x16,
|
|
16
16
|
} from 'three/tsl';
|
|
17
17
|
import {
|
|
18
|
-
unpackTriangleNormal, triangleRow, instanceRows, instanceFaceNormalToWorld,
|
|
18
|
+
unpackTriangleNormal, triangleRow, instanceRows, instanceFaceNormalToWorld, instancePointToWorld,
|
|
19
19
|
} from './Common.js';
|
|
20
20
|
import { shadowTerminatorLift } from './ShadowTerminator.js';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* @returns {{ faceN: Node, liftScale: Node }} the facet normal on the viewer's side (the
|
|
24
|
-
* interpolated one for a degenerate triangle),
|
|
23
|
+
* @returns {{ faceN: Node, liftScale: Node, surfaceOffset: Node }} the facet normal on the viewer's side (the
|
|
24
|
+
* interpolated one for a degenerate triangle), the terminator lift (0 unless `liftEnabled`), and how far along
|
|
25
|
+
* faceN `hitPoint` lies from the triangle's plane (ExtendKernel moves the stored distance onto it)
|
|
25
26
|
*/
|
|
26
27
|
export function hitFacet( { triangleBuffer, bvhBuffer, triIdx, instanceLeaf, hitPoint, smoothNormal, viewDir, didHit, liftEnabled } ) {
|
|
27
28
|
|
|
28
29
|
const faceN = vec3( 0.0, 0.0, 1.0 ).toVar();
|
|
29
30
|
const liftScale = float( 0.0 ).toVar();
|
|
31
|
+
const surfaceOffset = float( 0.0 ).toVar();
|
|
30
32
|
|
|
31
33
|
If( didHit, () => {
|
|
32
34
|
|
|
@@ -47,9 +49,18 @@ export function hitFacet( { triangleBuffer, bvhBuffer, triIdx, instanceLeaf, hit
|
|
|
47
49
|
|
|
48
50
|
} );
|
|
49
51
|
|
|
50
|
-
const
|
|
52
|
+
const degenerate = dot( face, face ).lessThanEqual( 0.0 ).toVar();
|
|
53
|
+
const n = select( degenerate, smoothNormal, normalize( face ) ).toVar();
|
|
51
54
|
faceN.assign( select( dot( n, viewDir ).lessThan( 0.0 ), n.negate(), n ) );
|
|
52
55
|
|
|
56
|
+
const corner = V0.toVar();
|
|
57
|
+
If( instanced, () => {
|
|
58
|
+
|
|
59
|
+
corner.assign( instancePointToWorld( instanceRows( bvhBuffer, instanceLeaf ), V0 ) );
|
|
60
|
+
|
|
61
|
+
} );
|
|
62
|
+
surfaceOffset.assign( select( degenerate, float( 0.0 ), dot( corner.sub( hitPoint ), faceN ) ) );
|
|
63
|
+
|
|
53
64
|
If( liftEnabled, () => {
|
|
54
65
|
|
|
55
66
|
liftScale.assign( shadowTerminatorLift( {
|
|
@@ -62,7 +73,26 @@ export function hitFacet( { triangleBuffer, bvhBuffer, triIdx, instanceLeaf, hit
|
|
|
62
73
|
|
|
63
74
|
} );
|
|
64
75
|
|
|
65
|
-
return { faceN, liftScale };
|
|
76
|
+
return { faceN, liftScale, surfaceOffset };
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The triangle's unit winding normal in world space: what the traversal's front/back test sees (a mirrored
|
|
82
|
+
* placement keeps its object-space sense). The interpolated normal can face the other way near a coarse mesh's
|
|
83
|
+
* silhouette. Unit length because sideAccepts has a threshold: a raw cross product of a small triangle is under it.
|
|
84
|
+
*/
|
|
85
|
+
export function windingNormal( triangleBuffer, bvhBuffer, triIdx, instanceLeaf ) {
|
|
86
|
+
|
|
87
|
+
const V0 = uintBitsToFloat( triangleRow( triangleBuffer, triIdx, 0 ).xyz ).toVar();
|
|
88
|
+
const local = cross( uintBitsToFloat( triangleRow( triangleBuffer, triIdx, 1 ).xyz ).sub( V0 ), uintBitsToFloat( triangleRow( triangleBuffer, triIdx, 2 ).xyz ).sub( V0 ) ).toVar();
|
|
89
|
+
const n = local.toVar();
|
|
90
|
+
If( instanceLeaf.greaterThanEqual( int( 0 ) ), () => {
|
|
91
|
+
|
|
92
|
+
n.assign( instanceFaceNormalToWorld( instanceRows( bvhBuffer, instanceLeaf ), local ) );
|
|
93
|
+
|
|
94
|
+
} );
|
|
95
|
+
return normalize( n );
|
|
66
96
|
|
|
67
97
|
}
|
|
68
98
|
|
|
@@ -18,11 +18,14 @@ import {
|
|
|
18
18
|
normalize,
|
|
19
19
|
cross,
|
|
20
20
|
length,
|
|
21
|
+
abs,
|
|
21
22
|
} from 'three/tsl';
|
|
22
23
|
import { MIN_PDF } from './Common.js';
|
|
24
|
+
import { sideAccepts } from './BVHTraversal.js';
|
|
23
25
|
import { getRandomSample1D, getRandomSample2D } from './Random.js';
|
|
24
26
|
import {
|
|
25
27
|
EmissiveSample,
|
|
28
|
+
EmissiveSampleIndexed,
|
|
26
29
|
sampleTriangle,
|
|
27
30
|
interpolateNormal,
|
|
28
31
|
fetchTriangleData,
|
|
@@ -103,7 +106,7 @@ export const lbvhNodeImportance = Fn( ( [ nMin, power, nMax, coneAxis, cosThetaO
|
|
|
103
106
|
*
|
|
104
107
|
* Returns an EmissiveSample struct.
|
|
105
108
|
*/
|
|
106
|
-
|
|
109
|
+
const makeSampleLightBVHTriangle = ( indexed ) => Fn( ( [
|
|
107
110
|
hitPoint, surfaceNormal,
|
|
108
111
|
rngState,
|
|
109
112
|
pixelCoord, resolution, frame, dimBase,
|
|
@@ -111,9 +114,11 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
111
114
|
emissiveTriangleBuffer,
|
|
112
115
|
emissiveVec4Offset,
|
|
113
116
|
triangleBuffer, bvhBuffer,
|
|
117
|
+
// The surface passes light through diffusely: a point behind it is as good as one in front.
|
|
118
|
+
throughSurface,
|
|
114
119
|
] ) => {
|
|
115
120
|
|
|
116
|
-
const
|
|
121
|
+
const fields = {
|
|
117
122
|
position: vec3( 0.0 ),
|
|
118
123
|
normal: vec3( 0.0 ),
|
|
119
124
|
emission: vec3( 0.0 ),
|
|
@@ -123,7 +128,10 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
123
128
|
area: float( 0.0 ),
|
|
124
129
|
cosThetaLight: float( 0.0 ),
|
|
125
130
|
valid: false,
|
|
126
|
-
}
|
|
131
|
+
};
|
|
132
|
+
const result = ( indexed
|
|
133
|
+
? EmissiveSampleIndexed( { ...fields, triangleIndex: int( - 1 ), faceNormal: vec3( 0.0 ) } )
|
|
134
|
+
: EmissiveSample( fields ) ).toVar();
|
|
127
135
|
|
|
128
136
|
// Accumulated selection PDF (product of per-level choice probabilities)
|
|
129
137
|
const selectionPdf = float( 1.0 ).toVar();
|
|
@@ -279,9 +287,9 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
279
287
|
const samplePos = sphResult.position;
|
|
280
288
|
|
|
281
289
|
const surfaceFacing = dot( dir, surfaceNormal );
|
|
282
|
-
const emissiveFacing = dot( dir, geoNormal
|
|
290
|
+
const emissiveFacing = abs( dot( dir, geoNormal ) );
|
|
283
291
|
|
|
284
|
-
If( surfaceFacing.greaterThan( float( 0.0 ) ).
|
|
292
|
+
If( surfaceFacing.greaterThan( float( 0.0 ) ).or( throughSurface ).and( sideAccepts( triData.side, dot( dir, geoNormal ) ) ), () => {
|
|
285
293
|
|
|
286
294
|
// Interpolate normal at sampled point via barycentric coords
|
|
287
295
|
const barycentricCoords = barycentricFromPoint( samplePos, triData.v0, triData.v1, triData.v2 );
|
|
@@ -305,6 +313,12 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
305
313
|
result.area.assign( area );
|
|
306
314
|
result.cosThetaLight.assign( emissiveFacing );
|
|
307
315
|
result.valid.assign( true );
|
|
316
|
+
if ( indexed ) {
|
|
317
|
+
|
|
318
|
+
result.triangleIndex.assign( triangleIndex );
|
|
319
|
+
result.faceNormal.assign( geoNormal );
|
|
320
|
+
|
|
321
|
+
}
|
|
308
322
|
|
|
309
323
|
} );
|
|
310
324
|
|
|
@@ -322,9 +336,11 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
322
336
|
const dir = toEmissive.div( dist );
|
|
323
337
|
|
|
324
338
|
const surfaceFacing = dot( dir, surfaceNormal );
|
|
325
|
-
|
|
339
|
+
// The facet's cosine, not the shading normal's: it is what turns an area density into a solid-angle one.
|
|
340
|
+
const emissiveFacing = abs( dot( dir, geoNormal ) );
|
|
326
341
|
|
|
327
|
-
|
|
342
|
+
// Edge-on (a two-sided emitter passes its side test there) the density is infinite and the light zero.
|
|
343
|
+
If( surfaceFacing.greaterThan( float( 0.0 ) ).or( throughSurface ).and( sideAccepts( triData.side, dot( dir, geoNormal ) ) ).and( emissiveFacing.greaterThan( float( 0.0 ) ) ), () => {
|
|
328
344
|
|
|
329
345
|
// PDF: selectionPdf / area, converted to solid angle: pdfArea * distSq / cosLight
|
|
330
346
|
const pdfArea = selectionPdf.div( max( area, float( 1e-10 ) ) );
|
|
@@ -339,6 +355,12 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
339
355
|
result.area.assign( area );
|
|
340
356
|
result.cosThetaLight.assign( emissiveFacing );
|
|
341
357
|
result.valid.assign( true );
|
|
358
|
+
if ( indexed ) {
|
|
359
|
+
|
|
360
|
+
result.triangleIndex.assign( triangleIndex );
|
|
361
|
+
result.faceNormal.assign( geoNormal );
|
|
362
|
+
|
|
363
|
+
}
|
|
342
364
|
|
|
343
365
|
} );
|
|
344
366
|
|
|
@@ -350,6 +372,9 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
350
372
|
|
|
351
373
|
} );
|
|
352
374
|
|
|
375
|
+
export const sampleLightBVHTriangle = /*@__PURE__*/ makeSampleLightBVHTriangle( false );
|
|
376
|
+
export const sampleLightBVHTriangleIndexed = /*@__PURE__*/ makeSampleLightBVHTriangle( true );
|
|
377
|
+
|
|
353
378
|
// ================================================================================
|
|
354
379
|
// LIGHT-BVH MIS PDF (re-walk)
|
|
355
380
|
// ================================================================================
|
|
@@ -482,6 +507,12 @@ export const calculateLightBVHPdf = Fn( ( [
|
|
|
482
507
|
|
|
483
508
|
// Convert selection pdf → solid-angle measure using the SAME heuristic as the sampler.
|
|
484
509
|
const triData = TriangleData.wrap( fetchTriangleData( triIdx, triangleBuffer, bvhBuffer, targetInstance ) );
|
|
510
|
+
// The sampler draws only the sides the triangle emits from (a unit normal: sideAccepts has a threshold).
|
|
511
|
+
If( sideAccepts( triData.side, dot( rayDir, normalize( cross( triData.v1.sub( triData.v0 ), triData.v2.sub( triData.v0 ) ) ) ) ).not(), () => {
|
|
512
|
+
|
|
513
|
+
selectionPdf.assign( float( 0.0 ) );
|
|
514
|
+
|
|
515
|
+
} );
|
|
485
516
|
If( useSphericalSampling( triData.v0, triData.v1, triData.v2, shadingPoint ), () => {
|
|
486
517
|
|
|
487
518
|
const solidAngle = sphericalTriangleSolidAngle( triData.v0, triData.v1, triData.v2, shadingPoint );
|
|
@@ -490,7 +521,7 @@ export const calculateLightBVHPdf = Fn( ( [
|
|
|
490
521
|
} ).Else( () => {
|
|
491
522
|
|
|
492
523
|
const geoNormal = normalize( cross( triData.v1.sub( triData.v0 ), triData.v2.sub( triData.v0 ) ) );
|
|
493
|
-
const cosLight = max( dot( rayDir
|
|
524
|
+
const cosLight = max( abs( dot( rayDir, geoNormal ) ), float( 0.001 ) );
|
|
494
525
|
const area = triangleArea( triData.v0, triData.v1, triData.v2 );
|
|
495
526
|
const distSq = hitDistance.mul( hitDistance );
|
|
496
527
|
const pdfArea = selectionPdf.div( max( area, float( 1e-10 ) ) );
|
|
@@ -502,6 +533,6 @@ export const calculateLightBVHPdf = Fn( ( [
|
|
|
502
533
|
|
|
503
534
|
} );
|
|
504
535
|
|
|
505
|
-
return max( result, MIN_PDF );
|
|
536
|
+
return select( result.greaterThan( 0.0 ), max( result, MIN_PDF ), float( 0.0 ) );
|
|
506
537
|
|
|
507
538
|
} );
|