@@ -21,14 +21,11 @@ import {
2121
2222import { store } from 'src/lib/store.ts' ;
2323import type { GBuffer } from '../../gBuffer.ts' ;
24- import { ONES_3F } from '../wgslUtils/mathConstants.ts' ;
2524import { Material , skyColor , worldMat , worldSdf } from './worldSdf.ts' ;
2625
2726const BlockSize = 8 ;
2827
2928// parameters
30- const OutputFormat = tgpu [ '~unstable' ] . slot ( ) . $name ( 'output_format' ) ;
31-
3229const SUPER_SAMPLES = 4 ;
3330const ONE_OVER_SUPER_SAMPLES = 1 / SUPER_SAMPLES ;
3431const SUB_SAMPLES = 16 ;
@@ -42,6 +39,8 @@ const Reflection = d.struct({
4239 roughness : d . f32 ,
4340} ) ;
4441
42+ const ReflectionArray = d . arrayOf ( Reflection , MAX_REFL ) ;
43+
4544export const accumulatedLayersAtom = atom ( 0 ) ;
4645
4746/**
@@ -50,140 +49,123 @@ export const accumulatedLayersAtom = atom(0);
5049 * @param normal
5150 * @param mat_roughness
5251 */
53- const reflect = tgpu [ '~unstable' ]
54- . fn (
55- [ d . vec3f , d . vec3f , d . f32 , d . ptrFn ( d . f32 ) ] ,
56- d . vec3f ,
57- ) (
58- `(rayDir, normal, matRoughness, outRoughness) {
59- let slope = dot(rayDir, normal);
60- let dn2 = 2. * slope;
61- let refl_dir = rayDir - dn2 * normal;
62-
63- let fresnel = 1. - pow(1. + slope, 16.);
64- let roughness = matRoughness * fresnel;
65- *outRoughness = roughness;
66-
67- var new_ray_dir = randf.onHemisphere(normal);
68- new_ray_dir = mix(refl_dir, new_ray_dir, roughness);
69- return normalize(new_ray_dir);
70- }` ,
71- )
72- . $uses ( { randf } )
73- . $name ( 'reflect' ) ;
74-
75- const renderSubPixel = tgpu [ '~unstable' ]
76- . fn (
77- [ d . vec2f ] ,
78- d . vec3f ,
79- ) (
80- /* wgsl */ `(coord: vec2f) -> vec3f {
81- // doing the first march before each sub-sample, since the first march result is the same for all of them
82-
83- var init_shape_ctx: ShapeContext;
84- init_shape_ctx.rayPos = constructRayPos();
85- init_shape_ctx.rayDir = constructRayDir(coord);
86- init_shape_ctx.rayDistance = 0.;
87- var init_march_result: MarchResult;
88-
89- march(&init_shape_ctx, MAX_STEPS, &init_march_result);
90-
91- if (init_march_result.steps >= MAX_STEPS) {
92- return min(skyColor(init_shape_ctx.rayDir), ONES_3F);
93- }
52+ const reflect = tgpu . fn (
53+ [ d . vec3f , d . vec3f , d . f32 , d . ptrFn ( d . f32 ) ] ,
54+ d . vec3f ,
55+ ) ( ( rayDir , normal , matRoughness , outRoughness ) => {
56+ const slope = std . dot ( rayDir , normal ) ;
57+ const refl_dir = rayDir . sub ( normal . mul ( 2 * slope ) ) ;
58+
59+ const fresnel = 1 - std . pow ( 1 + slope , 16 ) ;
60+ const roughness = matRoughness * fresnel ;
61+ // TODO: Fix when boxed values are introduced
62+ // biome-ignore lint/style/noParameterAssign: Has to be done like this for now
63+ outRoughness = roughness ;
64+
65+ let new_ray_dir = randf . onHemisphere ( normal ) ;
66+ new_ray_dir = std . mix ( refl_dir , new_ray_dir , roughness ) ;
67+ return std . normalize ( new_ray_dir ) ;
68+ } ) ;
9469
95- let init_normal = estimateNormal(init_march_result.position, init_shape_ctx);
70+ const renderSubPixel = tgpu . fn (
71+ [ d . vec2f ] ,
72+ d . vec3f ,
73+ ) ( ( coord ) => {
74+ // doing the first march before each sub-sample, since the first march result is the same for all of them
9675
97- var init_material: Material;
98- worldMat(init_march_result.position, init_shape_ctx, &init_material);
76+ const init_shape_ctx = ShapeContext ( {
77+ rayPos : constructRayPos ( ) ,
78+ rayDir : constructRayDir ( coord ) ,
79+ rayDistance : 0 ,
80+ } ) ;
81+ const init_march_result = MarchResult ( ) ;
9982
100- if (init_material.emissive) {
101- return min(init_material.albedo, ONES_3F);
102- }
83+ march ( init_shape_ctx , MarchParams . maxSteps . $ , init_march_result ) ;
10384
104- var reflections: array<Reflection, MAX_REFL>;
85+ if ( init_march_result . steps >= MarchParams . maxSteps . $ ) {
86+ return std . min ( skyColor ( init_shape_ctx . rayDir ) , d . vec3f ( 1 ) ) ;
87+ }
10588
106- var acc = vec3f(0., 0., 0.);
107- for (var sub = 0u; sub < SUB_SAMPLES; sub++) {
108- var material: Material = init_material;
109- var normal = init_normal;
89+ const init_normal = estimateNormal (
90+ init_march_result . position ,
91+ init_shape_ctx ,
92+ ) ;
93+ const init_material = Material ( ) ;
11094
111- var emissive_color = vec3f(0., 0., 0.);
112- var refl_count = 0u;
95+ worldMat ( init_march_result . position , init_shape_ctx , init_material ) ;
11396
114- var shape_ctx: ShapeContext;
115- shape_ctx.rayPos = init_march_result.position;
116- shape_ctx.rayDir = init_shape_ctx.rayDir;
117- shape_ctx.rayDistance = init_shape_ctx.rayDistance;
97+ if ( init_material . emissive ) {
98+ return std . min ( init_material . albedo , d . vec3f ( 1 ) ) ;
99+ }
118100
119- for (var refl = 0u; refl < MAX_REFL; refl++) {
120- var roughness: f32 = 0.;
121- shape_ctx.rayDir = reflect(
122- shape_ctx.rayDir,
123- normal,
124- material.roughness,
125- &roughness,
126- );
127- reflections[refl_count].color = material.albedo;
128- reflections[refl_count].roughness = roughness;
129- refl_count++;
101+ const reflections = ReflectionArray ( ) ;
102+
103+ let acc = d . vec3f ( ) ;
104+ for ( let sub = d . u32 ( 0 ) ; sub < SUB_SAMPLES ; sub ++ ) {
105+ const material = Material ( init_material ) ;
106+
107+ let normal = d . vec3f ( init_normal ) ;
108+ let emissive_color = d . vec3f ( ) ;
109+ let refl_count = d . u32 ( 0 ) ;
110+
111+ const shape_ctx = ShapeContext ( {
112+ rayPos : init_march_result . position ,
113+ rayDir : init_shape_ctx . rayDir ,
114+ rayDistance : init_shape_ctx . rayDistance ,
115+ } ) ;
116+
117+ for ( let refl = d . u32 ( 0 ) ; refl < MAX_REFL ; refl ++ ) {
118+ const roughness = d . f32 ( 0 ) ;
119+ shape_ctx . rayDir = reflect (
120+ shape_ctx . rayDir ,
121+ normal ,
122+ material . roughness ,
123+ roughness ,
124+ ) ;
125+ reflections [ refl_count ] . color = material . albedo ;
126+ reflections [ refl_count ] . roughness = roughness ;
127+ refl_count ++ ;
130128
131- var march_result: MarchResult;
132- march(& shape_ctx, MAX_STEPS, & march_result);
133- shape_ctx.rayPos = march_result.position;
129+ const march_result = MarchResult ( ) ;
130+ march ( shape_ctx , MarchParams . maxSteps . $ , march_result ) ;
131+ shape_ctx . rayPos = march_result . position ;
134132
135- if (march_result.steps >= MAX_STEPS ) {
136- emissive_color = skyColor(shape_ctx.rayDir);
137- break;
138- }
133+ if ( march_result . steps >= MarchParams . maxSteps . $ ) {
134+ emissive_color = skyColor ( shape_ctx . rayDir ) ;
135+ break ;
136+ }
139137
140- normal = estimateNormal(shape_ctx.rayPos, shape_ctx);
138+ normal = estimateNormal ( shape_ctx . rayPos , shape_ctx ) ;
141139
142- worldMat(shape_ctx.rayPos, shape_ctx, & material);
140+ worldMat ( shape_ctx . rayPos , shape_ctx , material ) ;
143141
144- if (material.emissive) {
145- emissive_color = material.albedo;
146- break;
147- }
142+ if ( material . emissive ) {
143+ emissive_color = material . albedo ;
144+ break ;
148145 }
146+ }
149147
150- var sub_acc = emissive_color;
151- for (var i = i32(refl_count) - 1; i >= 0; i--) {
152- let mat_color = reflections[i].color;
153- let reflectivity = 1. - reflections[i].roughness;
154-
155- sub_acc *= mix(mat_color, ONES_3F, max(0., min(reflectivity, 1.))); // absorb the ray color based on reflectivity
156- }
148+ let sub_acc = d . vec3f ( emissive_color ) ;
149+ for ( let i = d . i32 ( refl_count ) - 1 ; i >= 0 ; i -- ) {
150+ const mat_color = d . vec3f ( reflections [ i ] . color ) ;
151+ const reflectivity = 1 - reflections [ i ] . roughness ;
157152
158- acc += sub_acc;
153+ sub_acc = sub_acc . mul (
154+ std . mix ( mat_color , d . vec3f ( 1 ) , std . max ( 0 , std . min ( reflectivity , 1 ) ) ) ,
155+ ) ; // absorb the ray color based on reflectivity
159156 }
160157
161- // averaging
162- acc /= f32(SUB_SAMPLES);
158+ acc = acc . add ( sub_acc ) ;
159+ }
163160
164- // clipping
165- acc = min( acc, ONES_3F );
161+ // averaging
162+ acc = acc . div ( SUB_SAMPLES ) ;
166163
167- return acc;
168- }` ,
169- )
170- . $uses ( {
171- SUB_SAMPLES ,
172- MAX_STEPS : MarchParams . maxSteps ,
173- MAX_REFL ,
174- ONES_3F ,
175- MarchResult,
176- Material,
177- Reflection,
178- ShapeContext,
179- constructRayPos,
180- constructRayDir,
181- estimateNormal,
182- march,
183- skyColor,
184- worldMat,
185- reflect,
186- } ) ;
164+ // clipping
165+ acc = std . min ( acc , d . vec3f ( 1 ) ) ;
166+
167+ return acc ;
168+ } ) ;
187169
188170const mainLayout = tgpu . bindGroupLayout ( {
189171 previousRender : { texture : 'unfilterable-float' } ,
@@ -194,14 +176,12 @@ const mainComputeFn = tgpu['~unstable'].computeFn({
194176 workgroupSize : [ BlockSize , BlockSize ] ,
195177 in : { gid : d . builtin . globalInvocationId } ,
196178} ) ( ( input ) => {
179+ const preSeed = d . vec2f ( input . gid . xy ) ;
197180 randf . seed2 (
198- std . add (
199- std . mul ( d . vec2f ( input . gid . xy ) , 0.1646936793 ) ,
200- std . mul ( getRandomSeedPrimer . value , 0.934534732 ) ,
201- ) ,
181+ preSeed . mul ( 0.1646936793 ) . add ( getRandomSeedPrimer . $ * 0.934534732 ) ,
202182 ) ;
203183
204- const prev_layers = getAccumulatedLayers . value ;
184+ const prev_layers = getAccumulatedLayers . $ ;
205185 const prev_render = std . textureLoad (
206186 mainLayout . $ . previousRender ,
207187 input . gid . xy ,
@@ -211,30 +191,24 @@ const mainComputeFn = tgpu['~unstable'].computeFn({
211191 let acc = d . vec3f ( 0 , 0 , 0 ) ;
212192 for ( let sx = d . u32 ( 0 ) ; sx < SUPER_SAMPLES ; sx ++ ) {
213193 for ( let sy = d . u32 ( 0 ) ; sy < SUPER_SAMPLES ; sy ++ ) {
214- const offset = d . vec2f (
215- ( d . f32 ( sx ) + 0.5 ) * ONE_OVER_SUPER_SAMPLES ,
216- ( d . f32 ( sy ) + 0.5 ) * ONE_OVER_SUPER_SAMPLES ,
217- ) ;
194+ const offset = d . vec2f ( sx , sy ) . add ( 0.5 ) . mul ( ONE_OVER_SUPER_SAMPLES ) ;
218195
219- acc = std . add (
220- acc ,
221- renderSubPixel ( std . add ( d . vec2f ( input . gid . xy ) , offset ) ) ,
222- ) ;
196+ acc = acc . add ( renderSubPixel ( d . vec2f ( input . gid . xy ) . add ( offset ) ) ) ;
223197 }
224198 }
225199
226- acc = std . mul ( acc , ONE_OVER_SUPER_SAMPLES * ONE_OVER_SUPER_SAMPLES ) ;
200+ acc = acc . mul ( ONE_OVER_SUPER_SAMPLES * ONE_OVER_SUPER_SAMPLES ) ;
227201
228202 // applying gamma correction
229203 const gamma = 2.2 ;
230- acc = std . pow ( acc , d . vec3f ( d . f32 ( 1 ) / gamma ) ) ;
204+ acc = std . pow ( acc , d . vec3f ( 1 / gamma ) ) ;
231205
232- let new_render = d . vec4f ( acc , 1.0 ) ;
206+ let new_render = d . vec4f ( acc , 1 ) ;
233207 if ( prev_layers > 0 ) {
234- new_render = std . div (
235- std . add ( std . mul ( prev_render , prev_layers ) , d . vec4f ( acc , 1.0 ) ) ,
236- prev_layers + 1 ,
237- ) ;
208+ new_render = prev_render
209+ . mul ( prev_layers )
210+ . add ( d . vec4f ( acc , 1.0 ) )
211+ . div ( prev_layers + 1 ) ;
238212 }
239213
240214 std . textureStore ( mainLayout . $ . mainOutput , input . gid . xy , new_render ) ;
@@ -342,7 +316,6 @@ export function createSDFRenderer(options: SDFRendererOptions) {
342316
343317 const mainPipeline = root [ '~unstable' ]
344318 // filling slots
345- . with ( OutputFormat , 'rgba8unorm' )
346319 . with ( getRandomSeedPrimer , randomSeedPrimerBuffer . as ( 'uniform' ) )
347320 . with ( getAccumulatedLayers , layersBuffer . as ( 'uniform' ) )
348321 . with ( getCameraProps , camera . cameraBuffer . as ( 'uniform' ) )
@@ -355,7 +328,6 @@ export function createSDFRenderer(options: SDFRendererOptions) {
355328
356329 const auxPipeline = root [ '~unstable' ]
357330 // filling slots
358- . with ( OutputFormat , 'rgba16float' )
359331 . with ( getCameraProps , camera . cameraBuffer . as ( 'uniform' ) )
360332 . with ( accessViewportSize , d . vec2f ( auxPassSize [ 0 ] , auxPassSize [ 1 ] ) )
361333 . with ( MarchParams . sampleSdf , worldSdf )
0 commit comments