improve performance of boxes
parent
1d48a49987
commit
18c179f8e3
@ -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…
Reference in New Issue