add sphere
parent
7875befa94
commit
590054a046
@ -0,0 +1,14 @@
|
||||
package eu.jonahbauer.raytracing.shape;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public sealed interface Shape permits Sphere {
|
||||
|
||||
/**
|
||||
* {@return the value <code>t</code> such that <code>ray.at(t)</code> is the intersection of this shaped closest to
|
||||
* the ray origin, or <code>Double.NaN</code> if the ray does not intersect this shape}
|
||||
* @param ray a ray
|
||||
*/
|
||||
double hit(@NotNull Ray ray);
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package eu.jonahbauer.raytracing.shape;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record Sphere(@NotNull Vec3 center, double radius) implements Shape {
|
||||
public static final @NotNull Sphere UNIT = new Sphere(Vec3.ZERO, 1.0);
|
||||
|
||||
public Sphere {
|
||||
Objects.requireNonNull(center, "center");
|
||||
if (radius <= 0 || !Double.isFinite(radius)) throw new IllegalArgumentException("radius must be positive");
|
||||
}
|
||||
|
||||
public Sphere(double x, double y, double z, double r) {
|
||||
this(new Vec3(x, y, z), r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double hit(@NotNull Ray ray) {
|
||||
var oc = ray.origin().minus(center());
|
||||
|
||||
var a = ray.direction().squared();
|
||||
var b = 2 * ray.direction().times(oc);
|
||||
var c = oc.squared() - radius * radius;
|
||||
|
||||
var discriminant = b * b - 4 * a * c;
|
||||
if (discriminant < 0) return Double.NaN;
|
||||
|
||||
var sd = Math.sqrt(discriminant);
|
||||
|
||||
double t = (- b - sd) / (2 * a);
|
||||
if (t < 0) t = (-b + sd) / (2 * a);
|
||||
if (t < 0) t = Double.NaN;
|
||||
return t;
|
||||
}
|
||||
|
||||
public @NotNull Sphere withCenter(@NotNull Vec3 center) {
|
||||
return new Sphere(center, radius);
|
||||
}
|
||||
|
||||
public @NotNull Sphere withCenter(double x, double y, double z) {
|
||||
return withCenter(new Vec3(x, y, z));
|
||||
}
|
||||
|
||||
public @NotNull Sphere withRadius(double radius) {
|
||||
return new Sphere(center, radius);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package eu.jonahbauer.raytracing.shape;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class SphereTest {
|
||||
|
||||
@Test
|
||||
void hit() {
|
||||
var center = new Vec3(1, 2, 3);
|
||||
var radius = 5;
|
||||
var sphere = new Sphere(center, radius);
|
||||
|
||||
var origin = new Vec3(6, 7, 8);
|
||||
var direction = new Vec3(-1, -1, -1);
|
||||
var ray = new Ray(origin, direction);
|
||||
|
||||
var t = sphere.hit(ray);
|
||||
assertFalse(Double.isNaN(t));
|
||||
assertEquals(center.plus(new Vec3(1, 1, 1).unit().times(radius)), ray.at(t));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue