minor performance improvements

main
jbb01 6 months ago
parent e2c9609e0e
commit dbd3d5fc4b

@ -23,7 +23,9 @@ public record MixtureProbabilityDensityFunction(
@Override @Override
public double value(@NotNull Vec3 direction) { public double value(@NotNull Vec3 direction) {
return weight * a.value(direction) + (1 - weight) * b.value(direction); var v = a.value(direction);
var w = b.value(direction);
return Math.fma(weight, v, Math.fma(-weight, w, w));
} }
@Override @Override

@ -4,6 +4,7 @@ import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.scene.Target; import eu.jonahbauer.raytracing.scene.Target;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
@ -11,10 +12,13 @@ import java.util.random.RandomGenerator;
/** /**
* A probability density function targeting a target. * A probability density function targeting a target.
*/ */
public record TargetingProbabilityDensityFunction(@NotNull Vec3 origin, @NotNull List<@NotNull Target> targets) implements ProbabilityDensityFunction { public final class TargetingProbabilityDensityFunction implements ProbabilityDensityFunction {
public TargetingProbabilityDensityFunction { private final @NotNull Vec3 origin;
Objects.requireNonNull(origin, "origin"); private final @NotNull List<@NotNull Target> targets;
targets = List.copyOf(targets);
public TargetingProbabilityDensityFunction(@NotNull Vec3 origin, @NotNull List<@NotNull Target> targets) {
this.origin = Objects.requireNonNull(origin, "origin");
this.targets = new ArrayList<>(targets);
} }
@Override @Override

@ -11,12 +11,13 @@ import org.jetbrains.annotations.NotNull;
import java.util.Optional; import java.util.Optional;
public interface Hittable { public interface Hittable {
@NotNull Range FORWARD = new Range(0.001, Double.POSITIVE_INFINITY);
/** /**
* @see #hit(Ray, Range) * @see #hit(Ray, Range)
*/ */
default @NotNull Optional<HitResult> hit(@NotNull Ray ray) { default @NotNull Optional<HitResult> hit(@NotNull Ray ray) {
return hit(ray, new Range(0.001, Double.POSITIVE_INFINITY)); return hit(ray, FORWARD);
} }
/** /**

@ -57,6 +57,23 @@ public abstract class Hittable2D implements Hittable {
)); ));
} }
protected double hit0(@NotNull Ray ray, @NotNull Range range) {
var denominator = ray.direction().times(normal);
if (Math.abs(denominator) < 1e-8) return Double.NaN; // parallel
var t = (d - ray.origin().times(normal)) / denominator;
if (!range.surrounds(t)) return Double.NaN;
var position = ray.at(t);
var p = position.minus(origin);
var alpha = w.times(p.cross(v));
var beta = w.times(u.cross(p));
if (!isInterior(alpha, beta)) return Double.NaN;
return t;
}
protected abstract boolean isInterior(double alpha, double beta); protected abstract boolean isInterior(double alpha, double beta);
@Override @Override

@ -31,14 +31,13 @@ public final class Parallelogram extends Hittable2D implements Target {
@Override @Override
public double getProbabilityDensity(@NotNull Vec3 origin, @NotNull Vec3 direction) { public double getProbabilityDensity(@NotNull Vec3 origin, @NotNull Vec3 direction) {
var result = hit(new Ray(origin, direction)); if (Double.isNaN(hit0(new Ray(origin, direction), FORWARD))) return 0;
if (result.isEmpty()) return 0;
var a = this.origin.minus(origin).unit();
var a = this.origin; var b = this.origin.plus(u).minus(origin).unit();
var b = this.origin.plus(u); var c = this.origin.plus(v).minus(origin).unit();
var c = this.origin.plus(v); var d = this.origin.plus(u).plus(v).minus(origin).unit();
var d = b.plus(v); var angle = PdfUtil.getSolidAngle(a, b, d) + PdfUtil.getSolidAngle(c, b, d);
var angle = PdfUtil.getSolidAngle(origin, a, b, d) + PdfUtil.getSolidAngle(origin, c, b, d);
return 1 / angle; return 1 / angle;
} }

@ -293,12 +293,12 @@ public final class Box implements Hittable, Target {
* {@return the solid angle covered by <code>this</code> side of the <code>box</code> when viewed from <code>pos</code>} * {@return the solid angle covered by <code>this</code> side of the <code>box</code> when viewed from <code>pos</code>}
*/ */
public double getSolidAngle(@NotNull AABB box, @NotNull Vec3 pos) { public double getSolidAngle(@NotNull AABB box, @NotNull Vec3 pos) {
var a = get(box, 0, 0); var a = get(box, 0, 0).minus(pos).unit();
var b = get(box, 0, 1); var b = get(box, 0, 1).minus(pos).unit();
var c = get(box, 1, 1); var c = get(box, 1, 1).minus(pos).unit();
var d = get(box, 1, 0); var d = get(box, 1, 0).minus(pos).unit();
return PdfUtil.getSolidAngle(pos, a, b, d) + PdfUtil.getSolidAngle(pos, c, b, d); return PdfUtil.getSolidAngle(a, b, d) + PdfUtil.getSolidAngle(c, b, d);
} }
} }
} }

@ -21,12 +21,18 @@ public final class Sphere implements Hittable, Target {
private final @NotNull AABB bbox; private final @NotNull AABB bbox;
private final @NotNull Vec3 normalizedCenter;
private final double invRadius;
public Sphere(@NotNull Vec3 center, double radius, @NotNull Material material) { public Sphere(@NotNull Vec3 center, double radius, @NotNull Material material) {
this.center = Objects.requireNonNull(center, "center"); this.center = Objects.requireNonNull(center, "center");
this.material = Objects.requireNonNull(material, "material"); this.material = Objects.requireNonNull(material, "material");
if (radius <= 0 || !Double.isFinite(radius)) throw new IllegalArgumentException("radius must be positive"); if (radius <= 0 || !Double.isFinite(radius)) throw new IllegalArgumentException("radius must be positive");
this.radius = radius; this.radius = radius;
this.invRadius = 1 / radius;
this.normalizedCenter = this.center.times(-this.invRadius);
this.bbox = new AABB( this.bbox = new AABB(
center.minus(radius, radius, radius), center.minus(radius, radius, radius),
center.plus(radius, radius, radius) center.plus(radius, radius, radius)
@ -35,23 +41,11 @@ public final class Sphere implements Hittable, Target {
@Override @Override
public @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) { public @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
var oc = ray.origin().minus(center); var t = hit0(ray, range);
if (Double.isNaN(t)) return Optional.empty();
var a = ray.direction().squared();
var h = ray.direction().times(oc);
var c = oc.squared() - radius * radius;
var discriminant = h * h - a * c;
if (discriminant < 0) return Optional.empty();
var sd = Math.sqrt(discriminant);
double t = (- h - sd) / a;
if (!range.surrounds(t)) t = (- h + sd) / a;
if (!range.surrounds(t)) return Optional.empty();
var position = ray.at(t); var position = ray.at(t);
var normal = position.minus(center).div(radius); var normal = Vec3.fma(invRadius, position, normalizedCenter);
var frontFace = normal.times(ray.direction()) < 0; var frontFace = normal.times(ray.direction()) < 0;
double u; double u;
@ -72,6 +66,25 @@ public final class Sphere implements Hittable, Target {
)); ));
} }
private double hit0(@NotNull Ray ray, @NotNull Range range) {
var oc = ray.origin().minus(center);
var a = ray.direction().squared();
var h = ray.direction().times(oc);
var c = oc.squared() - radius * radius;
var discriminant = h * h - a * c;
if (discriminant < 0) return Double.NaN;
var sd = Math.sqrt(discriminant);
double t = (- h - sd) / a;
if (!range.surrounds(t)) t = (- h + sd) / a;
if (!range.surrounds(t)) return Double.NaN;
return t;
}
@Override @Override
public @NotNull AABB getBoundingBox() { public @NotNull AABB getBoundingBox() {
return bbox; return bbox;
@ -79,7 +92,7 @@ public final class Sphere implements Hittable, Target {
@Override @Override
public double getProbabilityDensity(@NotNull Vec3 origin, @NotNull Vec3 direction) { public double getProbabilityDensity(@NotNull Vec3 origin, @NotNull Vec3 direction) {
if (hit(new Ray(origin, direction)).isEmpty()) return 0; if (Double.isNaN(hit0(new Ray(origin, direction), FORWARD))) return 0;
var cos = Math.sqrt(1 - radius * radius / (center.minus(origin).squared())); var cos = Math.sqrt(1 - radius * radius / (center.minus(origin).squared()));
var solidAngle = 2 * Math.PI * (1 - cos); var solidAngle = 2 * Math.PI * (1 - cos);

@ -8,12 +8,12 @@ public final class PdfUtil {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public static double getSolidAngle(@NotNull Vec3 o, @NotNull Vec3 a, @NotNull Vec3 b, @NotNull Vec3 c) { /**
var i = a.minus(o).unit(); * {@return the solid angle of the triangle abc as seen from the origin} The vectors {@code a}, {@code b} and {@code c}
var j = b.minus(o).unit(); * must be unit vectors.
var k = c.minus(o).unit(); */
public static double getSolidAngle(@NotNull Vec3 a, @NotNull Vec3 b, @NotNull Vec3 c) {
var angle = 2 * Math.atan(Math.abs(i.times(j.cross(k))) / (1 + i.times(j) + j.times(k) + k.times(i))); var angle = 2 * Math.atan(Math.abs(a.times(b.cross(c))) / (1 + a.times(b) + b.times(c) + c.times(a)));
return angle < 0 ? 2 * Math.PI + angle : angle; return angle < 0 ? 2 * Math.PI + angle : angle;
} }
} }

Loading…
Cancel
Save