rayzee 7.10.1 → 7.10.2
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 +2 -3
- package/dist/rayzee.es.js +1175 -1349
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +34 -46
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/EngineDefaults.js +0 -5
- package/src/PathTracerApp.js +0 -4
- package/src/Processor/TextureCreator.js +16 -1
- package/src/Stages/Compositor.js +0 -1
- package/src/TSL/Common.js +0 -17
- package/src/managers/DenoisingManager.js +11 -23
- package/src/Stages/SSRC.js +0 -328
- package/src/TSL/SSRC.js +0 -266
package/src/TSL/SSRC.js
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
// Screen-Space Radiance Cache (SSRC) — TSL compute shader builders
|
|
2
|
-
//
|
|
3
|
-
// Two passes per frame:
|
|
4
|
-
// Pass 1 (Temporal): Reproject previous cache via motion vectors, EMA blend
|
|
5
|
-
// Pass 2 (Spatial): 8-tap neighbor reuse weighted by normal/depth similarity
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
Fn,
|
|
9
|
-
vec3,
|
|
10
|
-
vec4,
|
|
11
|
-
float,
|
|
12
|
-
int,
|
|
13
|
-
ivec2,
|
|
14
|
-
uvec2,
|
|
15
|
-
If,
|
|
16
|
-
max,
|
|
17
|
-
min,
|
|
18
|
-
mix,
|
|
19
|
-
textureLoad,
|
|
20
|
-
textureStore,
|
|
21
|
-
localId,
|
|
22
|
-
workgroupId,
|
|
23
|
-
} from 'three/tsl';
|
|
24
|
-
import { normalDepthWeight } from './Common.js';
|
|
25
|
-
|
|
26
|
-
// ── Pass 1: Temporal Accumulation ──────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Build the temporal reprojection + EMA accumulation compute shader.
|
|
30
|
-
*
|
|
31
|
-
* @param {object} params
|
|
32
|
-
* @param {TextureNode} params.colorTexNode — pathtracer:color (current frame)
|
|
33
|
-
* @param {TextureNode} params.ndTexNode — pathtracer:normalDepth (current frame)
|
|
34
|
-
* @param {TextureNode} params.motionTexNode — motionVector:screenSpace
|
|
35
|
-
* @param {TextureNode} params.readCacheTexNode — previous frame's cache (ping-pong read)
|
|
36
|
-
* @param {TextureNode} params.readPrevNDTexNode — previous frame's normalDepth (ping-pong read)
|
|
37
|
-
* @param {StorageTexture} params.writeCacheTex — this frame's cache output (ping-pong write)
|
|
38
|
-
* @param {StorageTexture} params.writePrevNDTex — current normalDepth saved for next frame
|
|
39
|
-
* @param {uniform} params.resW / params.resH — render dimensions
|
|
40
|
-
* @param {uniform} params.temporalAlpha — EMA blend factor (0.05–0.2)
|
|
41
|
-
* @param {uniform} params.phiNormal — normal edge-stopping exponent
|
|
42
|
-
* @param {uniform} params.phiDepth — depth edge-stopping scale
|
|
43
|
-
* @param {uniform} params.maxHistory — history frame cap
|
|
44
|
-
* @param {uniform} params.framesSinceReset — frames since last reset; 0 = skip cache lookup
|
|
45
|
-
* @returns {Fn} — call `.compute([dX, dY, 1], [8, 8, 1])` on the result
|
|
46
|
-
*/
|
|
47
|
-
export function buildTemporalPass( {
|
|
48
|
-
colorTexNode,
|
|
49
|
-
ndTexNode,
|
|
50
|
-
motionTexNode,
|
|
51
|
-
readCacheTexNode,
|
|
52
|
-
readPrevNDTexNode,
|
|
53
|
-
writeCacheTex,
|
|
54
|
-
writePrevNDTex,
|
|
55
|
-
resW,
|
|
56
|
-
resH,
|
|
57
|
-
temporalAlpha,
|
|
58
|
-
phiNormal,
|
|
59
|
-
phiDepth,
|
|
60
|
-
maxHistory,
|
|
61
|
-
framesSinceReset,
|
|
62
|
-
} ) {
|
|
63
|
-
|
|
64
|
-
const WG_SIZE = 8;
|
|
65
|
-
|
|
66
|
-
return Fn( () => {
|
|
67
|
-
|
|
68
|
-
const gx = int( workgroupId.x ).mul( WG_SIZE ).add( int( localId.x ) );
|
|
69
|
-
const gy = int( workgroupId.y ).mul( WG_SIZE ).add( int( localId.y ) );
|
|
70
|
-
|
|
71
|
-
If( gx.lessThan( int( resW ) ).and( gy.lessThan( int( resH ) ) ), () => {
|
|
72
|
-
|
|
73
|
-
const coord = ivec2( gx, gy );
|
|
74
|
-
|
|
75
|
-
// Current frame data
|
|
76
|
-
const currentColor = textureLoad( colorTexNode, coord ).xyz;
|
|
77
|
-
const currentND = textureLoad( ndTexNode, coord );
|
|
78
|
-
|
|
79
|
-
// Default: pass-through, history = 1 (used on reset frames or cache misses)
|
|
80
|
-
const result = vec4( currentColor, 1.0 ).toVar();
|
|
81
|
-
|
|
82
|
-
// Skip cache lookup on the first frame after a reset — prevents stale data bleeding in
|
|
83
|
-
If( framesSinceReset.greaterThan( int( 0 ) ), () => {
|
|
84
|
-
|
|
85
|
-
// Read motion vector (.xy = UV-space offset, .w = validity)
|
|
86
|
-
const motion = textureLoad( motionTexNode, coord );
|
|
87
|
-
const motionValid = motion.w.greaterThan( 0.5 );
|
|
88
|
-
|
|
89
|
-
// Reprojected pixel coordinates (ASVGF convention: current - motion * res)
|
|
90
|
-
const prevXf = float( gx ).sub( motion.x.mul( resW ) );
|
|
91
|
-
const prevYf = float( gy ).sub( motion.y.mul( resH ) );
|
|
92
|
-
const prevOnScreen = prevXf.greaterThanEqual( 0.0 )
|
|
93
|
-
.and( prevXf.lessThan( float( resW ) ) )
|
|
94
|
-
.and( prevYf.greaterThanEqual( 0.0 ) )
|
|
95
|
-
.and( prevYf.lessThan( float( resH ) ) );
|
|
96
|
-
|
|
97
|
-
If( motionValid.and( prevOnScreen ), () => {
|
|
98
|
-
|
|
99
|
-
const prevX = int( prevXf ).clamp( int( 0 ), int( resW ).sub( 1 ) );
|
|
100
|
-
const prevY = int( prevYf ).clamp( int( 0 ), int( resH ).sub( 1 ) );
|
|
101
|
-
const prevCoord = ivec2( prevX, prevY );
|
|
102
|
-
|
|
103
|
-
// Edge-stopping: compare normals and depths
|
|
104
|
-
// Normals packed in [0,1] in normalDepth texture — decode to [-1,1]
|
|
105
|
-
const currentNormal = currentND.xyz.mul( 2.0 ).sub( 1.0 );
|
|
106
|
-
const prevND = textureLoad( readPrevNDTexNode, prevCoord );
|
|
107
|
-
const prevNormal = prevND.xyz.mul( 2.0 ).sub( 1.0 );
|
|
108
|
-
|
|
109
|
-
const similarity = normalDepthWeight(
|
|
110
|
-
currentNormal, prevNormal,
|
|
111
|
-
currentND.w, prevND.w,
|
|
112
|
-
phiNormal, phiDepth
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
If( similarity.greaterThan( 0.01 ), () => {
|
|
116
|
-
|
|
117
|
-
// Read previous cache: .rgb = radiance, .w = history count
|
|
118
|
-
const prevCache = textureLoad( readCacheTexNode, prevCoord );
|
|
119
|
-
const prevColor = prevCache.xyz;
|
|
120
|
-
const prevHistory = prevCache.w;
|
|
121
|
-
|
|
122
|
-
// Effective alpha: at least temporalAlpha, but use 1/(history+1) when
|
|
123
|
-
// history is low so the first few frames converge faster
|
|
124
|
-
const historyAlpha = float( 1.0 ).div( prevHistory.add( 1.0 ) );
|
|
125
|
-
const effectiveAlpha = max( temporalAlpha, historyAlpha );
|
|
126
|
-
|
|
127
|
-
// Weigh alpha by similarity to suppress bleeding across edges
|
|
128
|
-
const blendAlpha = min( effectiveAlpha.div( max( similarity, float( 0.1 ) ) ), 1.0 );
|
|
129
|
-
|
|
130
|
-
const blended = mix( prevColor, currentColor, blendAlpha );
|
|
131
|
-
const newHistory = min( prevHistory.add( 1.0 ), maxHistory );
|
|
132
|
-
|
|
133
|
-
result.assign( vec4( blended, newHistory ) );
|
|
134
|
-
|
|
135
|
-
} ).Else( () => {
|
|
136
|
-
|
|
137
|
-
// Edge detected or similarity too low — start fresh
|
|
138
|
-
result.assign( vec4( currentColor, 1.0 ) );
|
|
139
|
-
|
|
140
|
-
} );
|
|
141
|
-
|
|
142
|
-
} ).Else( () => {
|
|
143
|
-
|
|
144
|
-
// Off-screen or invalid motion — start fresh
|
|
145
|
-
result.assign( vec4( currentColor, 1.0 ) );
|
|
146
|
-
|
|
147
|
-
} );
|
|
148
|
-
|
|
149
|
-
} ); // end framesSinceReset guard
|
|
150
|
-
|
|
151
|
-
// Always write — even on reset frames (seeds cache with current color,
|
|
152
|
-
// and saves normalDepth so the next frame has valid prevND for edge-stopping)
|
|
153
|
-
textureStore( writeCacheTex, uvec2( gx, gy ), result ).toWriteOnly();
|
|
154
|
-
textureStore( writePrevNDTex, uvec2( gx, gy ), currentND ).toWriteOnly();
|
|
155
|
-
|
|
156
|
-
} );
|
|
157
|
-
|
|
158
|
-
} );
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// ── Pass 2: Spatial Neighbor Reuse ─────────────────────────────────────────
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Build the spatial 8-tap neighbor reuse compute shader.
|
|
166
|
-
*
|
|
167
|
-
* Samples 8 neighbors at ±spatialRadius in a cross + diagonal pattern.
|
|
168
|
-
* Spatial influence fades as temporal history accumulates (trust temporal over spatial).
|
|
169
|
-
*
|
|
170
|
-
* @param {object} params
|
|
171
|
-
* @param {TextureNode} params.ndTexNode — pathtracer:normalDepth (current frame)
|
|
172
|
-
* @param {TextureNode} params.readCacheTexNode — temporal cache from pass 1 (just-written)
|
|
173
|
-
* @param {StorageTexture} params.outputTex — final SSRC output
|
|
174
|
-
* @param {uniform} params.resW / params.resH
|
|
175
|
-
* @param {uniform} params.spatialRadius — neighbor offset in pixels (int)
|
|
176
|
-
* @param {uniform} params.spatialWeight — max spatial contribution weight
|
|
177
|
-
* @param {uniform} params.phiNormal — normal edge-stopping exponent
|
|
178
|
-
* @param {uniform} params.phiDepth — depth edge-stopping scale
|
|
179
|
-
* @returns {Fn}
|
|
180
|
-
*/
|
|
181
|
-
export function buildSpatialPass( {
|
|
182
|
-
colorTexNode,
|
|
183
|
-
ndTexNode,
|
|
184
|
-
readCacheTexNode,
|
|
185
|
-
outputTex,
|
|
186
|
-
resW,
|
|
187
|
-
resH,
|
|
188
|
-
spatialRadius,
|
|
189
|
-
spatialWeight,
|
|
190
|
-
phiNormal,
|
|
191
|
-
phiDepth,
|
|
192
|
-
} ) {
|
|
193
|
-
|
|
194
|
-
const WG_SIZE = 8;
|
|
195
|
-
|
|
196
|
-
// 8 neighbor offsets: axis-aligned ×4 + diagonal ×4
|
|
197
|
-
const OFFSETS = [
|
|
198
|
-
[ 1, 0 ], [ - 1, 0 ], [ 0, 1 ], [ 0, - 1 ],
|
|
199
|
-
[ 1, 1 ], [ - 1, 1 ], [ 1, - 1 ], [ - 1, - 1 ],
|
|
200
|
-
];
|
|
201
|
-
|
|
202
|
-
return Fn( () => {
|
|
203
|
-
|
|
204
|
-
const gx = int( workgroupId.x ).mul( WG_SIZE ).add( int( localId.x ) );
|
|
205
|
-
const gy = int( workgroupId.y ).mul( WG_SIZE ).add( int( localId.y ) );
|
|
206
|
-
|
|
207
|
-
If( gx.lessThan( int( resW ) ).and( gy.lessThan( int( resH ) ) ), () => {
|
|
208
|
-
|
|
209
|
-
const coord = ivec2( gx, gy );
|
|
210
|
-
|
|
211
|
-
// Center pixel
|
|
212
|
-
const centerCache = textureLoad( readCacheTexNode, coord );
|
|
213
|
-
const centerColor = centerCache.xyz;
|
|
214
|
-
const centerHistory = centerCache.w;
|
|
215
|
-
const centerND = textureLoad( ndTexNode, coord );
|
|
216
|
-
const centerNormal = centerND.xyz.mul( 2.0 ).sub( 1.0 );
|
|
217
|
-
|
|
218
|
-
// Adaptive spatial weight: fades to 0 once history >= 16
|
|
219
|
-
// (temporal data is reliable by then)
|
|
220
|
-
const historyFactor = float( 1.0 ).sub(
|
|
221
|
-
centerHistory.div( 16.0 ).clamp( 0.0, 1.0 )
|
|
222
|
-
);
|
|
223
|
-
const effectiveSpatialWeight = spatialWeight.mul( historyFactor );
|
|
224
|
-
|
|
225
|
-
// Weighted sum over 8 neighbors
|
|
226
|
-
const weightedSum = vec3( centerColor ).toVar();
|
|
227
|
-
const weightSum = float( 1.0 ).toVar();
|
|
228
|
-
|
|
229
|
-
for ( let i = 0; i < OFFSETS.length; i ++ ) {
|
|
230
|
-
|
|
231
|
-
const [ ox, oy ] = OFFSETS[ i ];
|
|
232
|
-
|
|
233
|
-
const nx = gx.add( int( spatialRadius ).mul( ox ) ).clamp( int( 0 ), int( resW ).sub( 1 ) );
|
|
234
|
-
const ny = gy.add( int( spatialRadius ).mul( oy ) ).clamp( int( 0 ), int( resH ).sub( 1 ) );
|
|
235
|
-
|
|
236
|
-
const neighborCoord = ivec2( nx, ny );
|
|
237
|
-
const neighborCache = textureLoad( readCacheTexNode, neighborCoord );
|
|
238
|
-
const neighborColor = neighborCache.xyz;
|
|
239
|
-
|
|
240
|
-
const neighborND = textureLoad( ndTexNode, neighborCoord );
|
|
241
|
-
const neighborNormal = neighborND.xyz.mul( 2.0 ).sub( 1.0 );
|
|
242
|
-
|
|
243
|
-
const w = normalDepthWeight(
|
|
244
|
-
centerNormal, neighborNormal,
|
|
245
|
-
centerND.w, neighborND.w,
|
|
246
|
-
phiNormal, phiDepth
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
weightedSum.addAssign( neighborColor.mul( w ) );
|
|
250
|
-
weightSum.addAssign( w );
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Blend: (1 - effective spatial) * temporal + effective spatial * spatial average
|
|
255
|
-
const spatialAverage = weightedSum.div( max( weightSum, 0.0001 ) );
|
|
256
|
-
const finalColor = mix( centerColor, spatialAverage, effectiveSpatialWeight );
|
|
257
|
-
|
|
258
|
-
// Pass through path tracer alpha to support transparentBackground mode
|
|
259
|
-
const ptAlpha = textureLoad( colorTexNode, coord ).w;
|
|
260
|
-
textureStore( outputTex, uvec2( gx, gy ), vec4( finalColor, ptAlpha ) ).toWriteOnly();
|
|
261
|
-
|
|
262
|
-
} );
|
|
263
|
-
|
|
264
|
-
} );
|
|
265
|
-
|
|
266
|
-
}
|