allow multiple sampling targets in a scene
This commit is contained in:
parent
6e35453932
commit
ed9e50b8f2
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<? extends @NotNull Hittable> objects) {
|
||||
this(Color.BLACK, objects);
|
||||
this(objects, null);
|
||||
}
|
||||
|
||||
public Scene(@NotNull Color background, @NotNull List<? extends @NotNull Hittable> objects) {
|
||||
this(SkyBox.solid(background), objects);
|
||||
public Scene(@NotNull List<? extends @NotNull Hittable> objects, @Nullable List<? extends @NotNull Target> targets) {
|
||||
this(Color.BLACK, objects, targets);
|
||||
}
|
||||
|
||||
public Scene(@NotNull SkyBox background, @NotNull List<? extends @NotNull Hittable> objects) {
|
||||
this.objects = new HittableBinaryTree(objects);
|
||||
this(background, objects, null);
|
||||
}
|
||||
|
||||
public Scene(@NotNull SkyBox background, @NotNull List<? extends @NotNull Hittable> objects, @Nullable List<? extends @NotNull Target> targets) {
|
||||
var list = new ArrayList<Hittable>(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);
|
||||
|
||||
this.light = (Target) objects.get(1);
|
||||
}
|
||||
|
||||
public Scene(@NotNull Hittable @NotNull... objects) {
|
||||
this(List.of(objects));
|
||||
}
|
||||
|
||||
public Scene(@NotNull Color background, @NotNull Hittable @NotNull... objects) {
|
||||
this(background, List.of(objects));
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user