add shading according to normal vector

main
jbb01 6 months ago
parent 590054a046
commit 14fd1d73fc

@ -4,7 +4,9 @@ import eu.jonahbauer.raytracing.math.Ray;
import eu.jonahbauer.raytracing.shape.Shape; import eu.jonahbauer.raytracing.shape.Shape;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional;
public record Scene(@NotNull List<@NotNull Shape> shapes) { public record Scene(@NotNull List<@NotNull Shape> shapes) {
@ -25,11 +27,17 @@ public record Scene(@NotNull List<@NotNull Shape> shapes) {
var ray = pixel.ray(); var ray = pixel.ray();
var result = shapes.stream() var result = shapes.stream()
.mapToDouble(shape -> shape.hit(ray)) .map(shape -> shape.hit(ray))
.filter(Double::isFinite) .flatMap(Optional::stream)
.min(); .min(Comparator.naturalOrder());
if (result.isPresent()) { if (result.isPresent()) {
image.set(x, y, Color.RED); var normal = result.get().normal();
image.set(x, y, new Color(
0.5 * (normal.x() + 1),
0.5 * (normal.y() + 1),
0.5 * (normal.z() + 1)
));
} else { } else {
image.set(x, y, getSkyboxColor(ray)); image.set(x, y, getSkyboxColor(ray));
} }

@ -0,0 +1,16 @@
package eu.jonahbauer.raytracing.shape;
import eu.jonahbauer.raytracing.math.Vec3;
import org.jetbrains.annotations.NotNull;
public record HitResult(double t, @NotNull Vec3 normal) implements Comparable<HitResult> {
public HitResult {
if (t < 0 || !Double.isFinite(t)) throw new IllegalArgumentException("t must be non-negative");
normal = normal.unit();
}
@Override
public int compareTo(@NotNull HitResult o) {
return Double.compare(t, o.t);
}
}

@ -3,6 +3,8 @@ package eu.jonahbauer.raytracing.shape;
import eu.jonahbauer.raytracing.math.Ray; import eu.jonahbauer.raytracing.math.Ray;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public sealed interface Shape permits Sphere { public sealed interface Shape permits Sphere {
/** /**
@ -10,5 +12,5 @@ public sealed interface Shape permits Sphere {
* the ray origin, or <code>Double.NaN</code> if the ray does not intersect this shape} * the ray origin, or <code>Double.NaN</code> if the ray does not intersect this shape}
* @param ray a ray * @param ray a ray
*/ */
double hit(@NotNull Ray ray); @NotNull Optional<HitResult> hit(@NotNull Ray ray);
} }

@ -5,6 +5,7 @@ import eu.jonahbauer.raytracing.math.Vec3;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
public record Sphere(@NotNull Vec3 center, double radius) implements Shape { public record Sphere(@NotNull Vec3 center, double radius) implements Shape {
public static final @NotNull Sphere UNIT = new Sphere(Vec3.ZERO, 1.0); public static final @NotNull Sphere UNIT = new Sphere(Vec3.ZERO, 1.0);
@ -19,7 +20,7 @@ public record Sphere(@NotNull Vec3 center, double radius) implements Shape {
} }
@Override @Override
public double hit(@NotNull Ray ray) { public @NotNull Optional<HitResult> hit(@NotNull Ray ray) {
var oc = ray.origin().minus(center()); var oc = ray.origin().minus(center());
var a = ray.direction().squared(); var a = ray.direction().squared();
@ -27,14 +28,14 @@ public record Sphere(@NotNull Vec3 center, double radius) implements Shape {
var c = oc.squared() - radius * radius; var c = oc.squared() - radius * radius;
var discriminant = b * b - 4 * a * c; var discriminant = b * b - 4 * a * c;
if (discriminant < 0) return Double.NaN; if (discriminant < 0) return Optional.empty();
var sd = Math.sqrt(discriminant); var sd = Math.sqrt(discriminant);
double t = (- b - sd) / (2 * a); double t = (- b - sd) / (2 * a);
if (t < 0) t = (-b + sd) / (2 * a); if (t < 0) t = (-b + sd) / (2 * a);
if (t < 0) t = Double.NaN; if (t < 0) return Optional.empty();
return t; return Optional.of(new HitResult(t, ray.at(t).minus(center)));
} }
public @NotNull Sphere withCenter(@NotNull Vec3 center) { public @NotNull Sphere withCenter(@NotNull Vec3 center) {

@ -18,8 +18,8 @@ class SphereTest {
var direction = new Vec3(-1, -1, -1); var direction = new Vec3(-1, -1, -1);
var ray = new Ray(origin, direction); var ray = new Ray(origin, direction);
var t = sphere.hit(ray); var result = sphere.hit(ray);
assertFalse(Double.isNaN(t)); assertFalse(result.isEmpty());
assertEquals(center.plus(new Vec3(1, 1, 1).unit().times(radius)), ray.at(t)); assertEquals(center.plus(new Vec3(1, 1, 1).unit().times(radius)), ray.at(result.get().t()));
} }
} }
Loading…
Cancel
Save