|
|
@ -2,6 +2,7 @@ package eu.jonahbauer.raytracing.math;
|
|
|
|
|
|
|
|
|
|
|
|
import eu.jonahbauer.raytracing.scene.Hittable;
|
|
|
|
import eu.jonahbauer.raytracing.scene.Hittable;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.Comparator;
|
|
|
|
import java.util.Comparator;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
@ -11,7 +12,6 @@ import java.util.Optional;
|
|
|
|
* An axis-aligned bounding box.
|
|
|
|
* An axis-aligned bounding box.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
|
|
|
|
public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
|
|
|
|
public static final AABB UNIVERSE = new AABB(Vec3.MIN, Vec3.MAX);
|
|
|
|
|
|
|
|
public static final AABB EMPTY = new AABB(Vec3.ZERO, Vec3.ZERO);
|
|
|
|
public static final AABB EMPTY = new AABB(Vec3.ZERO, Vec3.ZERO);
|
|
|
|
public static final Comparator<AABB> X_AXIS = Comparator.comparing(AABB::min, Comparator.comparingDouble(Vec3::x));
|
|
|
|
public static final Comparator<AABB> X_AXIS = Comparator.comparing(AABB::min, Comparator.comparingDouble(Vec3::x));
|
|
|
|
public static final Comparator<AABB> Y_AXIS = Comparator.comparing(AABB::min, Comparator.comparingDouble(Vec3::y));
|
|
|
|
public static final Comparator<AABB> Y_AXIS = Comparator.comparing(AABB::min, Comparator.comparingDouble(Vec3::y));
|
|
|
@ -57,17 +57,13 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public boolean hit(@NotNull Ray ray) {
|
|
|
|
public boolean hit(@NotNull Ray ray) {
|
|
|
|
return intersect(ray).isPresent();
|
|
|
|
return intersect(ray) != null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public @NotNull Optional<Range> intersect(@NotNull Ray ray) {
|
|
|
|
public @Nullable Range intersect(@NotNull Ray ray) {
|
|
|
|
if (this == UNIVERSE) return Optional.of(Range.UNIVERSE);
|
|
|
|
|
|
|
|
if (this == EMPTY) return Optional.empty();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int vmask = ray.vmask();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var origin = ray.origin();
|
|
|
|
var origin = ray.origin();
|
|
|
|
var invDirection = ray.direction().inv();
|
|
|
|
var direction = ray.direction();
|
|
|
|
|
|
|
|
var invDirection = direction.inv();
|
|
|
|
|
|
|
|
|
|
|
|
// calculate t values for intersection points of ray with planes through min
|
|
|
|
// calculate t values for intersection points of ray with planes through min
|
|
|
|
var tmin = intersect(min(), origin, invDirection);
|
|
|
|
var tmin = intersect(min(), origin, invDirection);
|
|
|
@ -78,19 +74,27 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
|
|
|
|
double tlmax = Double.NEGATIVE_INFINITY; // lower limit maximum
|
|
|
|
double tlmax = Double.NEGATIVE_INFINITY; // lower limit maximum
|
|
|
|
double tumin = Double.POSITIVE_INFINITY; // upper limit minimum
|
|
|
|
double tumin = Double.POSITIVE_INFINITY; // upper limit minimum
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
// classify t values as lower or upper limit based on vmask
|
|
|
|
// classify t values as lower or upper limit based on ray direction
|
|
|
|
if ((vmask & (1 << i)) == 0) {
|
|
|
|
if (direction.get(i) >= 0) {
|
|
|
|
// min is lower limit and max is upper limit
|
|
|
|
// min is lower limit and max is upper limit
|
|
|
|
tlmax = Math.max(tlmax, tmin[i]);
|
|
|
|
if (tmin[i] > tlmax) {
|
|
|
|
tumin = Math.min(tumin, tmax[i]);
|
|
|
|
tlmax = tmin[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmax[i] < tumin) {
|
|
|
|
|
|
|
|
tumin = tmax[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// max is lower limit and min is upper limit
|
|
|
|
// max is lower limit and min is upper limit
|
|
|
|
tlmax = Math.max(tlmax, tmax[i]);
|
|
|
|
if (tmax[i] > tlmax) {
|
|
|
|
tumin = Math.min(tumin, tmin[i]);
|
|
|
|
tlmax = tmax[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmin[i] < tumin) {
|
|
|
|
|
|
|
|
tumin = tmin[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tlmax < tumin ? Optional.of(new Range(tlmax, tumin)) : Optional.empty();
|
|
|
|
return tlmax < tumin ? new Range(tlmax, tumin) : null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Ray ray) {
|
|
|
|
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Ray ray) {
|
|
|
|