improve performance of boxes

main
jbb01 6 months ago
parent 1d48a49987
commit 18c179f8e3

@ -11,9 +11,9 @@ import eu.jonahbauer.raytracing.scene.Hittable;
import eu.jonahbauer.raytracing.scene.Scene;
import eu.jonahbauer.raytracing.scene.SkyBox;
import eu.jonahbauer.raytracing.scene.hittable2d.Parallelogram;
import eu.jonahbauer.raytracing.scene.hittable3d.Box;
import eu.jonahbauer.raytracing.scene.hittable3d.ConstantMedium;
import eu.jonahbauer.raytracing.scene.hittable3d.Sphere;
import eu.jonahbauer.raytracing.scene.util.Hittables;
import eu.jonahbauer.raytracing.scene.util.HittableBinaryTree;
import org.jetbrains.annotations.NotNull;
@ -168,8 +168,8 @@ public class Examples {
new Parallelogram(new Vec3(0, 0, 0), new Vec3(555, 0, 0), new Vec3(0, 0, 555), white),
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0, 0), new Vec3(0, 0, -555), white),
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0, 0), new Vec3(0, 555, 0), white),
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65))
new Box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
new Box(new Vec3(0, 0, 0), new Vec3(165, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65))
),
SimpleCamera.builder()
.withImage(height, height)
@ -196,11 +196,11 @@ public class Examples {
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0, 0), new Vec3(0, 0, -555), white),
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0, 0), new Vec3(0, 555, 0), white),
new ConstantMedium(
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
new Box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
0.01, new IsotropicMaterial(Color.BLACK)
),
new ConstantMedium(
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65)),
new Box(new Vec3(0, 0, 0), new Vec3(165, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65)),
0.01, new IsotropicMaterial(Color.WHITE)
)
),
@ -243,7 +243,7 @@ public class Examples {
for (int i = 0; i < data.size(); i++) {
var partei = data.get(i);
objects.add(Hittables.box(
objects.add(new Box(
new Vec3((i + 1) * spacing + i * size, 0, spacing),
new Vec3((i + 1) * spacing + (i + 1) * size, partei.stimmen() * 15, spacing + size),
new DielectricMaterial(1.5, partei.color())
@ -316,7 +316,7 @@ public class Examples {
var x1 = x0 + w;
var y1 = random.nextInt(1, 101);
var z1 = z0 + w;
boxes.add(Hittables.box(new Vec3(x0, y0, z0), new Vec3(x1, y1, z1), ground));
boxes.add(new Box(new Vec3(x0, y0, z0), new Vec3(x1, y1, z1), ground));
}
}
objects.add(new HittableBinaryTree(boxes));

@ -2,7 +2,6 @@ package eu.jonahbauer.raytracing.math;
import eu.jonahbauer.raytracing.scene.Hittable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.List;
@ -57,10 +56,6 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
}
public boolean hit(@NotNull Ray ray) {
return intersect(ray) != null;
}
public @Nullable Range intersect(@NotNull Ray ray) {
var origin = ray.origin();
var direction = ray.direction();
var invDirection = direction.inv();
@ -73,35 +68,24 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
// determine range of t for which the ray is inside this voxel
double tlmax = Double.NEGATIVE_INFINITY; // lower limit maximum
double tumin = Double.POSITIVE_INFINITY; // upper limit minimum
for (int i = 0; i < 3; i++) {
// classify t values as lower or upper limit based on ray direction
if (direction.get(i) >= 0) {
// min is lower limit and max is upper limit
if (tmin[i] > tlmax) {
tlmax = tmin[i];
}
if (tmax[i] < tumin) {
tumin = tmax[i];
}
if (tmin[i] > tlmax) tlmax = tmin[i];
if (tmax[i] < tumin) tumin = tmax[i];
} else {
// max is lower limit and min is upper limit
if (tmax[i] > tlmax) {
tlmax = tmax[i];
if (tmax[i] > tlmax) tlmax = tmax[i];
if (tmin[i] < tumin) tumin = tmin[i];
}
if (tmin[i] < tumin) {
tumin = tmin[i];
}
}
}
return tlmax < tumin ? new Range(tlmax, tumin) : null;
}
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Ray ray) {
return intersect(corner, ray.origin(), ray.direction().inv());
return tlmax < tumin;
}
private static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Vec3 origin, @NotNull Vec3 invDirection) {
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Vec3 origin, @NotNull Vec3 invDirection) {
return new double[] {
(corner.x() - origin.x()) * invDirection.x(),
(corner.y() - origin.y()) * invDirection.y(),

@ -0,0 +1,136 @@
package eu.jonahbauer.raytracing.scene.hittable3d;
import eu.jonahbauer.raytracing.math.AABB;
import eu.jonahbauer.raytracing.math.Range;
import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.render.material.Material;
import eu.jonahbauer.raytracing.scene.HitResult;
import eu.jonahbauer.raytracing.scene.Hittable;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.Optional;
public record Box(@NotNull AABB box, @NotNull Material material) implements Hittable {
public Box {
Objects.requireNonNull(box, "box");
Objects.requireNonNull(material, "material");
}
public Box(@NotNull Vec3 a, @NotNull Vec3 b, @NotNull Material material) {
this(new AABB(a, b), material);
}
@Override
public @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
// based on AABB#hit with additional detection of the side hit
var origin = ray.origin();
var direction = ray.direction();
var invDirection = direction.inv();
var tmin = AABB.intersect(box.min(), origin, invDirection);
var tmax = AABB.intersect(box.max(), origin, invDirection);
double tlmax = Double.NEGATIVE_INFINITY;
double tumin = Double.POSITIVE_INFINITY;
Side entry = null;
Side exit = null;
for (int i = 0; i < 3; i++) {
if (direction.get(i) >= 0) {
if (tmin[i] > tlmax) {
tlmax = tmin[i];
entry = Side.NEGATIVE[i];
}
if (tmax[i] < tumin) {
tumin = tmax[i];
exit = Side.POSITIVE[i];
}
} else {
if (tmax[i] > tlmax) {
tlmax = tmax[i];
entry = Side.POSITIVE[i];
}
if (tmin[i] < tumin) {
tumin = tmin[i];
exit = Side.NEGATIVE[i];
}
}
}
if (tlmax >= tumin) return Optional.empty();
assert entry != null && exit != null;
return hit0(tlmax, tumin, entry, exit, ray, range);
}
private @NotNull Optional<HitResult> hit0(double tmin, double tmax, @NotNull Side entry, @NotNull Side exit, @NotNull Ray ray, @NotNull Range range) {
boolean frontFace;
double t;
if (range.surrounds(tmin)) {
frontFace = true;
t = tmin;
} else if (range.surrounds(tmax)) {
frontFace = false;
t = tmax;
} else {
return Optional.empty();
}
var side = frontFace ? entry : exit;
var normal = frontFace ? side.normal : side.normal.neg();
var position = ray.at(t);
var u = side.getTextureU(box, position);
var v = side.getTextureV(box, position);
return Optional.of(new HitResult(t, position, normal, material, u, v, frontFace));
}
@Override
public @NotNull AABB getBoundingBox() {
return box;
}
private enum Side {
NEG_X(Vec3.UNIT_X.neg()),
NEG_Y(Vec3.UNIT_Y.neg()),
NEG_Z(Vec3.UNIT_Z.neg()),
POS_X(Vec3.UNIT_X),
POS_Y(Vec3.UNIT_Y),
POS_Z(Vec3.UNIT_Z),
;
private static final Side[] NEGATIVE = new Side[] {Side.NEG_X, Side.NEG_Y, Side.NEG_Z};
private static final Side[] POSITIVE = new Side[] {Side.POS_X, Side.POS_Y, Side.POS_Z};
private final @NotNull Vec3 normal;
Side(@NotNull Vec3 normal) {
this.normal = Objects.requireNonNull(normal, "normal");
}
/**
* {@return the texture u coordinate for a position on this side of the box}
*/
public double getTextureU(@NotNull AABB box, @NotNull Vec3 pos) {
return switch (this) {
case NEG_X -> (pos.z() - box.min().z()) / (box.max().z() - box.min().z());
case POS_X -> (box.max().z() - pos.z()) / (box.max().z() - box.min().z());
case NEG_Y, POS_Y, POS_Z -> (pos.x() - box.min().x()) / (box.max().x() - box.min().x());
case NEG_Z -> (box.max().x() - pos.x()) / (box.max().x() - box.min().x());
};
}
/**
* {@return the texture v coordinate for a position on this side of the box}
*/
public double getTextureV(@NotNull AABB box, @NotNull Vec3 pos) {
return switch (this) {
case NEG_X, POS_X, NEG_Z, POS_Z -> (pos.y() - box.min().y()) / (box.max().y() - box.min().y());
case NEG_Y -> (pos.z() - box.min().z()) / (box.max().z() - box.min().z());
case POS_Y -> (box.max().z() - pos.z()) / (box.max().z() - box.min().z());
};
}
}
}

@ -1,35 +0,0 @@
package eu.jonahbauer.raytracing.scene.util;
import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.render.material.Material;
import eu.jonahbauer.raytracing.scene.Hittable;
import eu.jonahbauer.raytracing.scene.hittable2d.Parallelogram;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
public final class Hittables {
private Hittables() {
throw new UnsupportedOperationException();
}
public static @NotNull Hittable box(@NotNull Vec3 a, @NotNull Vec3 b, @NotNull Material material) {
var sides = new ArrayList<Hittable>();
var min = Vec3.min(a, b);
var max = Vec3.max(a, b);
var dx = new Vec3(max.x() - min.x(), 0, 0);
var dy = new Vec3(0, max.y() - min.y(), 0);
var dz = new Vec3(0, 0, max.z() - min.z());
sides.add(new Parallelogram(new Vec3(min.x(), min.y(), max.z()), dx, dy, material)); // front
sides.add(new Parallelogram(new Vec3(max.x(), min.y(), max.z()), dz.neg(), dy, material)); // right
sides.add(new Parallelogram(new Vec3(max.x(), min.y(), min.z()), dx.neg(), dy, material)); // back
sides.add(new Parallelogram(new Vec3(min.x(), min.y(), min.z()), dz, dy, material)); // left
sides.add(new Parallelogram(new Vec3(min.x(), max.y(), max.z()), dx, dz.neg(), material)); // top
sides.add(new Parallelogram(new Vec3(min.x(), min.y(), min.z()), dx, dz, material)); // bottom
return new HittableList(sides);
}
}
Loading…
Cancel
Save