rayzee 4.8.11 → 4.8.13
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 +24 -0
- package/dist/rayzee.es.js +105 -79
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +3 -3
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/Passes/OIDNDenoiser.js +54 -17
- package/src/Processor/AssetLoader.js +1 -1
- package/src/TSL/BVHTraversal.js +2 -1
- package/src/TSL/LightsDirect.js +8 -4
package/package.json
CHANGED
|
@@ -383,23 +383,53 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
383
383
|
// Ensure storage buffers are sized correctly (recreate on resolution change)
|
|
384
384
|
this._ensureGPUInputBuffers( width, height );
|
|
385
385
|
|
|
386
|
-
// Copy render target textures → GPU storage buffers
|
|
387
|
-
// copyTextureToBuffer requires
|
|
388
|
-
//
|
|
386
|
+
// Copy render target textures → tightly packed GPU storage buffers for oidn-web.
|
|
387
|
+
// copyTextureToBuffer requires bytesPerRow to be a multiple of 256. When the tight
|
|
388
|
+
// row size (width * 16) isn't aligned, copy via a padded staging buffer per texture
|
|
389
|
+
// then strip padding row-by-row.
|
|
389
390
|
const encoder = device.createCommandEncoder( { label: 'oidn-tex-to-buf' } );
|
|
390
|
-
const
|
|
391
|
+
const tightRowBytes = width * 16; // rgba32float
|
|
392
|
+
const paddedRowBytes = Math.ceil( tightRowBytes / 256 ) * 256;
|
|
393
|
+
const needsPadStrip = paddedRowBytes !== tightRowBytes;
|
|
394
|
+
const stagingBufs = [];
|
|
391
395
|
|
|
392
|
-
const copyTex = ( tex,
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
396
|
+
const copyTex = ( tex, tightBuf ) => {
|
|
397
|
+
|
|
398
|
+
if ( ! needsPadStrip ) {
|
|
399
|
+
|
|
400
|
+
encoder.copyTextureToBuffer(
|
|
401
|
+
{ texture: tex, mipLevel: 0 },
|
|
402
|
+
{ buffer: tightBuf, offset: 0, bytesPerRow: tightRowBytes, rowsPerImage: height },
|
|
403
|
+
{ width, height, depthOrArrayLayers: 1 }
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
} else {
|
|
407
|
+
|
|
408
|
+
const padBuf = device.createBuffer( { size: paddedRowBytes * height, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC } );
|
|
409
|
+
stagingBufs.push( padBuf );
|
|
410
|
+
|
|
411
|
+
encoder.copyTextureToBuffer(
|
|
412
|
+
{ texture: tex, mipLevel: 0 },
|
|
413
|
+
{ buffer: padBuf, offset: 0, bytesPerRow: paddedRowBytes, rowsPerImage: height },
|
|
414
|
+
{ width, height, depthOrArrayLayers: 1 }
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
for ( let row = 0; row < height; row ++ ) {
|
|
418
|
+
|
|
419
|
+
encoder.copyBufferToBuffer( padBuf, row * paddedRowBytes, tightBuf, row * tightRowBytes, tightRowBytes );
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
};
|
|
397
426
|
|
|
398
427
|
copyTex( textures.color, this._gpuInputBuffers.color );
|
|
399
428
|
copyTex( textures.albedo, this._gpuInputBuffers.albedo );
|
|
400
429
|
copyTex( textures.normal, this._gpuInputBuffers.normal );
|
|
401
430
|
|
|
402
431
|
device.queue.submit( [ encoder.finish() ] );
|
|
432
|
+
for ( const buf of stagingBufs ) buf.destroy();
|
|
403
433
|
|
|
404
434
|
// Cache alpha channel from input color buffer when transparent background is enabled.
|
|
405
435
|
// OIDN only processes RGB — the alpha channel is lost, so we read it before denoising.
|
|
@@ -440,7 +470,7 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
440
470
|
this._destroyGPUInputBuffers();
|
|
441
471
|
|
|
442
472
|
const device = this.gpuDevice;
|
|
443
|
-
const byteSize = width * height *
|
|
473
|
+
const byteSize = width * height * 16; // rgba32float, tightly packed for oidn-web
|
|
444
474
|
const usage = GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC;
|
|
445
475
|
|
|
446
476
|
this._gpuInputBuffers.color = device.createBuffer( { label: 'oidn-in-color', size: byteSize, usage } );
|
|
@@ -466,7 +496,7 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
466
496
|
*/
|
|
467
497
|
async _cacheInputAlpha( device, width, height ) {
|
|
468
498
|
|
|
469
|
-
const byteSize = width * height *
|
|
499
|
+
const byteSize = width * height * 16; // rgba32float, tightly packed
|
|
470
500
|
const staging = device.createBuffer( {
|
|
471
501
|
label: 'oidn-alpha-staging',
|
|
472
502
|
size: byteSize,
|
|
@@ -565,9 +595,16 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
565
595
|
|
|
566
596
|
const device = this.gpuDevice;
|
|
567
597
|
const fullWidth = outputData.width;
|
|
598
|
+
const fullHeight = outputData.height;
|
|
568
599
|
const bytesPerPixel = 16; // rgba32float = 4 × float32
|
|
569
|
-
|
|
570
|
-
|
|
600
|
+
|
|
601
|
+
// Clamp tile to image bounds (edge tiles may extend past the image)
|
|
602
|
+
const clampedW = Math.min( tile.width, fullWidth - tile.x );
|
|
603
|
+
const clampedH = Math.min( tile.height, fullHeight - tile.y );
|
|
604
|
+
if ( clampedW <= 0 || clampedH <= 0 ) return;
|
|
605
|
+
|
|
606
|
+
const tileRowBytes = clampedW * bytesPerPixel;
|
|
607
|
+
const tileByteSize = clampedW * clampedH * bytesPerPixel;
|
|
571
608
|
|
|
572
609
|
const staging = device.createBuffer( {
|
|
573
610
|
size: tileByteSize,
|
|
@@ -577,7 +614,7 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
577
614
|
// Copy each tile row from its position in the full output buffer
|
|
578
615
|
const enc = device.createCommandEncoder();
|
|
579
616
|
|
|
580
|
-
for ( let row = 0; row <
|
|
617
|
+
for ( let row = 0; row < clampedH; row ++ ) {
|
|
581
618
|
|
|
582
619
|
const srcOffset = ( ( tile.y + row ) * fullWidth + tile.x ) * bytesPerPixel;
|
|
583
620
|
const dstOffset = row * tileRowBytes;
|
|
@@ -591,7 +628,7 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
591
628
|
staging.mapAsync( GPUMapMode.READ ).then( () => {
|
|
592
629
|
|
|
593
630
|
const f32 = new Float32Array( staging.getMappedRange() );
|
|
594
|
-
const tileImageData = new ImageData(
|
|
631
|
+
const tileImageData = new ImageData( clampedW, clampedH );
|
|
595
632
|
const exposure = this.getExposure();
|
|
596
633
|
const saturation = this.getSaturation();
|
|
597
634
|
const tmFn = TONE_MAP_FNS.get( this.getToneMapping() ) || TONE_MAP_FNS.get( ACESFilmicToneMapping );
|
|
@@ -617,8 +654,8 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
617
654
|
|
|
618
655
|
if ( alpha ) {
|
|
619
656
|
|
|
620
|
-
const px = ( i >> 2 ) %
|
|
621
|
-
const py = ( i >> 2 ) /
|
|
657
|
+
const px = ( i >> 2 ) % clampedW;
|
|
658
|
+
const py = ( i >> 2 ) / clampedW | 0;
|
|
622
659
|
tileImageData.data[ i + 3 ] = alpha[ ( tile.y + py ) * alphaW + tile.x + px ];
|
|
623
660
|
|
|
624
661
|
} else {
|
|
@@ -1214,7 +1214,7 @@ export class AssetLoader extends EventDispatcher {
|
|
|
1214
1214
|
|
|
1215
1215
|
const light = new RectAreaLight(
|
|
1216
1216
|
new Color( ...userData.color ),
|
|
1217
|
-
userData.intensity,
|
|
1217
|
+
userData.intensity / Math.PI, // Adjust intensity for better visual results
|
|
1218
1218
|
userData.width,
|
|
1219
1219
|
userData.height
|
|
1220
1220
|
);
|
package/src/TSL/BVHTraversal.js
CHANGED
|
@@ -391,11 +391,12 @@ export const traverseBVHShadow = Fn( ( [
|
|
|
391
391
|
bvhBuffer,
|
|
392
392
|
triangleBuffer,
|
|
393
393
|
materialBuffer,
|
|
394
|
+
maxShadowDist,
|
|
394
395
|
] ) => {
|
|
395
396
|
|
|
396
397
|
const closestHit = HitInfo( {
|
|
397
398
|
didHit: false,
|
|
398
|
-
dst:
|
|
399
|
+
dst: maxShadowDist,
|
|
399
400
|
hitPoint: vec3( 0.0 ),
|
|
400
401
|
normal: vec3( 0.0 ),
|
|
401
402
|
uv: vec2( 0.0 ),
|
package/src/TSL/LightsDirect.js
CHANGED
|
@@ -79,6 +79,7 @@ export const traceShadowRay = Fn( ( [
|
|
|
79
79
|
|
|
80
80
|
const transmittance = float( 1.0 ).toVar();
|
|
81
81
|
const rayOrigin = origin.toVar();
|
|
82
|
+
const remainingDist = float( maxDist ).toVar();
|
|
82
83
|
|
|
83
84
|
const MAX_SHADOW_TRANSMISSIONS = 8;
|
|
84
85
|
|
|
@@ -91,10 +92,11 @@ export const traceShadowRay = Fn( ( [
|
|
|
91
92
|
bvhBuffer,
|
|
92
93
|
triangleBuffer,
|
|
93
94
|
materialBuffer,
|
|
95
|
+
remainingDist,
|
|
94
96
|
) );
|
|
95
97
|
|
|
96
|
-
// No hit
|
|
97
|
-
If( shadowHit.didHit.not()
|
|
98
|
+
// No hit within remaining distance to light
|
|
99
|
+
If( shadowHit.didHit.not(), () => {
|
|
98
100
|
|
|
99
101
|
Break();
|
|
100
102
|
|
|
@@ -139,8 +141,9 @@ export const traceShadowRay = Fn( ( [
|
|
|
139
141
|
|
|
140
142
|
} );
|
|
141
143
|
|
|
142
|
-
// Continue ray
|
|
144
|
+
// Continue ray past transmissive surface
|
|
143
145
|
rayOrigin.assign( shadowHit.hitPoint.add( dir.mul( 0.001 ) ) );
|
|
146
|
+
remainingDist.subAssign( shadowHit.dst.add( 0.001 ) );
|
|
144
147
|
|
|
145
148
|
} ).ElseIf( shadowMaterial.transparent, () => {
|
|
146
149
|
|
|
@@ -154,8 +157,9 @@ export const traceShadowRay = Fn( ( [
|
|
|
154
157
|
|
|
155
158
|
} );
|
|
156
159
|
|
|
157
|
-
// Continue ray
|
|
160
|
+
// Continue ray past transparent surface
|
|
158
161
|
rayOrigin.assign( shadowHit.hitPoint.add( dir.mul( 0.001 ) ) );
|
|
162
|
+
remainingDist.subAssign( shadowHit.dst.add( 0.001 ) );
|
|
159
163
|
|
|
160
164
|
} ).Else( () => {
|
|
161
165
|
|