From 82b38d450109a09073428a48ad2efe93b3fc1996 Mon Sep 17 00:00:00 2001 From: jbb01 <32650546+jbb01@users.noreply.github.com> Date: Sat, 3 Aug 2024 22:16:53 +0200 Subject: [PATCH] add total internal reflection --- .../java/eu/jonahbauer/raytracing/Main.java | 2 +- .../material/DielectricMaterial.java | 18 ++++++++++++++++-- .../eu/jonahbauer/raytracing/math/Vec3.java | 11 ++++++++--- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/jonahbauer/raytracing/Main.java b/src/main/java/eu/jonahbauer/raytracing/Main.java index 5cb14f3..0cbaae6 100644 --- a/src/main/java/eu/jonahbauer/raytracing/Main.java +++ b/src/main/java/eu/jonahbauer/raytracing/Main.java @@ -17,7 +17,7 @@ public class Main { var scene = new Scene( new Sphere(0, -100.5, 1, 100, new LambertianMaterial(new Color(0.8, 0.8, 0.0))), new Sphere(0, 0, 1.2, 0.5, new LambertianMaterial(new Color(0.1, 0.2, 0.5))), - new Sphere(-1, 0, 1, 0.5, new DielectricMaterial(1.5)), + new Sphere(-1, 0, 1, 0.5, new DielectricMaterial(0.75)), new Sphere(1, 0, 1, 0.5, new MetallicMaterial(new Color(0.8, 0.6, 0.2), 1.0)) ); var camera = new Camera(512, 2, 16 / 9d); diff --git a/src/main/java/eu/jonahbauer/raytracing/material/DielectricMaterial.java b/src/main/java/eu/jonahbauer/raytracing/material/DielectricMaterial.java index 14870b0..e07cef9 100644 --- a/src/main/java/eu/jonahbauer/raytracing/material/DielectricMaterial.java +++ b/src/main/java/eu/jonahbauer/raytracing/material/DielectricMaterial.java @@ -12,7 +12,21 @@ public record DielectricMaterial(double refractionIndex) implements Material { @Override public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit) { var ri = hit.frontFace() ? (1 / refractionIndex) : refractionIndex; - var refracted = Vec3.refract(ray.direction(), hit.normal(), ri); - return Optional.of(new ScatterResult(new Ray(hit.position(), refracted), Color.WHITE)); + + var cosTheta = Math.min(- ray.direction().unit().times(hit.normal()), 1.0); + var reflectance = reflectance(cosTheta); + var reflect = reflectance > Math.random(); + + var newDirection = (reflect ? Optional.empty() : Vec3.refract(ray.direction(), hit.normal(), ri)) + .orElseGet(() -> Vec3.reflect(ray.direction(), hit.normal())); + + return Optional.of(new ScatterResult(new Ray(hit.position(), newDirection), Color.WHITE)); + } + + private double reflectance(double cos) { + // use schlick's approximation for reflectance + var r0 = (1 - refractionIndex) / (1 + refractionIndex); + r0 = r0 * r0; + return r0 + (1 - r0) * (1 - cos) * (1 - cos) * (1 - cos) * (1 - cos) * (1 - cos); } } diff --git a/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java b/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java index 9bb8f85..8dafe48 100644 --- a/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java +++ b/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java @@ -2,6 +2,8 @@ package eu.jonahbauer.raytracing.math; import org.jetbrains.annotations.NotNull; +import java.util.Optional; + public record Vec3(double x, double y, double z) { public static final Vec3 ZERO = new Vec3(0, 0, 0); public static final Vec3 UNIT_X = new Vec3(1, 0, 0); @@ -31,12 +33,15 @@ public record Vec3(double x, double y, double z) { return vec.minus(normal.times(2 * normal.times(vec))); } - public static @NotNull Vec3 refract(@NotNull Vec3 vec, @NotNull Vec3 normal, double index) { + public static @NotNull Optional refract(@NotNull Vec3 vec, @NotNull Vec3 normal, double ri) { vec = vec.unit(); var cosTheta = Math.min(- vec.times(normal), 1.0); - var rOutPerp = vec.plus(normal.times(cosTheta)).times(index); + var sinTheta = Math.sqrt(1 - cosTheta * cosTheta); + if (ri * sinTheta > 1) return Optional.empty(); + + var rOutPerp = vec.plus(normal.times(cosTheta)).times(ri); var rOutParallel = normal.times(- Math.sqrt(Math.abs(1 - rOutPerp.squared()))); - return rOutPerp.plus(rOutParallel); + return Optional.of(rOutPerp.plus(rOutParallel)); } public @NotNull Vec3 plus(@NotNull Vec3 b) {