diff --git a/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java b/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java index 0766781..ef58034 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java @@ -128,7 +128,7 @@ public final class SimpleRenderer implements Renderer { var attenuation = white; while (depth-- > 0) { - var optional = scene.hit(ray); + var optional = scene.hit(ray, random); if (optional.isEmpty()) { var background = scene.getBackgroundColor(ray); color = SampledSpectrum.fma(attenuation, background, color); diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/Hittable.java b/src/main/java/eu/jonahbauer/raytracing/scene/Hittable.java index f78c75c..3cf21ce 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/Hittable.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/Hittable.java @@ -9,15 +9,16 @@ import eu.jonahbauer.raytracing.scene.transform.Translate; import org.jetbrains.annotations.NotNull; import java.util.Optional; +import java.util.random.RandomGenerator; public interface Hittable { @NotNull Range FORWARD = new Range(0.001, Double.POSITIVE_INFINITY); /** - * @see #hit(Ray, Range) + * @see #hit(Ray, Range, RandomGenerator) */ - default @NotNull Optional hit(@NotNull Ray ray) { - return hit(ray, FORWARD); + default @NotNull Optional hit(@NotNull Ray ray, @NotNull RandomGenerator random) { + return hit(ray, FORWARD, random); } /** @@ -31,7 +32,7 @@ public interface Hittable { * @return the result of the hit test, containing (among others) the value {@code t} such that {@code ray.at(t)} is * a point on {@code this} hittable */ - @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range); + @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range, @NotNull RandomGenerator random); /** * {@return the axis-aligned bounding box of this hittable} diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java b/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java index 633bbc4..b609f88 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java @@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.random.RandomGenerator; public final class Scene extends HittableCollection { private final @NotNull HittableCollection objects; @@ -42,8 +43,8 @@ public final class Scene extends HittableCollection { } @Override - public void hit(@NotNull Ray ray, @NotNull State state) { - objects.hit(ray, state); + public void hit(@NotNull Ray ray, @NotNull State state, @NotNull RandomGenerator random) { + objects.hit(ray, state, random); } @Override diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/hittable2d/Hittable2D.java b/src/main/java/eu/jonahbauer/raytracing/scene/hittable2d/Hittable2D.java index 9fe384e..f8e2648 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/hittable2d/Hittable2D.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/hittable2d/Hittable2D.java @@ -7,9 +7,11 @@ import eu.jonahbauer.raytracing.render.material.Material; import eu.jonahbauer.raytracing.scene.HitResult; import eu.jonahbauer.raytracing.scene.Hittable; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.Optional; +import java.util.random.RandomGenerator; public abstract class Hittable2D implements Hittable { protected final @NotNull Vec3 origin; @@ -36,7 +38,7 @@ public abstract class Hittable2D implements Hittable { } @Override - public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range) { + public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range, @Nullable RandomGenerator random) { var denominator = ray.direction().dot(normal); if (Math.abs(denominator) < 1e-8) return Optional.empty(); // parallel diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java index c30c603..9349279 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java @@ -48,7 +48,7 @@ public final class Box implements Hittable, Target { } @Override - public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range) { + public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range, @Nullable RandomGenerator random) { // based on AABB#hit with additional detection of the side hit var origin = ray.origin(); var direction = ray.direction(); @@ -103,13 +103,13 @@ public final class Box implements Hittable, Target { t = tmin; side = entry; frontFace = true; - material = materials[side.ordinal()]; + material = materials[entry.ordinal()]; normal = side.normal; } else if (range.surrounds(tmax) && materials[exit.ordinal()] != null) { t = tmax; side = exit; frontFace = false; - material = materials[side.ordinal()]; + material = materials[exit.ordinal()]; normal = side.normal.neg(); } else { return Optional.empty(); @@ -130,7 +130,7 @@ public final class Box implements Hittable, Target { @Override public double getProbabilityDensity(@NotNull Vec3 origin, @NotNull Vec3 direction) { if (contains(origin)) return 1 / (4 * Math.PI); - if (hit(new Ray(origin, direction)).isEmpty()) return 0; + if (hit(new Ray(origin, direction), null).isEmpty()) return 0; var solidAngle = 0d; for (var s : Side.values()) { diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java index eb0613e..499ce7e 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java @@ -10,15 +10,16 @@ import eu.jonahbauer.raytracing.scene.Hittable; import org.jetbrains.annotations.NotNull; import java.util.Optional; +import java.util.random.RandomGenerator; public record ConstantMedium(@NotNull Hittable boundary, double density, @NotNull IsotropicMaterial material) implements Hittable { @Override - public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range) { - var hit1 = boundary.hit(ray, Range.UNIVERSE); + public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range, @NotNull RandomGenerator random) { + var hit1 = boundary.hit(ray, Range.UNIVERSE, random); if (hit1.isEmpty()) return Optional.empty(); - var hit2 = boundary.hit(ray, new Range(hit1.get().t() + 0.0001, Double.POSITIVE_INFINITY)); + var hit2 = boundary.hit(ray, new Range(hit1.get().t() + 0.0001, Double.POSITIVE_INFINITY), random); if (hit2.isEmpty()) return Optional.empty(); var tmin = Math.max(range.min(), hit1.get().t()); @@ -28,7 +29,7 @@ public record ConstantMedium(@NotNull Hittable boundary, double density, @NotNul var length = ray.direction().length(); var distance = length * (tmax - tmin); - var hitDistance = - Math.log(Math.random()) / density; + var hitDistance = - Math.log(random.nextDouble()) / density; if (hitDistance > distance) return Optional.empty(); var t = tmin + hitDistance / length; diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Sphere.java b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Sphere.java index 26101b4..a7324d8 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Sphere.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Sphere.java @@ -9,6 +9,7 @@ import eu.jonahbauer.raytracing.scene.HitResult; import eu.jonahbauer.raytracing.scene.Hittable; import eu.jonahbauer.raytracing.scene.Target; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.Optional; @@ -40,7 +41,7 @@ public final class Sphere implements Hittable, Target { } @Override - public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range) { + public @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range, @Nullable RandomGenerator random) { var t = hit0(ray, range); if (Double.isNaN(t)) return Optional.empty(); diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/transform/Transform.java b/src/main/java/eu/jonahbauer/raytracing/scene/transform/Transform.java index 28db126..49b5e83 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/transform/Transform.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/transform/Transform.java @@ -2,10 +2,8 @@ package eu.jonahbauer.raytracing.scene.transform; import eu.jonahbauer.raytracing.math.Range; import eu.jonahbauer.raytracing.math.Ray; -import eu.jonahbauer.raytracing.math.Vec3; import eu.jonahbauer.raytracing.scene.HitResult; import eu.jonahbauer.raytracing.scene.Hittable; -import eu.jonahbauer.raytracing.scene.Target; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -24,7 +22,7 @@ public abstract class Transform implements Hittable { protected abstract @NotNull HitResult transform(@NotNull HitResult result); @Override - public final @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range) { - return object.hit(transform(ray), range).map(this::transform); + public final @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range, @NotNull RandomGenerator random) { + return object.hit(transform(ray), range, random).map(this::transform); } } diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableBinaryTree.java b/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableBinaryTree.java index 7415a28..e7d12e0 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableBinaryTree.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableBinaryTree.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Comparator; import java.util.List; +import java.util.random.RandomGenerator; public final class HittableBinaryTree extends HittableCollection { private final @Nullable Hittable left; @@ -46,17 +47,17 @@ public final class HittableBinaryTree extends HittableCollection { } @Override - public void hit(@NotNull Ray ray, @NotNull State state) { + public void hit(@NotNull Ray ray, @NotNull State state, @NotNull RandomGenerator random) { if (!bbox.hit(ray, state.getRange())) return; if (left instanceof HittableCollection coll) { - coll.hit(ray, state); + coll.hit(ray, state, random); } else if (left != null) { - hit(state, ray, left); + hit(state, ray, left, random); } if (right instanceof HittableCollection coll) { - coll.hit(ray, state); + coll.hit(ray, state, random); } else if (right != null) { - hit(state, ray, right); + hit(state, ray, right, random); } } diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableCollection.java b/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableCollection.java index 35904cd..64d925c 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableCollection.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableCollection.java @@ -8,20 +8,21 @@ import org.jetbrains.annotations.NotNull; import java.util.Objects; import java.util.Optional; +import java.util.random.RandomGenerator; public abstract class HittableCollection implements Hittable { @Override - public final @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range) { + public final @NotNull Optional hit(@NotNull Ray ray, @NotNull Range range, @NotNull RandomGenerator random) { var state = new State(range); - hit(ray, state); + hit(ray, state, random); return state.getResult(); } - public abstract void hit(@NotNull Ray ray, @NotNull State state); + public abstract void hit(@NotNull Ray ray, @NotNull State state, @NotNull RandomGenerator random); - protected static boolean hit(@NotNull State state, @NotNull Ray ray, @NotNull Hittable object) { - var r = object.hit(ray, state.range); + protected static boolean hit(@NotNull State state, @NotNull Ray ray, @NotNull Hittable object, @NotNull RandomGenerator random) { + var r = object.hit(ray, state.range, random); if (r.isPresent()) { if (state.range.surrounds(r.get().t())){ state.result = r.get(); diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableList.java b/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableList.java index 29b87d4..2cf9eb7 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableList.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/util/HittableList.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.random.RandomGenerator; public final class HittableList extends HittableCollection { private final @NotNull List objects; @@ -22,8 +23,8 @@ public final class HittableList extends HittableCollection { } @Override - public void hit(@NotNull Ray ray, @NotNull State state) { - objects.forEach(object -> hit(state, ray, object)); + public void hit(@NotNull Ray ray, @NotNull State state, @NotNull RandomGenerator random) { + objects.forEach(object -> hit(state, ray, object, random)); } @Override