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