diff --git a/examples/raytracer.png b/examples/raytracer.png index a92d625..89717ec 100644 Binary files a/examples/raytracer.png and b/examples/raytracer.png differ diff --git a/examples/raytracer.psl b/examples/raytracer.psl index 3733731..2f2a16b 100644 --- a/examples/raytracer.psl +++ b/examples/raytracer.psl @@ -211,6 +211,9 @@ func log(x: f32) -> f32: func abs(x: f32) -> f32: return if x >= 0.0 then x else -x +func sqr(x: f32) -> f32: + return x * x + func min(x: f32, y: f32) -> f32: return if x <= y then x else y @@ -598,21 +601,29 @@ func raytrace(scene: scene*, camera_ray: ray, rng: rng mut*) -> vec3: new_direction = normalized(add(new_direction, mults(next_vec3_normal(rng), cosine * intersection.material.roughness))) else if intersection.material.type == glass_tag: - // This should also contain multiplication by brdf and division by direction pdf, - // but we'll just pretend that the random refracted ray pdf coincides with brdf and thus cancels out - factor = multv(factor, intersection.material.color) - mut ior = intersection.material.ior if inside: ior = 1.0 / ior - // Compute perfect refracted ray - let k = 1.0 - ior * ior * (1.0 - cosine * cosine) - if k >= 0.0: - new_direction = add(mults(current_ray.direction, ior), mults(intersection.normal, ior * abs(cosine) - sqrt(k))) - else: - // Total internal reflection + // Schlick's approximation for Fresnel term + let r0 = sqr((1.0 - ior) / (1.0 + ior)) + let reflectance = r0 + (1.0 - r0) * pow(max(0.0, 1.0 - abs(cosine)), 5.0) + + if next_f32(rng) < reflectance: + // Compute perfect-mirror reflected direction new_direction = add(current_ray.direction, mults(intersection.normal, 2.0 * cosine)) + else: + // This should also contain multiplication by brdf and division by direction pdf, + // but we'll just pretend that the random refracted ray pdf coincides with brdf and thus cancels out + factor = multv(factor, intersection.material.color) + + // Compute perfect refracted ray + let k = 1.0 - ior * ior * (1.0 - cosine * cosine) + if k >= 0.0: + new_direction = add(mults(current_ray.direction, ior), mults(intersection.normal, ior * abs(cosine) - sqrt(k))) + else: + // Total internal reflection + new_direction = add(current_ray.direction, mults(intersection.normal, 2.0 * cosine)) // Alter the direction based on roughness new_direction = normalized(add(new_direction, mults(next_vec3_normal(rng), intersection.material.roughness)))