switch from octree to binary tree
This commit is contained in:
parent
8773b04b0f
commit
5bf3108ab4
@ -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…
x
Reference in New Issue
Block a user