diff --git a/src/main/java/basics/math/algebra/Vector.java b/src/main/java/basics/math/algebra/Vector.java index 4717086..e0bd4b6 100644 --- a/src/main/java/basics/math/algebra/Vector.java +++ b/src/main/java/basics/math/algebra/Vector.java @@ -100,14 +100,31 @@ public class Vector { return this.sub(normal.scale(this.dot(normal) * 2.0)); } + // based on https://bheisler.github.io/post/writing-raytracer-in-rust-part-3/ public Vector refract(Vector normal, Vector incoming, double ior) { - double len2 = normal.dot(incoming); - double k = 1.0 - ior * ior * (1.0 - len2 * len2); - if (k < 0) - return Vector.origin(); + double iDotN = incoming.dot(normal); + double etaI = 1; + double etaT = ior; - return incoming.scale(ior).sub(normal.scale(ior * len2 + Math.sqrt(k))); + Vector refraction_n = normal; + + if (iDotN < 0) { + iDotN = -iDotN; + } else { + refraction_n = normal.negate(); + etaT = 1.0; + etaI = ior; + } + + double eta = etaI / etaT; + double k = 1.0 - (eta * eta) * (1.0 - iDotN * iDotN); + + if (k < 0.0) { + return Vector.origin(); + } else { + return incoming.add(refraction_n.scale(iDotN)).scale(eta).sub(refraction_n).scale(Math.sqrt(k)); + } } public Vector lerp(Vector other, double k) { diff --git a/src/main/java/geometry/scene/Scene.java b/src/main/java/geometry/scene/Scene.java index 60bf6cc..748ea1c 100644 --- a/src/main/java/geometry/scene/Scene.java +++ b/src/main/java/geometry/scene/Scene.java @@ -32,13 +32,14 @@ public class Scene { public static Scene generateExampleScene() { Scene scene = new Scene(new LinearList()); - BasicMaterial mirror = new BasicMaterial(Color.BLACK, 1.0, Color.WHITE, true); + BasicMaterial glass = new BasicMaterial(Color.BLACK, 1.0, Color.WHITE, true); + BasicMaterial mirror = new BasicMaterial(Color.BLACK, 1.0, Color.WHITE, false); BasicMaterial white = new BasicMaterial(new Color(0.8, 0.8, 0.8), 0.1, new Color(0.8, 0.8, 0.8), false); BasicMaterial red = new BasicMaterial(new Color(0.8, 0.0, 0.0), 0.1, new Color(0.8, 0.8, 0.8), false); BasicMaterial green = new BasicMaterial(new Color(0.0, 0.8, 0.0), 0.1, new Color(0.8, 0.8, 0.8), false); BasicMaterial blue = new BasicMaterial(new Color(0.0, 0.0, 0.8), 0.1, new Color(0.8, 0.8, 0.8), false); - scene.addMesh(new BasicMesh(mirror, new Sphere(new Vector(0,1.5,0), 1.0))); + scene.addMesh(new BasicMesh(glass, new Sphere(new Vector(0,0,0), 1.0))); scene.addMesh(new BasicMesh(white, new Sphere(new Vector(3,2,0), 0.25))); scene.addMesh(new BasicMesh(red, new Sphere(new Vector(2.5,2,-3), 0.33))); @@ -49,7 +50,7 @@ public class Scene { scene.addMesh(new BasicMesh(green, new Plane(new Vector(1, 0, 0), 4))); scene.addMesh(new BasicMesh(blue, new Plane(new Vector(0, 0, 1), 5))); - scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 0, 1), -4))); + scene.addMesh(new BasicMesh(mirror, new Plane(new Vector(0, 0, 1), -4))); scene.addLight(new Point(Color.WHITE.scale(0.5), new Vector(0, 4, 0))); scene.addLight(new Point(Color.WHITE.scale(0.5), new Vector(1, 3, 1)));