@@ -12,15 +12,15 @@ struct Params {
1212 accumulated_frames : u32 ,
1313 width : u32 ,
1414 height : u32 ,
15- triangle_mesh_count : u32 ,
16- sphere_count : u32 ,
1715};
1816
1917struct Material {
2018 diffuse_color : vec3f ,
2119 smoothness : f32 ,
2220 emission_color : vec3f ,
2321 emission_strength : f32 ,
22+ refractive_index : f32 ,
23+ flag : u32 ,
2424};
2525
2626struct Sphere {
@@ -51,6 +51,7 @@ struct RayHit {
5151 distance : f32 ,
5252 position : vec3f ,
5353 normal : vec3f ,
54+ is_backface : bool ,
5455 material : Material ,
5556 hit : bool ,
5657};
@@ -136,9 +137,17 @@ fn trace_single(ray: ptr<function, Ray>, state: ptr<function, u32>) -> vec3f {
136137 if hit . hit {
137138 (*ray ). origin = hit . position ;
138139 let diffuse = normalize (hit . normal + random_direction (state ));
139- let specular = reflect ((*ray ). direction , hit . normal );
140-
141- (*ray ). direction = mix (diffuse , specular , hit . material . smoothness );
140+ let specular = reflect ((*ray ). direction , hit . normal , 0 .0 );
141+
142+ if hit . material . flag == 1u {
143+ if hit . is_backface {
144+ let refracted = refract ((*ray ). direction , hit . normal , hit . material . refractive_index );
145+ let kr = pow (1 .0 - max (dot (- (*ray ). direction , hit . normal ), 0 .0 ), 5 .0 );
146+ (*ray ). direction = normalize (mix (refracted , specular , kr ));
147+ }
148+ } else {
149+ (*ray ). direction = mix (diffuse , specular , hit . material . smoothness );
150+ }
142151
143152 let emitted = hit . material . emission_color * hit . material . emission_strength ;
144153 color = color * hit . material . diffuse_color ;
@@ -152,28 +161,46 @@ fn trace_single(ray: ptr<function, Ray>, state: ptr<function, u32>) -> vec3f {
152161 return light ;
153162}
154163
155- fn reflect (I : vec3f , N : vec3f ) -> vec3f {
164+ fn reflect (I : vec3f , N : vec3f , index : f32 ) -> vec3f {
156165 return I - 2 .0 * dot (N , I ) * N ;
157166}
158167
168+ fn refract (I : vec3f , N : vec3f , index : f32 ) -> vec3f {
169+ var cosi = clamp (dot (I , N ), - 1 .0 , 1 .0 );
170+ let etai = 1 .0 ;
171+ let etat = index ;
172+ var n = N ;
173+ var eta = etai / etat ;
174+ if cosi < 0 .0 {
175+ cosi = - cosi ;
176+ } else {
177+ n = - N ;
178+ }
179+ let k = 1 .0 - eta * eta * (1 .0 - cosi * cosi );
180+ if k < 0 .0 {
181+ return vec3f (0 .0 , 0 .0 , 0 .0 );
182+ } else {
183+ return eta * I + (eta * cosi - sqrt (k )) * n ;
184+ }
185+ }
186+
159187fn calculate_collision (ray : Ray ) -> RayHit {
160188 var closest_hit : RayHit ;
161- for (var i : u32 = 0u ; i < params . sphere_count ; i = i + 1u ) {
189+ for (var i : u32 = 0u ; i < arrayLength ( & spheres ) ; i = i + 1u ) {
162190 let hit = sphere_intersect (ray , spheres [i ]);
163191 if hit . hit && (! closest_hit . hit || hit . distance < closest_hit . distance ) {
164192 closest_hit = hit ;
165193 }
166194 }
167- for (var i : u32 = 0u ; i < params . triangle_mesh_count ; i = i + 1u ) {
195+ for (var i : u32 = 0u ; i < arrayLength ( & triangle_meshes ) ; i = i + 1u ) {
168196 let tri_mesh = triangle_meshes [i ];
169- if ! aabb_intersect (ray , tri_mesh . aabb ) {
170- continue ;
171- }
172- for (var j : u32 = 0u ; j < tri_mesh . vertex_count / 3u ; j = j + 1u ) {
173- let hit = triangle_intersect (ray , tri_mesh . start_index + j * 3u );
174- if hit . hit && (! closest_hit . hit || hit . distance < closest_hit . distance ) {
175- closest_hit = hit ;
176- closest_hit . material = tri_mesh . material ;
197+ if aabb_intersect (ray , tri_mesh . aabb ) {
198+ for (var j : u32 = 0u ; j < tri_mesh . vertex_count / 3u ; j = j + 1u ) {
199+ let hit = triangle_intersect (ray , tri_mesh . start_index + j * 3u , tri_mesh . material . flag == 0u );
200+ if hit . hit && (! closest_hit . hit || hit . distance < closest_hit . distance ) {
201+ closest_hit = hit ;
202+ closest_hit . material = tri_mesh . material ;
203+ }
177204 }
178205 }
179206 }
@@ -198,25 +225,22 @@ fn sphere_intersect(ray: Ray, sphere: Sphere) -> RayHit {
198225 let b = 2 .0 * dot (oc , ray . direction );
199226 let c = dot (oc , oc ) - sphere . radius * sphere . radius ;
200227 let discriminant = b * b - 4 .0 * a * c ;
201- if discriminant < 0 .0 {
202- return hit ;
203- } else {
228+ if discriminant >= 0 .0 {
204229 let t = (- b - sqrt (discriminant )) / (2 .0 * a );
205- if t > 0 .0 {
230+ if t > 1e-5 {
206231 hit . distance = t ;
207232 hit . material = sphere . material ;
208233 hit . position = ray . origin + t * ray . direction ;
209234 hit . normal = normalize (hit . position - sphere . position );
235+ hit . is_backface = dot (ray . direction , hit . normal ) < 0 .0 ;
210236 hit . hit = true ;
211- return hit ;
212- } else {
213- return hit ;
214237 }
215238 }
239+ return hit ;
216240}
217241
218242// moller-trumbore algorithm
219- fn triangle_intersect (ray : Ray , v0_idx : u32 ) -> RayHit {
243+ fn triangle_intersect (ray : Ray , v0_idx : u32 , detect_backface : bool ) -> RayHit {
220244 var hit : RayHit ;
221245 let v0 = triangle_vertices [v0_idx ]. xyz ;
222246 let v1 = triangle_vertices [v0_idx + 1u ]. xyz ;
@@ -246,15 +270,24 @@ fn triangle_intersect(ray: Ray, v0_idx: u32) -> RayHit {
246270 return hit ;
247271 }
248272
273+ let w = 1 .0 - u - v ;
274+
249275 let t = f * dot (edge2 , q );
250276
251- if t > 0 .0001 {
252- hit . distance = t ;
253- hit . position = ray . origin + t * ray . direction ;
254- hit . normal = normalize (cross (edge1 , edge2 ));
255- hit . hit = true ;
277+ let tri_face_vector = cross (edge1 , edge2 );
278+ let determinant = dot (tri_face_vector , ray . direction );
279+ var is_valid : bool ;
280+ if detect_backface {
281+ is_valid = abs (determinant ) >= 1e-8 ;
282+ } else {
283+ is_valid = determinant >= 1e-8 ;
256284 }
257285
286+ hit . hit = is_valid && t > 1e-5 && u >= 0 .0 && v >= 0 .0 && w >= 0 .0 ;
287+ hit . normal = normalize (tri_face_vector ) * - sign (determinant );
288+ hit . distance = t ;
289+ hit . position = ray . origin + t * ray . direction ;
290+ hit . is_backface = determinant > 0 .0 ;
258291 return hit ;
259292}
260293
0 commit comments