add total internal reflection

main
jbb01 6 months ago
parent 088263b344
commit 82b38d4501

@ -17,7 +17,7 @@ public class Main {
var scene = new Scene( var scene = new Scene(
new Sphere(0, -100.5, 1, 100, new LambertianMaterial(new Color(0.8, 0.8, 0.0))), 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(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)) 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); var camera = new Camera(512, 2, 16 / 9d);

@ -12,7 +12,21 @@ public record DielectricMaterial(double refractionIndex) implements Material {
@Override @Override
public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit) { public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit) {
var ri = hit.frontFace() ? (1 / refractionIndex) : refractionIndex; 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.<Vec3>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);
} }
} }

@ -2,6 +2,8 @@ package eu.jonahbauer.raytracing.math;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public record Vec3(double x, double y, double z) { public record Vec3(double x, double y, double z) {
public static final Vec3 ZERO = new Vec3(0, 0, 0); public static final Vec3 ZERO = new Vec3(0, 0, 0);
public static final Vec3 UNIT_X = new Vec3(1, 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))); 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<Vec3> refract(@NotNull Vec3 vec, @NotNull Vec3 normal, double ri) {
vec = vec.unit(); vec = vec.unit();
var cosTheta = Math.min(- vec.times(normal), 1.0); 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()))); 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) { public @NotNull Vec3 plus(@NotNull Vec3 b) {

Loading…
Cancel
Save