diff --git a/src/main/java/eu/jonahbauer/raytracing/Examples.java b/src/main/java/eu/jonahbauer/raytracing/Examples.java index 3abab16..2ff235f 100644 --- a/src/main/java/eu/jonahbauer/raytracing/Examples.java +++ b/src/main/java/eu/jonahbauer/raytracing/Examples.java @@ -51,14 +51,13 @@ public class Examples { public static @NotNull Example getSimpleScene(int height) { if (height <= 0) height = 675; return new Example( - new Scene( - getSkyBox(), + new Scene(getSkyBox(), List.of( new Sphere(new Vec3(0, -100.5, -1.0), 100.0, new LambertianMaterial(new Color(0.8, 0.8, 0.0))), new Sphere(new Vec3(0, 0, -1.2), 0.5, new LambertianMaterial(new Color(0.1, 0.2, 0.5))), new Sphere(new Vec3(-1.0, 0, -1.2), 0.5, new DielectricMaterial(1.5)), new Sphere(new Vec3(-1.0, 0, -1.2), 0.4, new DielectricMaterial(1 / 1.5)), new Sphere(new Vec3(1.0, 0, -1.2), 0.5, new MetallicMaterial(new Color(0.8, 0.6, 0.2), 0.0)) - ), + )), SimpleCamera.builder() .withImage(height * 16 / 9, height) .build() @@ -119,14 +118,13 @@ public class Examples { public static @NotNull Example getSquares(int height) { if (height <= 0) height = 600; return new Example( - new Scene( - getSkyBox(), + new Scene(getSkyBox(), List.of( new Parallelogram(new Vec3(-3, -2, 5), new Vec3(0, 0, -4), new Vec3(0, 4, 0), new LambertianMaterial(new Color(1.0, 0.2, 0.2))), new Parallelogram(new Vec3(-2, -2, 0), new Vec3(4, 0, 0), new Vec3(0, 4, 0), new LambertianMaterial(new Color(0.2, 1.0, 0.2))), new Parallelogram(new Vec3(3, -2, 1), new Vec3(0, 0, 4), new Vec3(0, 4, 0), new LambertianMaterial(new Color(0.2, 0.2, 1.0))), new Parallelogram(new Vec3(-2, 3, 1), new Vec3(4, 0, 0), new Vec3(0, 0, 4), new LambertianMaterial(new Color(1.0, 0.5, 0.0))), new Parallelogram(new Vec3(-2, -3, 5), new Vec3(4, 0, 0), new Vec3(0, 0, -4), new LambertianMaterial(new Color(0.2, 0.8, 0.8))) - ), + )), SimpleCamera.builder() .withImage(height, height) .withFieldOfView(Math.toRadians(80)) @@ -139,12 +137,12 @@ public class Examples { public static @NotNull Example getLight(int height) { if (height <= 0) height = 225; return new Example( - new Scene( + new Scene(List.of( new Sphere(new Vec3(0, -1000, 0), 1000, new LambertianMaterial(new Color(0.2, 0.2, 0.2))), new Sphere(new Vec3(0, 2, 0), 2, new LambertianMaterial(new Color(0.2, 0.2, 0.2))), new Parallelogram(new Vec3(3, 1, -2), new Vec3(2, 0, 0), new Vec3(0, 2, 0), new DiffuseLight(new Color(4.0, 4.0, 4.0))), new Sphere(new Vec3(0, 7, 0), 2, new DiffuseLight(new Color(4.0, 4.0, 4.0))) - ), + )), SimpleCamera.builder() .withImage(height * 16 / 9, height) .withFieldOfView(Math.toRadians(20)) @@ -163,7 +161,7 @@ public class Examples { var light = new DiffuseLight(new Color(15.0, 15.0, 15.0)); return new Example( - new Scene( + new Scene(List.of( new Box( new AABB(new Vec3(0, 0, 0), new Vec3(555, 555, 555)), white, white, red, green, white, null @@ -171,7 +169,7 @@ public class Examples { new Parallelogram(new Vec3(343, 554, 332), new Vec3(-130, 0, 0), new Vec3(0, 0, -105), light), new 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, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65)) - ), + )), SimpleCamera.builder() .withImage(height, height) .withFieldOfView(Math.toRadians(40)) @@ -189,7 +187,7 @@ public class Examples { var light = new DiffuseLight(new Color(7.0, 7.0, 7.0)); return new Example( - new Scene( + new Scene(List.of( new Box( new AABB(new Vec3(0, 0, 0), new Vec3(555, 555, 555)), white, white, red, green, white, null @@ -203,7 +201,7 @@ public class Examples { 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) ) - ), + )), SimpleCamera.builder() .withImage(height, height) .withFieldOfView(Math.toRadians(40)) @@ -223,19 +221,19 @@ public class Examples { var aluminum = new MetallicMaterial(new Color(0.8, 0.85, 0.88)); var glass = new DielectricMaterial(1.5); + var room = new Box( + new AABB(new Vec3(0, 0, 0), new Vec3(555, 555, 555)), + white, white, red, green, white, null + ); + var lamp = new Parallelogram(new Vec3(343, 554, 332), new Vec3(-130, 0, 0), new Vec3(0, 0, -105), light); + var box = new Box( + new AABB(new Vec3(0, 0, 0), new Vec3(165, 330, 165)), + white, white, white, white, white, aluminum + ).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)); + var sphere = new Sphere(new Vec3(190, 90, 190), 90, glass); + return new Example( - new Scene( - new Box( - new AABB(new Vec3(0, 0, 0), new Vec3(555, 555, 555)), - white, white, red, green, white, null - ), - new Parallelogram(new Vec3(343, 554, 332), new Vec3(-130, 0, 0), new Vec3(0, 0, -105), light), - new Box( - new AABB(new Vec3(0, 0, 0), new Vec3(165, 330, 165)), - white, white, white, white, white, aluminum - ).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)), - new Sphere(new Vec3(190, 90, 190), 90, glass) - ), + new Scene(List.of(room, box), List.of(lamp, sphere)), SimpleCamera.builder() .withImage(height, height) .withFieldOfView(Math.toRadians(40)) @@ -297,10 +295,9 @@ public class Examples { if (height <= 0) height = 450; return new Example( - new Scene( - getSkyBox(), + new Scene(getSkyBox(), List.of( new Sphere(Vec3.ZERO, 2, new LambertianMaterial(new ImageTexture("/earthmap.jpg"))) - ), + )), SimpleCamera.builder() .withImage(height * 16 / 9, height) .withFieldOfView(Math.toRadians(20)) @@ -316,11 +313,10 @@ public class Examples { var material = new LambertianMaterial(new PerlinTexture(4)); return new Example( - new Scene( - getSkyBox(), + new Scene(getSkyBox(), List.of( new Sphere(new Vec3(0, -1000, 0), 1000, material), new Sphere(new Vec3(0, 2, 0), 2, material) - ), + )), SimpleCamera.builder() .withImage(height * 16 / 9, height) .withFieldOfView(Math.toRadians(20)) diff --git a/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java b/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java index b3e8e35..e7bb9a2 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/renderer/SimpleRenderer.java @@ -170,7 +170,7 @@ public final class SimpleRenderer implements Renderer { } } case Material.PdfScatterResult(var a, var pdf) -> { - if (scene.getLights() == null) { + if (scene.getTargets() == null) { attenuation = Color.multiply(attenuation, a); ray = new Ray(hit.position(), pdf.generate(random)); @@ -178,7 +178,7 @@ public final class SimpleRenderer implements Renderer { System.out.println(" Pdf scattering with albedo " + a); } } else { - var mixed = new MixtureProbabilityDensityFunction(new TargetingProbabilityDensityFunction(hit.position(), scene.getLights()), pdf, 0.5); + var mixed = new MixtureProbabilityDensityFunction(new TargetingProbabilityDensityFunction(hit.position(), scene.getTargets()), pdf, 0.5); var direction = mixed.generate(random); var idealPdf = pdf.value(direction); @@ -194,7 +194,6 @@ public final class SimpleRenderer implements Renderer { System.out.println(" Pdf scattering with albedo " + a + " and factor " + factor); } } - } } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/TargetingProbabilityDensityFunction.java b/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/TargetingProbabilityDensityFunction.java index 898347b..d63f51b 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/TargetingProbabilityDensityFunction.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/renderer/pdf/TargetingProbabilityDensityFunction.java @@ -4,25 +4,33 @@ import eu.jonahbauer.raytracing.math.Vec3; import eu.jonahbauer.raytracing.scene.Target; import org.jetbrains.annotations.NotNull; +import java.util.List; import java.util.Objects; import java.util.random.RandomGenerator; /** * A probability density function targeting a target. */ -public record TargetingProbabilityDensityFunction(@NotNull Vec3 origin, @NotNull Target target) implements ProbabilityDensityFunction { +public record TargetingProbabilityDensityFunction(@NotNull Vec3 origin, @NotNull List<@NotNull Target> targets) implements ProbabilityDensityFunction { public TargetingProbabilityDensityFunction { Objects.requireNonNull(origin, "origin"); - Objects.requireNonNull(target, "target"); + targets = List.copyOf(targets); } @Override public double value(@NotNull Vec3 direction) { - return target.getProbabilityDensity(origin, direction); + var weight = 1d / targets.size(); + var sum = 0.0; + + for (var target : targets) { + sum += weight * target.getProbabilityDensity(origin, direction); + } + + return sum; } @Override public @NotNull Vec3 generate(@NotNull RandomGenerator random) { - return target.getTargetingDirection(origin, random); + return targets.get(random.nextInt(targets.size())).getTargetingDirection(origin, random); } } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java b/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java index 511d72f..b7d1672 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java @@ -1,13 +1,15 @@ package eu.jonahbauer.raytracing.render.texture; +import eu.jonahbauer.raytracing.math.Ray; import eu.jonahbauer.raytracing.math.Vec3; +import eu.jonahbauer.raytracing.scene.SkyBox; import org.jetbrains.annotations.NotNull; import java.util.Random; import static eu.jonahbauer.raytracing.Main.DEBUG; -public record Color(double r, double g, double b) implements Texture { +public record Color(double r, double g, double b) implements Texture, SkyBox { public static final @NotNull Color BLACK = new Color(0.0, 0.0, 0.0); public static final @NotNull Color WHITE = new Color(1.0, 1.0, 1.0); public static final @NotNull Color RED = new Color(1.0, 0.0, 0.0); @@ -112,6 +114,11 @@ public record Color(double r, double g, double b) implements Texture { return this; } + @Override + public @NotNull Color getColor(@NotNull Ray ray) { + return this; + } + @Override public boolean isUVRequired() { return false; diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java b/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java index 5517aff..c3b456c 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/Scene.java @@ -8,6 +8,7 @@ import eu.jonahbauer.raytracing.scene.util.HittableCollection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -15,33 +16,28 @@ public final class Scene extends HittableCollection { private final @NotNull HittableCollection objects; private final @NotNull SkyBox background; - private final @Nullable Target light; + private final @Nullable List<@NotNull Target> targets; public Scene(@NotNull List objects) { - this(Color.BLACK, objects); + this(objects, null); } - public Scene(@NotNull Color background, @NotNull List objects) { - this(SkyBox.solid(background), objects); + public Scene(@NotNull List objects, @Nullable List targets) { + this(Color.BLACK, objects, targets); } public Scene(@NotNull SkyBox background, @NotNull List objects) { - this.objects = new HittableBinaryTree(objects); - this.background = Objects.requireNonNull(background); - - this.light = (Target) objects.get(1); - } - - public Scene(@NotNull Hittable @NotNull... objects) { - this(List.of(objects)); + this(background, objects, null); } - public Scene(@NotNull Color background, @NotNull Hittable @NotNull... objects) { - this(background, List.of(objects)); - } + public Scene(@NotNull SkyBox background, @NotNull List objects, @Nullable List targets) { + var list = new ArrayList(objects.size() + (targets != null ? targets.size() : 0)); + list.addAll(objects); + if (targets != null) list.addAll(targets); + this.objects = new HittableBinaryTree(list); + this.background = Objects.requireNonNull(background); - public Scene(@NotNull SkyBox background, @NotNull Hittable @NotNull... objects) { - this(background, List.of(objects)); + this.targets = targets != null ? List.copyOf(targets) : null; } @Override @@ -54,8 +50,8 @@ public final class Scene extends HittableCollection { return objects.getBoundingBox(); } - public @Nullable Target getLights() { - return light; + public @Nullable List<@NotNull Target> getTargets() { + return targets; } public @NotNull Color getBackgroundColor(@NotNull Ray ray) { diff --git a/src/main/java/eu/jonahbauer/raytracing/scene/SkyBox.java b/src/main/java/eu/jonahbauer/raytracing/scene/SkyBox.java index 58cbf8e..ee22d30 100644 --- a/src/main/java/eu/jonahbauer/raytracing/scene/SkyBox.java +++ b/src/main/java/eu/jonahbauer/raytracing/scene/SkyBox.java @@ -18,8 +18,4 @@ public interface SkyBox { return Color.lerp(bottom, top, alt / Math.PI + 0.5); }; } - - static @NotNull SkyBox solid(@NotNull Color color) { - return _ -> color; - } }