11struct Params {
2+ camera_pos : vec3f ,
3+ _pad1 : u32 ,
24 width : u32 ,
35 height : u32 ,
46 iTime : f32 ,
7+ _pad2 : u32 ,
8+ };
9+
10+ struct Material {
11+ diffuse_color : vec3f ,
12+ _pad : f32 ,
13+ emission_color : vec3f ,
14+ emission_strength : f32 ,
15+ };
16+
17+ struct Sphere {
18+ center : vec3f ,
19+ radius : f32 ,
20+ material : Material ,
521};
622
723@group (0 ) @binding (0 ) var <uniform > params : Params ;
824@group (0 ) @binding (1 ) var outputTex : texture_storage_2d <rgba8unorm , write >;
25+ @group (0 ) @binding (2 ) var <storage , read > spheres : array <Sphere >;
26+
27+ const PI : f32 = 3 .141592 ;
28+
29+ const MAX_BOUNCES : u32 = 5u ;
930
1031struct Ray {
1132 origin : vec3f ,
@@ -16,46 +37,133 @@ struct RayHit {
1637 distance : f32 ,
1738 position : vec3f ,
1839 normal : vec3f ,
40+ material : Material ,
1941 hit : bool ,
2042};
2143
22- fn sphere_intersect (ray : Ray , center : vec3f , radius : f32 ) -> RayHit {
23- let oc = ray . origin - center ;
44+ fn hash (seed : vec2f ) -> u32 {
45+ var h = u32 (seed . x * 73856093 .0 ) ^ u32 (seed . y * 19349663 .0 );
46+ h = (h ^ (h >> 16u )) * 0x45d9f3bu ;
47+ h = (h ^ (h >> 16u )) * 0x45d9f3bu ;
48+ h = h ^ (h >> 16u );
49+ return h ;
50+ }
51+
52+ fn next_random (state : ptr <function , u32 >) -> u32 {
53+ (*state ) = (*state ) * 1664525u + 1013904223u ;
54+ let result = ((*state >> ((*state >> 28u ) + 4u )) ^ *state ) * 277803737u ;
55+ return (result >> 22u ) ^ result ;
56+ }
57+
58+ fn random_value (state : ptr <function , u32 >) -> f32 {
59+ return f32 (next_random (state )) / 4294967295 .0 ;
60+ }
61+
62+ fn random_normal_distribution (state : ptr <function , u32 >) -> f32 {
63+ let theta = 2 .0 * PI * random_value (state );
64+ let rho = sqrt (- 2 .0 * log (random_value (state )));
65+ return rho * cos (theta );
66+ }
67+
68+ fn random_direction (state : ptr <function , u32 >) -> vec3f {
69+ let x = random_normal_distribution (state );
70+ let y = random_normal_distribution (state );
71+ let z = random_normal_distribution (state );
72+ return normalize (vec3f (x , y , z ));
73+ }
74+
75+ fn random_hemisphere_dir (normal : vec3f , state : ptr <function , u32 >) -> vec3f {
76+ let dir = random_direction (state );
77+ if dot (dir , normal ) < 0 .0 {
78+ return - dir ;
79+ } else {
80+ return dir ;
81+ }
82+ }
83+
84+ fn trace (ray : ptr <function , Ray >, state : ptr <function , u32 >) -> vec3f {
85+ var light = vec3f (0 .0 , 0 .0 , 0 .0 );
86+ var color = vec3f (1 .0 , 1 .0 , 1 .0 );
87+
88+ for (var bounce : u32 = 0u ; bounce < MAX_BOUNCES ; bounce = bounce + 1u ) {
89+ let hit = calculate_collision (*ray );
90+ if hit . hit {
91+ (*ray ). origin = hit . position + hit . normal * 0 .001 ;
92+ (*ray ). direction = random_hemisphere_dir (hit . normal , state );
93+
94+ let emitted = hit . material . emission_color * hit . material . emission_strength ;
95+ light = light + color * emitted ;
96+ color = color * hit . material . diffuse_color ;
97+ } else {
98+ break ;
99+ }
100+ }
101+
102+ return light ;
103+ }
104+
105+ fn calculate_collision (ray : Ray ) -> RayHit {
106+ var closest_hit = RayHit (
107+ 0 .0 ,
108+ vec3f (0 .0 ),
109+ vec3f (0 .0 ),
110+ Material (vec3f (0 .0 ), 0 .0 , vec3f (0 .0 ), 0 .0 ),
111+ false
112+ );
113+ for (var i : u32 = 0u ; i < params . _pad2 ; i = i + 1u ) {
114+ let hit = sphere_intersect (ray , spheres [i ]);
115+ if hit . hit && (! closest_hit . hit || hit . distance < closest_hit . distance ) {
116+ closest_hit = hit ;
117+ }
118+ }
119+ return closest_hit ;
120+ }
121+
122+ fn sphere_intersect (ray : Ray , sphere : Sphere ) -> RayHit {
123+ var hit = RayHit (
124+ 0 .0 ,
125+ vec3f (0 .0 ),
126+ vec3f (0 .0 ),
127+ Material (vec3f (0 .0 ), 0 .0 , vec3f (0 .0 ), 0 .0 ),
128+ false
129+ );
130+ let oc = ray . origin - sphere . center ;
24131 let a = dot (ray . direction , ray . direction );
25132 let b = 2 .0 * dot (oc , ray . direction );
26- let c = dot (oc , oc ) - radius * radius ;
133+ let c = dot (oc , oc ) - sphere . radius * sphere . radius ;
27134 let discriminant = b * b - 4 .0 * a * c ;
28135 if discriminant < 0 .0 {
29- return RayHit ( 0 .0 , vec3f ( 0 .0 ), vec3f ( 0 .0 ), false ) ;
136+ return hit ;
30137 } else {
31138 let t = (- b - sqrt (discriminant )) / (2 .0 * a );
32139 if t > 0 .0 {
33- let position = ray . origin + t * ray . direction ;
34- let normal = normalize (position - center );
35- return RayHit (t , position , normal , true );
140+ hit . distance = t ;
141+ hit . material = sphere . material ;
142+ hit . position = ray . origin + t * ray . direction ;
143+ hit . normal = normalize (hit . position - sphere . center );
144+ hit . hit = true ;
145+ return hit ;
36146 } else {
37- return RayHit ( 0 .0 , vec3f ( 0 .0 ), vec3f ( 0 .0 ), false ) ;
147+ return hit ;
38148 }
39149 }
40150}
41151
42- const PI : f32 = 3 .14159265 ;
43-
44152@compute @workgroup_size (16 , 16 )
45153fn main (@builtin (global_invocation_id ) global_ix : vec3 <u32 >) {
46- let fragCoord = vec2f (global_ix . xy ) / vec2f (f32 (params . width ), f32 (params . height )) - vec2f ( 0 .5 , 0 .5 ) ;
154+ let fragCoord = vec2f (global_ix . xy ) / vec2f (f32 (params . width ), f32 (params . height )) ;
47155
48- let camera_pos = vec3f (0 .0 , 0 .0 , 5 .0 );
49156 let aspect_ratio = f32 (params . width ) / f32 (params . height );
50- let fov = 60 .0 * PI / 180 .0 ;
51- let px = (2 .0 * ( fragCoord . x + 0 .5 ) - 1 .0 ) * tan ( fov / 2 .0 ) * aspect_ratio ;
52- let py = (1 .0 - 2 .0 * ( fragCoord . y + 0 .5 )) * tan ( fov / 2 .0 ) ;
157+ let half_fov_tan = tan ( radians ( 60 .0 ) * 0 .5 ) ;
158+ let px = (2 .0 * fragCoord . x - 1 .0 ) * half_fov_tan * aspect_ratio ;
159+ let py = (1 .0 - 2 .0 * fragCoord . y ) * half_fov_tan ;
53160 let ray_dir = normalize (vec3f (px , py , - 1 .0 ));
54- let ray = Ray (camera_pos , ray_dir );
161+ var ray = Ray (params . camera_pos , ray_dir );
162+
163+ var state = hash (fragCoord . xy + params . iTime );
55164
56- let hit = f32 (u32 (sphere_intersect (ray , vec3f (0 .0 ), 1 .0 ). hit ));
57165
58- let fragColor = vec4f (hit , hit , hit , 1 .0 );
166+ let fragColor = vec4f (trace ( & ray , & state ) , 1 .0 );
59167
60168 textureStore (outputTex , vec2i (global_ix . xy ), fragColor );
61169}
0 commit comments