From 89c4340821c0ffdee49954e844e78a32cc457dc6 Mon Sep 17 00:00:00 2001 From: jbb01 <32650546+jbb01@users.noreply.github.com> Date: Thu, 8 Aug 2024 21:06:49 +0200 Subject: [PATCH] make Vec3#random generate unit vectors by default --- .../eu/jonahbauer/raytracing/math/Vec3.java | 36 ++++++++++--------- .../render/material/MetallicMaterial.java | 2 +- .../pdf/CosineProbabilityDensityFunction.java | 2 +- .../pdf/SphereProbabilityDensityFunction.java | 2 +- .../render/texture/PerlinTexture.java | 2 +- .../raytracing/scene/hittable3d/Box.java | 2 +- .../raytracing/scene/hittable3d/Sphere.java | 13 ++++--- 7 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java b/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java index 7870fc5..6398560 100644 --- a/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java +++ b/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java @@ -18,28 +18,32 @@ public record Vec3(double x, double y, double z) { } /** - * {@return a uniformly random vector with components in the range [-1, 1)} + * {@return a uniformly random unit vector} */ public static @NotNull Vec3 random(@NotNull RandomGenerator random) { - return new Vec3( - Math.fma(2, random.nextDouble(), -1), - Math.fma(2, random.nextDouble(), -1), - Math.fma(2, random.nextDouble(), -1) - ); + double x, y, z; + double squared; + do { + x = Math.fma(2, random.nextDouble(), -1); + y = Math.fma(2, random.nextDouble(), -1); + z = Math.fma(2, random.nextDouble(), -1); + squared = x * x + y * y + z * z; + } while (squared > 1); + var factor = 1 / Math.sqrt(squared); + return new Vec3(x * factor, y * factor, z * factor); } - /** - * {@return a uniformly random unit vector} - */ - public static @NotNull Vec3 random(@NotNull RandomGenerator random, boolean unit) { - if (!unit) return random(random); - Vec3 vec; + public static @NotNull Vec3 randomOppositeHemisphere(@NotNull RandomGenerator random, @NotNull Vec3 direction) { + double x, y, z; double squared; do { - vec = random(random); - squared = vec.squared(); - } while (squared > 1); - return vec.div(Math.sqrt(squared)); + x = Math.fma(2, random.nextDouble(), -1); + y = Math.fma(2, random.nextDouble(), -1); + z = Math.fma(2, random.nextDouble(), -1); + squared = x * x + y * y + z * z; + } while (squared > 1 || direction.x() * x + direction.y() * y + direction.z() * z >= 0); + var factor = 1 / Math.sqrt(squared); + return new Vec3(x * factor, y * factor, z * factor); } public static @NotNull Vec3 reflect(@NotNull Vec3 vec, @NotNull Vec3 normal) { diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java b/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java index 82387ff..c1a66f4 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java @@ -25,7 +25,7 @@ public record MetallicMaterial(@NotNull Texture texture, double fuzz) implements public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { var newDirection = Vec3.reflect(ray.direction(), hit.normal()); if (fuzz > 0) { - newDirection = newDirection.unit().plus(Vec3.random(random, true).times(fuzz)); + newDirection = newDirection.unit().plus(Vec3.random(random).times(fuzz)); } var attenuation = texture.get(hit); return Optional.of(new SpecularScatterResult(attenuation, new Ray(hit.position(), newDirection))); diff --git a/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/CosineProbabilityDensityFunction.java b/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/CosineProbabilityDensityFunction.java index 306547e..d0780e9 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/CosineProbabilityDensityFunction.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/CosineProbabilityDensityFunction.java @@ -21,7 +21,7 @@ public record CosineProbabilityDensityFunction(@NotNull Vec3 normal) implements @Override public @NotNull Vec3 generate(@NotNull RandomGenerator random) { - var out = normal().plus(Vec3.random(random, true)); + var out = normal().plus(Vec3.random(random)); return out.isNearZero() ? normal() : out; } } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/SphereProbabilityDensityFunction.java b/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/SphereProbabilityDensityFunction.java index 30727bb..cfe22bb 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/SphereProbabilityDensityFunction.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/SphereProbabilityDensityFunction.java @@ -14,6 +14,6 @@ public record SphereProbabilityDensityFunction() implements ProbabilityDensityFu @Override public @NotNull Vec3 generate(@NotNull RandomGenerator random) { - return Vec3.random(random, true); + return Vec3.random(random); } } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/texture/PerlinTexture.java b/src/main/java/eu/jonahbauer/raytracing/render/texture/PerlinTexture.java index 1b3ebd7..d155d43 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/texture/PerlinTexture.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/texture/PerlinTexture.java @@ -53,7 +53,7 @@ public final class PerlinTexture implements Texture { this.mask = count - 1; this.randvec = new Vec3[count]; for (int i = 0; i < count; i++) { - this.randvec[i] = Vec3.random(random, true); + this.randvec[i] = Vec3.random(random); } this.permX = generatePerm(count, random); this.permY = generatePerm(count, random); 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 d8e1b9d..123f09a 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java @@ -143,7 +143,7 @@ public final class Box implements Hittable, Target { @Override public @NotNull Vec3 getTargetingDirection(@NotNull Vec3 origin, @NotNull RandomGenerator random) { - if (contains(origin)) return Vec3.random(random, true); + if (contains(origin)) return Vec3.random(random); // determine sides facing the origin and their solid angles int visible = 0; 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 cf03dcd..f2074b4 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Sphere.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Sphere.java @@ -89,13 +89,12 @@ public final class Sphere implements Hittable, Target { @Override public @NotNull Vec3 getTargetingDirection(@NotNull Vec3 origin, @NotNull RandomGenerator random) { var direction = center.minus(origin); - - Vec3 target; - do { - target = Vec3.random(random, true); - } while (target.times(direction) >= 0); - - return target.times(radius).plus(center).minus(origin); + var out = Vec3.randomOppositeHemisphere(random, direction); + return new Vec3( + Math.fma(radius, out.x(), center.x() - origin.x()), + Math.fma(radius, out.y(), center.y() - origin.y()), + Math.fma(radius, out.z(), center.z() - origin.z()) + ); } @Override