add transforms

main
jbb01 6 months ago
parent 27e3fc0990
commit 580d8eca12

@ -138,8 +138,8 @@ public class Main {
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(130, 0, 65), new Vec3(295, 165, 230), white),
Hittables.box(new Vec3(265, 0, 295), new Vec3(430, 330, 460), 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))
),
SimpleCamera.builder()
.withImage(600, 600)

@ -3,6 +3,9 @@ package eu.jonahbauer.raytracing.scene;
import eu.jonahbauer.raytracing.math.BoundingBox;
import eu.jonahbauer.raytracing.math.Range;
import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.scene.transform.RotateY;
import eu.jonahbauer.raytracing.scene.transform.Translate;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
@ -19,4 +22,12 @@ public interface Hittable {
default @NotNull Optional<BoundingBox> getBoundingBox() {
return Optional.empty();
}
default @NotNull Hittable translate(@NotNull Vec3 offset) {
return new Translate(this, offset);
}
default @NotNull Hittable rotateY(double angle) {
return new RotateY(this, angle);
}
}

@ -0,0 +1,91 @@
package eu.jonahbauer.raytracing.scene.transform;
import eu.jonahbauer.raytracing.math.BoundingBox;
import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.scene.HitResult;
import eu.jonahbauer.raytracing.scene.Hittable;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public final class RotateY extends Transform {
private final double cos;
private final double sin;
private final @NotNull Optional<BoundingBox> bbox;
public RotateY(@NotNull Hittable object, double angle) {
super(object);
this.cos = Math.cos(angle);
this.sin = Math.sin(angle);
this.bbox = object.getBoundingBox().map(bbox -> {
var min = new Vec3(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
var max = new Vec3(- Double.MAX_VALUE, - Double.MAX_VALUE, - Double.MAX_VALUE);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
var x = i * bbox.max().x() + (1 - i) * bbox.min().x();
var y = j * bbox.max().y() + (1 - j) * bbox.min().y();
var z = k * bbox.max().z() + (1 - k) * bbox.min().z();
var newx = cos * x + sin * z;
var newz = -sin * x + cos * z;
var temp = new Vec3(newx, y, newz);
min = Vec3.min(min, temp);
max = Vec3.max(max, temp);
}
}
}
return new BoundingBox(min, max);
});
}
@Override
protected @NotNull Ray transform(@NotNull Ray ray) {
var origin = ray.origin();
var direction = ray.direction();
var newOrigin = new Vec3(
cos * origin.x() - sin * origin.z(),
origin.y(),
sin * origin.x() + cos * origin.z()
);
var newDirection = new Vec3(
cos * direction.x() - sin * direction.z(),
direction.y(),
sin * direction.x() + cos * direction.z()
);
return new Ray(newOrigin, newDirection);
}
@Override
protected @NotNull HitResult transform(@NotNull HitResult result) {
var position = result.position();
var newPosition = new Vec3(
cos * position.x() + sin * position.z(),
position.y(),
- sin * position.x() + cos * position.z()
);
var normal = result.normal();
var newNormal = new Vec3(
cos * normal.x() + sin * normal.z(),
normal.y(),
-sin * normal.x() + cos * normal.z()
);
return new HitResult(result.t(), newPosition, newNormal, result.material(), result.frontFace());
}
@Override
public @NotNull Optional<BoundingBox> getBoundingBox() {
return bbox;
}
}

@ -0,0 +1,27 @@
package eu.jonahbauer.raytracing.scene.transform;
import eu.jonahbauer.raytracing.math.Range;
import eu.jonahbauer.raytracing.math.Ray;
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 abstract class Transform implements Hittable {
protected final @NotNull Hittable object;
protected Transform(@NotNull Hittable object) {
this.object = Objects.requireNonNull(object);
}
protected abstract @NotNull Ray transform(@NotNull Ray ray);
protected abstract @NotNull HitResult transform(@NotNull HitResult result);
@Override
public final @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
return object.hit(transform(ray), range).map(this::transform);
}
}

@ -0,0 +1,46 @@
package eu.jonahbauer.raytracing.scene.transform;
import eu.jonahbauer.raytracing.math.BoundingBox;
import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.math.Vec3;
import eu.jonahbauer.raytracing.scene.HitResult;
import eu.jonahbauer.raytracing.scene.Hittable;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public final class Translate extends Transform {
private final @NotNull Vec3 offset;
private final @NotNull Optional<BoundingBox> bbox;
public Translate(@NotNull Hittable object, @NotNull Vec3 offset) {
super(object);
this.offset = offset;
this.bbox = object.getBoundingBox().map(bbox -> new BoundingBox(
bbox.min().plus(offset),
bbox.max().plus(offset)
));
}
@Override
protected @NotNull Ray transform(@NotNull Ray ray) {
return new Ray(ray.origin().minus(offset), ray.direction());
}
@Override
protected @NotNull HitResult transform(@NotNull HitResult result) {
return new HitResult(
result.t(),
result.position().plus(offset),
result.normal(),
result.material(),
result.frontFace()
);
}
@Override
public @NotNull Optional<BoundingBox> getBoundingBox() {
return bbox;
}
}
Loading…
Cancel
Save