-
-
Notifications
You must be signed in to change notification settings - Fork 163
Expand file tree
/
Copy pathProcessHitsKernel.js
More file actions
121 lines (86 loc) · 4.32 KB
/
ProcessHitsKernel.js
File metadata and controls
121 lines (86 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { IndirectStorageBufferAttribute, StorageTexture, DataTexture } from 'three/webgpu';
import { ComputeKernel } from '../ComputeKernel.js';
import { uniform, storage, textureStore, globalId, texture, sampler } from 'three/tsl';
import { getSurfaceRecordFunc } from '../../nodes/material.wgsl.js';
import { queuedRayStruct, queuedHitStruct } from './structs.js';
import { proxy, proxyFn } from '../../lib/nodes/NodeProxy.js';
import { weightedAlphaBlendFn } from '../../nodes/sampling.wgsl.js';
import { wgslTagFn } from '../../lib/nodes/WGSLTagFnNode.js';
export class ProcessHitsKernel extends ComputeKernel {
constructor( material ) {
const params = {
bvhData: { value: null },
prevOutputTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadOnly(),
outputTarget: textureStore( new StorageTexture( 1, 1 ) ).toWriteOnly(),
sampleCountTarget: textureStore( new StorageTexture( 1, 1 ) ).toReadWrite(),
// settings
smoothNormals: uniform( 1 ),
bounces: uniform( 1 ),
// rays
rayQueue: storage( new IndirectStorageBufferAttribute( 1, queuedRayStruct.getLength() ), queuedRayStruct ),
hitQueue: storage( new IndirectStorageBufferAttribute( 1, queuedHitStruct.getLength() ), queuedHitStruct ),
queueSizes: storage( new IndirectStorageBufferAttribute( 4, 1 ), 'u32' ).toAtomic(),
textures: texture( new DataTexture( ) ),
textureSampler: sampler( new DataTexture( ) ),
globalId: globalId,
};
const sampleTrianglePointFn = proxyFn( 'bvhData.value.fns.sampleTrianglePoint', params );
const fn = wgslTagFn/* wgsl */`
fn compute(
// settings
smoothNormals: u32,
bounces: u32,
textures: texture_2d_array<f32>,
textureSampler: sampler,
globalId: vec3u
) -> void {
let rayQueue = &${ params.rayQueue };
let hitQueue = &${ params.hitQueue };
let queueSizes = &${ params.queueSizes };
let materials = &${ proxy( 'bvhData.value.storage.materials', params ) };
let transforms = &${ proxy( 'bvhData.value.storage.transforms', params ) };
// skip any rays invocations beyond the ray count
let hitQueueCapacity = arrayLength( hitQueue );
let hitIndex = ( globalId.x + atomicLoad( &queueSizes[ 2 ] ) );
if ( hitIndex >= atomicLoad( &queueSizes[ 3 ] ) ) {
return;
}
// get the ray info
let ACTIVE_FLAG = 0xF0000000u;
let input = hitQueue[ hitIndex ];
let indexUV = vec2u( input.pixel_x, input.pixel_y );
g_state.s0 = input.pcgStateS0;
let object = transforms[ input.objectIndex ];
var material = materials[ object.materialIndex ];
// apply per-object colors
material.color *= object.color.rgb;
material.opacity *= object.color.a;
var vertexData = ${ sampleTrianglePointFn }( input.barycoord, input.indices.xyz );
vertexData.normal = normalize( transpose( object.inverseMatrixWorld ) * vertexData.normal );
vertexData.position = object.matrixWorld * vertexData.position;
let surface = ${ getSurfaceRecordFunc }( material, vertexData, input.side, input.normal, textures, textureSampler );
let scatterRec = ${ material.getBsdfNode() }( input.view, surface );
if ( input.currentBounce >= bounces ) {
// terminate ray, write color
let sampleCount = ( textureLoad( ${ params.sampleCountTarget }, indexUV ).r & ( ~ ACTIVE_FLAG ) ) + 1;
let prevColor = textureLoad( ${ params.prevOutputTarget }, indexUV );
let blendedColor = ${ weightedAlphaBlendFn }( prevColor, input.resultColor, 1.0 / f32( sampleCount ) );
textureStore( ${ params.sampleCountTarget }, indexUV, vec4( sampleCount ) );
textureStore( ${ params.outputTarget }, indexUV, blendedColor );
} else {
let rayQueueCapacity = arrayLength( rayQueue );
let index = atomicAdd( &queueSizes[ 1 ], 1 ) % rayQueueCapacity;
let resultColor = input.resultColor + vec4f( input.throughputColor * surface.emission, 0.0 );
rayQueue[ index ].origin = vertexData.position.xyz;
rayQueue[ index ].direction = scatterRec.direction;
rayQueue[ index ].pixel = indexUV;
rayQueue[ index ].throughputColor = input.throughputColor * scatterRec.color / scatterRec.pdf;
rayQueue[ index ].currentBounce = input.currentBounce + 1;
rayQueue[ index ].pcgStateS0 = g_state.s0;
rayQueue[ index ].resultColor = resultColor;
}
}`;
super( fn( params ) );
this.defineUniformAccessors( params );
}
}