minor performance improvements
This commit is contained in:
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;
|
var a = this.origin.minus(origin).unit();
|
||||||
var b = this.origin.plus(u);
|
var b = this.origin.plus(u).minus(origin).unit();
|
||||||
var c = this.origin.plus(v);
|
var c = this.origin.plus(v).minus(origin).unit();
|
||||||
var d = b.plus(v);
|
var d = this.origin.plus(u).plus(v).minus(origin).unit();
|
||||||
var angle = PdfUtil.getSolidAngle(origin, a, b, d) + PdfUtil.getSolidAngle(origin, c, b, d);
|
var angle = PdfUtil.getSolidAngle(a, b, d) + PdfUtil.getSolidAngle(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…
x
Reference in New Issue
Block a user