diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java b/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java index c452e09..6813920 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java @@ -22,7 +22,7 @@ public record DielectricMaterial(double refractionIndex, @NotNull Texture textur @Override public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { - var ri = hit.frontFace() ? (1 / refractionIndex) : refractionIndex; + var ri = hit.isFrontFace() ? (1 / refractionIndex) : refractionIndex; var cosTheta = Math.min(- ray.direction().unit().times(hit.normal()), 1.0); var reflectance = reflectance(cosTheta); diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/DirectionalMaterial.java b/src/main/java/eu/jonahbauer/raytracing/render/material/DirectionalMaterial.java new file mode 100644 index 0000000..05c04ba --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/DirectionalMaterial.java @@ -0,0 +1,67 @@ +package eu.jonahbauer.raytracing.render.material; + +import eu.jonahbauer.raytracing.math.Ray; +import eu.jonahbauer.raytracing.math.Vec3; +import eu.jonahbauer.raytracing.render.texture.Color; +import eu.jonahbauer.raytracing.render.texture.Texture; +import eu.jonahbauer.raytracing.scene.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.random.RandomGenerator; + +public final class DirectionalMaterial implements Material { + private final @Nullable Material front; + private final @Nullable Material back; + + private final @NotNull Texture texture; + + public DirectionalMaterial(@Nullable Material front, @Nullable Material back) { + this.front = front; + this.back = back; + this.texture = new DirectionalTexture( + front != null ? front.texture() : null, + back != null ? back.texture() : null + ); + } + + @Override + public @NotNull Texture texture() { + return texture; + } + + @Override + public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { + if (hit.isFrontFace()) { + if (front != null) return front.scatter(ray, hit, random); + } else { + if (back != null) return back.scatter(ray, hit, random); + } + // let the ray pass through without obstruction + return Optional.of(new ScatterResult(new Ray(ray.at(hit.t()), ray.direction()), Color.WHITE)); + } + + @Override + public @NotNull Color emitted(@NotNull HitResult hit) { + if (hit.isFrontFace()) { + if (front != null) return front.emitted(hit); + } else { + if (back != null) return back.emitted(hit); + } + return Color.BLACK; + } + + private record DirectionalTexture(@Nullable Texture front, @Nullable Texture back) implements Texture { + + @Override + public @NotNull Color get(double u, double v, @NotNull Vec3 p) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isUVRequired() { + return front() != null && front().isUVRequired() || back() != null && back().isUVRequired(); + } + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/HitResult.java b/src/main/java/eu/jonahbauer/raytracing/scene/HitResult.java index c4a82a5..1483782 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/HitResult.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/HitResult.java @@ -8,7 +8,7 @@ import java.util.Objects; public record HitResult( double t, @NotNull Vec3 position, @NotNull Vec3 normal, - @NotNull Material material, double u, double v, boolean frontFace + @NotNull Material material, double u, double v, boolean isFrontFace ) implements Comparable { public HitResult { Objects.requireNonNull(position, "position"); @@ -16,7 +16,7 @@ public record HitResult( } public @NotNull HitResult withPositionAndNormal(@NotNull Vec3 position, @NotNull Vec3 normal) { - return new HitResult(t, position, normal, material, u, v, frontFace); + return new HitResult(t, position, normal, material, u, v, isFrontFace); } @Override diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java index 3c03d8a..bf104a4 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/hittable3d/ConstantMedium.java @@ -32,7 +32,7 @@ public record ConstantMedium(@NotNull Hittable boundary, double density, @NotNul if (hitDistance > distance) return Optional.empty(); var t = tmin + hitDistance / length; - return Optional.of(new HitResult(t, ray.at(t), Vec3.UNIT_X, material, 0, 0, true)); // arbitrary normal and frontFace + return Optional.of(new HitResult(t, ray.at(t), Vec3.UNIT_X, material, 0, 0, true)); // arbitrary normal, u, v and isFrontFace } @Override