improve performance of boxes
This commit is contained in:
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.Scene;
|
||||||
import eu.jonahbauer.raytracing.scene.SkyBox;
|
import eu.jonahbauer.raytracing.scene.SkyBox;
|
||||||
import eu.jonahbauer.raytracing.scene.hittable2d.Parallelogram;
|
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.ConstantMedium;
|
||||||
import eu.jonahbauer.raytracing.scene.hittable3d.Sphere;
|
import eu.jonahbauer.raytracing.scene.hittable3d.Sphere;
|
||||||
import eu.jonahbauer.raytracing.scene.util.Hittables;
|
|
||||||
import eu.jonahbauer.raytracing.scene.util.HittableBinaryTree;
|
import eu.jonahbauer.raytracing.scene.util.HittableBinaryTree;
|
||||||
import org.jetbrains.annotations.NotNull;
|
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(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(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 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)),
|
new 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, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65))
|
||||||
),
|
),
|
||||||
SimpleCamera.builder()
|
SimpleCamera.builder()
|
||||||
.withImage(height, height)
|
.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(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 Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0, 0), new Vec3(0, 555, 0), white),
|
||||||
new ConstantMedium(
|
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)
|
0.01, new IsotropicMaterial(Color.BLACK)
|
||||||
),
|
),
|
||||||
new ConstantMedium(
|
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)
|
0.01, new IsotropicMaterial(Color.WHITE)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@ -243,7 +243,7 @@ public class Examples {
|
|||||||
|
|
||||||
for (int i = 0; i < data.size(); i++) {
|
for (int i = 0; i < data.size(); i++) {
|
||||||
var partei = data.get(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 * size, 0, spacing),
|
||||||
new Vec3((i + 1) * spacing + (i + 1) * size, partei.stimmen() * 15, spacing + size),
|
new Vec3((i + 1) * spacing + (i + 1) * size, partei.stimmen() * 15, spacing + size),
|
||||||
new DielectricMaterial(1.5, partei.color())
|
new DielectricMaterial(1.5, partei.color())
|
||||||
@ -316,7 +316,7 @@ public class Examples {
|
|||||||
var x1 = x0 + w;
|
var x1 = x0 + w;
|
||||||
var y1 = random.nextInt(1, 101);
|
var y1 = random.nextInt(1, 101);
|
||||||
var z1 = z0 + w;
|
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));
|
objects.add(new HittableBinaryTree(boxes));
|
||||||
|
@ -2,7 +2,6 @@ package eu.jonahbauer.raytracing.math;
|
|||||||
|
|
||||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -57,10 +56,6 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hit(@NotNull Ray ray) {
|
public boolean hit(@NotNull Ray ray) {
|
||||||
return intersect(ray) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable Range intersect(@NotNull Ray ray) {
|
|
||||||
var origin = ray.origin();
|
var origin = ray.origin();
|
||||||
var direction = ray.direction();
|
var direction = ray.direction();
|
||||||
var invDirection = direction.inv();
|
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
|
// determine range of t for which the ray is inside this voxel
|
||||||
double tlmax = Double.NEGATIVE_INFINITY; // lower limit maximum
|
double tlmax = Double.NEGATIVE_INFINITY; // lower limit maximum
|
||||||
double tumin = Double.POSITIVE_INFINITY; // upper limit minimum
|
double tumin = Double.POSITIVE_INFINITY; // upper limit minimum
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
// classify t values as lower or upper limit based on ray direction
|
// classify t values as lower or upper limit based on ray direction
|
||||||
if (direction.get(i) >= 0) {
|
if (direction.get(i) >= 0) {
|
||||||
// min is lower limit and max is upper limit
|
// min is lower limit and max is upper limit
|
||||||
if (tmin[i] > tlmax) {
|
if (tmin[i] > tlmax) tlmax = tmin[i];
|
||||||
tlmax = tmin[i];
|
if (tmax[i] < tumin) tumin = tmax[i];
|
||||||
}
|
|
||||||
if (tmax[i] < tumin) {
|
|
||||||
tumin = tmax[i];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// max is lower limit and min is upper limit
|
// max is lower limit and min is upper limit
|
||||||
if (tmax[i] > tlmax) {
|
if (tmax[i] > tlmax) tlmax = tmax[i];
|
||||||
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;
|
return tlmax < tumin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Ray ray) {
|
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Vec3 origin, @NotNull Vec3 invDirection) {
|
||||||
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[] {
|
return new double[] {
|
||||||
(corner.x() - origin.x()) * invDirection.x(),
|
(corner.x() - origin.x()) * invDirection.x(),
|
||||||
(corner.y() - origin.y()) * invDirection.y(),
|
(corner.y() - origin.y()) * invDirection.y(),
|
||||||
|
136
src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java
Normal file
136
src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/Box.java
Normal file
@ -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…
x
Reference in New Issue
Block a user