switch from octree to binary tree

main
jbb01 6 months ago
parent 3a3949f518
commit 9106ccf8b0

@ -3,6 +3,7 @@ package eu.jonahbauer.raytracing.math;
import eu.jonahbauer.raytracing.scene.Hittable;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
@ -12,6 +13,9 @@ import java.util.Optional;
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 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> Z_AXIS = Comparator.comparing(AABB::min, Comparator.comparingDouble(Vec3::z));
public AABB {
var a = min;
@ -58,13 +62,17 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
public @NotNull Optional<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 invDirection = ray.direction().inv();
// calculate t values for intersection points of ray with planes through min
var tmin = intersect(min(), ray);
var tmin = intersect(min(), origin, invDirection);
// calculate t values for intersection points of ray with planes through max
var tmax = intersect(max(), ray);
var tmax = intersect(max(), origin, invDirection);
// determine range of t for which the ray is inside this voxel
double tlmax = Double.NEGATIVE_INFINITY; // lower limit maximum
@ -86,10 +94,14 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
}
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Ray ray) {
return intersect(corner, ray.origin(), ray.direction().inv());
}
private static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Vec3 origin, @NotNull Vec3 invDirection) {
return new double[] {
(corner.x() - ray.origin().x()) / ray.direction().x(),
(corner.y() - ray.origin().y()) / ray.direction().y(),
(corner.z() - ray.origin().z()) / ray.direction().z(),
(corner.x() - origin.x()) * invDirection.x(),
(corner.y() - origin.y()) * invDirection.y(),
(corner.z() - origin.z()) * invDirection.z(),
};
}
}

@ -16,4 +16,8 @@ public record Range(double min, double max) {
public boolean surrounds(double value) {
return min < value && value < max;
}
public double size() {
return max - min;
}
}

@ -106,6 +106,10 @@ public record Vec3(double x, double y, double z) {
return new Vec3(-x, -y, -z);
}
public @NotNull Vec3 inv() {
return new Vec3(1 / x, 1 / y, 1 / z);
}
public @NotNull Vec3 cross(@NotNull Vec3 b) {
return new Vec3(
this.y() * b.z() - b.y() * this.z(),

@ -3,17 +3,15 @@ package eu.jonahbauer.raytracing.scene;
import eu.jonahbauer.raytracing.math.AABB;
import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.render.Color;
import eu.jonahbauer.raytracing.scene.util.HittableBinaryTree;
import eu.jonahbauer.raytracing.scene.util.HittableCollection;
import eu.jonahbauer.raytracing.scene.util.HittableList;
import eu.jonahbauer.raytracing.scene.util.HittableOctree;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public final class Scene extends HittableCollection {
private final @NotNull HittableOctree octree;
private final @NotNull HittableList list;
private final @NotNull HittableCollection objects;
private final @NotNull SkyBox background;
public Scene(@NotNull List<? extends @NotNull Hittable> objects) {
@ -25,20 +23,8 @@ public final class Scene extends HittableCollection {
}
public Scene(@NotNull SkyBox background, @NotNull List<? extends @NotNull Hittable> objects) {
var bounded = new ArrayList<Hittable>();
var unbounded = new ArrayList<Hittable>();
objects.forEach(object -> {
if (object.getBoundingBox().isPresent()) {
bounded.add(object);
} else {
unbounded.add(object);
}
});
this.octree = new HittableOctree(bounded);
this.list = new HittableList(unbounded);
this.background = background;
this.objects = new HittableBinaryTree(objects);
this.background = Objects.requireNonNull(background);
}
public Scene(@NotNull Hittable @NotNull... objects) {
@ -55,8 +41,7 @@ public final class Scene extends HittableCollection {
@Override
public void hit(@NotNull Ray ray, @NotNull State state) {
octree.hit(ray, state);
list.hit(ray, state);
objects.hit(ray, state);
}
@Override

@ -0,0 +1,67 @@
package eu.jonahbauer.raytracing.scene.util;
import eu.jonahbauer.raytracing.math.AABB;
import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.scene.Hittable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.List;
public final class HittableBinaryTree extends HittableCollection {
private final @Nullable Hittable left;
private final @Nullable Hittable right;
private final @NotNull AABB bbox;
public HittableBinaryTree(@NotNull List<? extends @NotNull Hittable> objects) {
bbox = AABB.getBoundingBox(objects).orElse(AABB.EMPTY);
if (objects.isEmpty()) {
left = null;
right = null;
} else if (objects.size() == 1) {
left = objects.getFirst();
right = null;
} else if (objects.size() == 2) {
left = objects.getFirst();
right = objects.getLast();
} else {
var x = bbox.x().size();
var y = bbox.y().size();
var z = bbox.z().size();
Comparator<AABB> comparator;
if (x > y && x > z) {
comparator = AABB.X_AXIS;
} else if (y > z) {
comparator = AABB.Y_AXIS;
} else {
comparator = AABB.Z_AXIS;
}
var sorted = objects.stream().sorted(Comparator.comparing(Hittable::getBoundingBox, comparator)).toList();
var size = sorted.size();
left = new HittableBinaryTree(sorted.subList(0, size / 2));
right = new HittableBinaryTree(sorted.subList(size / 2, size));
}
}
@Override
public void hit(@NotNull Ray ray, @NotNull State state) {
if (!bbox.hit(ray)) return;
if (left instanceof HittableCollection coll) {
coll.hit(ray, state);
} else if (left != null) {
hit(state, ray, left);
}
if (right instanceof HittableCollection coll) {
coll.hit(ray, state);
} else if (right != null) {
hit(state, ray, right);
}
}
@Override
public @NotNull AABB getBoundingBox() {
return bbox;
}
}
Loading…
Cancel
Save