make Vec3#random generate unit vectors by default

main
jbb01 6 months ago
parent c0dccbbd0c
commit 89c4340821

@ -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) { public static @NotNull Vec3 random(@NotNull RandomGenerator random) {
return new Vec3( double x, y, z;
Math.fma(2, random.nextDouble(), -1), double squared;
Math.fma(2, random.nextDouble(), -1), do {
Math.fma(2, random.nextDouble(), -1) 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);
} }
/** public static @NotNull Vec3 randomOppositeHemisphere(@NotNull RandomGenerator random, @NotNull Vec3 direction) {
* {@return a uniformly random unit vector} double x, y, z;
*/
public static @NotNull Vec3 random(@NotNull RandomGenerator random, boolean unit) {
if (!unit) return random(random);
Vec3 vec;
double squared; double squared;
do { do {
vec = random(random); x = Math.fma(2, random.nextDouble(), -1);
squared = vec.squared(); y = Math.fma(2, random.nextDouble(), -1);
} while (squared > 1); z = Math.fma(2, random.nextDouble(), -1);
return vec.div(Math.sqrt(squared)); 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) { public static @NotNull Vec3 reflect(@NotNull Vec3 vec, @NotNull Vec3 normal) {

@ -25,7 +25,7 @@ public record MetallicMaterial(@NotNull Texture texture, double fuzz) implements
public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) {
var newDirection = Vec3.reflect(ray.direction(), hit.normal()); var newDirection = Vec3.reflect(ray.direction(), hit.normal());
if (fuzz > 0) { 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); var attenuation = texture.get(hit);
return Optional.of(new SpecularScatterResult(attenuation, new Ray(hit.position(), newDirection))); return Optional.of(new SpecularScatterResult(attenuation, new Ray(hit.position(), newDirection)));

@ -21,7 +21,7 @@ public record CosineProbabilityDensityFunction(@NotNull Vec3 normal) implements
@Override @Override
public @NotNull Vec3 generate(@NotNull RandomGenerator random) { 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; return out.isNearZero() ? normal() : out;
} }
} }

@ -14,6 +14,6 @@ public record SphereProbabilityDensityFunction() implements ProbabilityDensityFu
@Override @Override
public @NotNull Vec3 generate(@NotNull RandomGenerator random) { public @NotNull Vec3 generate(@NotNull RandomGenerator random) {
return Vec3.random(random, true); return Vec3.random(random);
} }
} }

@ -53,7 +53,7 @@ public final class PerlinTexture implements Texture {
this.mask = count - 1; this.mask = count - 1;
this.randvec = new Vec3[count]; this.randvec = new Vec3[count];
for (int i = 0; i < count; i++) { 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.permX = generatePerm(count, random);
this.permY = generatePerm(count, random); this.permY = generatePerm(count, random);

@ -143,7 +143,7 @@ public final class Box implements Hittable, Target {
@Override @Override
public @NotNull Vec3 getTargetingDirection(@NotNull Vec3 origin, @NotNull RandomGenerator random) { 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 // determine sides facing the origin and their solid angles
int visible = 0; int visible = 0;

@ -89,13 +89,12 @@ public final class Sphere implements Hittable, Target {
@Override @Override
public @NotNull Vec3 getTargetingDirection(@NotNull Vec3 origin, @NotNull RandomGenerator random) { public @NotNull Vec3 getTargetingDirection(@NotNull Vec3 origin, @NotNull RandomGenerator random) {
var direction = center.minus(origin); var direction = center.minus(origin);
var out = Vec3.randomOppositeHemisphere(random, direction);
Vec3 target; return new Vec3(
do { Math.fma(radius, out.x(), center.x() - origin.x()),
target = Vec3.random(random, true); Math.fma(radius, out.y(), center.y() - origin.y()),
} while (target.times(direction) >= 0); Math.fma(radius, out.z(), center.z() - origin.z())
);
return target.times(radius).plus(center).minus(origin);
} }
@Override @Override

Loading…
Cancel
Save