|
|
@ -5,11 +5,14 @@ import eu.jonahbauer.raytracing.render.Color;
|
|
|
|
import eu.jonahbauer.raytracing.render.ImageFormat;
|
|
|
|
import eu.jonahbauer.raytracing.render.ImageFormat;
|
|
|
|
import eu.jonahbauer.raytracing.render.camera.Camera;
|
|
|
|
import eu.jonahbauer.raytracing.render.camera.Camera;
|
|
|
|
import eu.jonahbauer.raytracing.render.camera.SimpleCamera;
|
|
|
|
import eu.jonahbauer.raytracing.render.camera.SimpleCamera;
|
|
|
|
|
|
|
|
import eu.jonahbauer.raytracing.render.canvas.Canvas;
|
|
|
|
import eu.jonahbauer.raytracing.render.canvas.Image;
|
|
|
|
import eu.jonahbauer.raytracing.render.canvas.Image;
|
|
|
|
import eu.jonahbauer.raytracing.render.canvas.LiveCanvas;
|
|
|
|
import eu.jonahbauer.raytracing.render.canvas.LiveCanvas;
|
|
|
|
import eu.jonahbauer.raytracing.render.material.*;
|
|
|
|
import eu.jonahbauer.raytracing.render.material.*;
|
|
|
|
import eu.jonahbauer.raytracing.render.renderer.SimpleRenderer;
|
|
|
|
import eu.jonahbauer.raytracing.render.renderer.SimpleRenderer;
|
|
|
|
import eu.jonahbauer.raytracing.scene.*;
|
|
|
|
import eu.jonahbauer.raytracing.scene.Hittable;
|
|
|
|
|
|
|
|
import eu.jonahbauer.raytracing.scene.Scene;
|
|
|
|
|
|
|
|
import eu.jonahbauer.raytracing.scene.SkyBox;
|
|
|
|
import eu.jonahbauer.raytracing.scene.hittable2d.Parallelogram;
|
|
|
|
import eu.jonahbauer.raytracing.scene.hittable2d.Parallelogram;
|
|
|
|
import eu.jonahbauer.raytracing.scene.hittable3d.ConstantMedium;
|
|
|
|
import eu.jonahbauer.raytracing.scene.hittable3d.ConstantMedium;
|
|
|
|
import eu.jonahbauer.raytracing.scene.hittable3d.Sphere;
|
|
|
|
import eu.jonahbauer.raytracing.scene.hittable3d.Sphere;
|
|
|
@ -17,185 +20,287 @@ import eu.jonahbauer.raytracing.scene.util.Hittables;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
import java.nio.file.InvalidPathException;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Random;
|
|
|
|
import java.util.Random;
|
|
|
|
|
|
|
|
import java.util.function.IntFunction;
|
|
|
|
|
|
|
|
|
|
|
|
public class Main {
|
|
|
|
public class Main {
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
|
var example = getCornellBoxSmoke();
|
|
|
|
var config = Config.parse(args);
|
|
|
|
|
|
|
|
var example = config.example;
|
|
|
|
var scene = example.scene();
|
|
|
|
var scene = example.scene();
|
|
|
|
var camera = example.camera();
|
|
|
|
var camera = example.camera();
|
|
|
|
|
|
|
|
|
|
|
|
var renderer = SimpleRenderer.builder()
|
|
|
|
var renderer = SimpleRenderer.builder()
|
|
|
|
.withSamplesPerPixel(1000)
|
|
|
|
.withSamplesPerPixel(config.samples)
|
|
|
|
.withMaxDepth(50)
|
|
|
|
.withMaxDepth(config.depth)
|
|
|
|
.withIterative(true)
|
|
|
|
.withIterative(config.iterative)
|
|
|
|
.build();
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
var image = new LiveCanvas(new Image(camera.getWidth(), camera.getHeight()));
|
|
|
|
Canvas canvas;
|
|
|
|
image.preview();
|
|
|
|
if (config.preview) {
|
|
|
|
|
|
|
|
var image = new LiveCanvas(new Image(camera.getWidth(), camera.getHeight()));
|
|
|
|
|
|
|
|
image.preview();
|
|
|
|
|
|
|
|
canvas = image;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
canvas = new Image(camera.getWidth(), camera.getHeight());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
long time = System.nanoTime();
|
|
|
|
long time = System.nanoTime();
|
|
|
|
renderer.render(camera, scene, image);
|
|
|
|
renderer.render(camera, scene, canvas);
|
|
|
|
System.out.printf("rendering finished after %dms", (System.nanoTime() - time) / 1_000_000);
|
|
|
|
System.out.printf("rendering finished after %dms", (System.nanoTime() - time) / 1_000_000);
|
|
|
|
|
|
|
|
|
|
|
|
ImageFormat.PNG.write(image, Path.of("scene-" + System.currentTimeMillis() + ".png"));
|
|
|
|
ImageFormat.PNG.write(canvas, config.path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull Example getSpheres() {
|
|
|
|
private record Config(@NotNull Example example, @NotNull Path path, boolean preview, boolean iterative, int samples, int depth) {
|
|
|
|
var rng = new Random(1);
|
|
|
|
|
|
|
|
var objects = new ArrayList<Hittable>();
|
|
|
|
|
|
|
|
objects.add(new Sphere(new Vec3(0, -1000, 0), 1000, new LambertianMaterial(new Color(0.5, 0.5, 0.5))));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int a = -11; a < 11; a++) {
|
|
|
|
|
|
|
|
for (int b = -11; b < 11; b++) {
|
|
|
|
|
|
|
|
var center = new Vec3(a + 0.9 * rng.nextDouble(), 0.2, b + 0.9 * rng.nextDouble());
|
|
|
|
|
|
|
|
if (Vec3.distance(center, new Vec3(4, 0.2, 0)) <= 0.9) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Material material;
|
|
|
|
|
|
|
|
var rnd = rng.nextDouble();
|
|
|
|
|
|
|
|
if (rnd < 0.8) {
|
|
|
|
|
|
|
|
// diffuse
|
|
|
|
|
|
|
|
var albedo = Color.multiply(Color.random(rng), Color.random(rng));
|
|
|
|
|
|
|
|
material = new LambertianMaterial(albedo);
|
|
|
|
|
|
|
|
} else if (rnd < 0.95) {
|
|
|
|
|
|
|
|
// metal
|
|
|
|
|
|
|
|
var albedo = Color.random(rng, 0.5, 1.0);
|
|
|
|
|
|
|
|
var fuzz = rng.nextDouble() * 0.5;
|
|
|
|
|
|
|
|
material = new MetallicMaterial(albedo, fuzz);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// glass
|
|
|
|
|
|
|
|
material = new DielectricMaterial(1.5);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
objects.add(new Sphere(center, 0.2, material));
|
|
|
|
public static @NotNull Config parse(@NotNull String @NotNull[] args) {
|
|
|
|
|
|
|
|
IntFunction<Example> example = null;
|
|
|
|
|
|
|
|
Path path = null;
|
|
|
|
|
|
|
|
boolean preview = true;
|
|
|
|
|
|
|
|
boolean iterative = false;
|
|
|
|
|
|
|
|
int samples = 1000;
|
|
|
|
|
|
|
|
int depth = 50;
|
|
|
|
|
|
|
|
int height = -1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < args.length; i++) {
|
|
|
|
|
|
|
|
switch (args[i]) {
|
|
|
|
|
|
|
|
case "--output" -> {
|
|
|
|
|
|
|
|
if (i + 1 == args.length) throw fail("missing value for parameter --output");
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
path = Path.of(args[++i]);
|
|
|
|
|
|
|
|
} catch (InvalidPathException ex) {
|
|
|
|
|
|
|
|
throw fail("value " + args[i] + " is not a valid path");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case "--preview" -> preview = true;
|
|
|
|
|
|
|
|
case "--no-preview" -> preview = false;
|
|
|
|
|
|
|
|
case "--iterative" -> iterative = true;
|
|
|
|
|
|
|
|
case "--no-iterative" -> iterative = false;
|
|
|
|
|
|
|
|
case "--samples" -> {
|
|
|
|
|
|
|
|
if (i + 1 == args.length) throw fail("missing value for parameter --samples");
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
samples = Integer.parseInt(args[++i]);
|
|
|
|
|
|
|
|
if (samples <= 0) throw fail("samples must be positive");
|
|
|
|
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
|
|
|
|
throw fail("value " + args[i] + " is not a valid integer");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case "--depth" -> {
|
|
|
|
|
|
|
|
if (i + 1 == args.length) throw fail("missing value for parameter --depth");
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
depth = Integer.parseInt(args[++i]);
|
|
|
|
|
|
|
|
if (depth <= 0) throw fail("depth must be positive");
|
|
|
|
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
|
|
|
|
throw fail("value " + args[i] + " is not a valid integer");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case "--height" -> {
|
|
|
|
|
|
|
|
if (i + 1 == args.length) throw fail("missing value for parameter --height");
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
height = Integer.parseInt(args[++i]);
|
|
|
|
|
|
|
|
if (height <= 0) throw fail("height must be positive");
|
|
|
|
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
|
|
|
|
throw fail("value " + args[i] + " is not a valid integer");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case String str when !str.startsWith("-") -> example = switch (str) {
|
|
|
|
|
|
|
|
case "SIMPLE" -> Examples::getSimpleScene;
|
|
|
|
|
|
|
|
case "SPHERES" -> Examples::getSpheres;
|
|
|
|
|
|
|
|
case "SQUARES" -> Examples::getSquares;
|
|
|
|
|
|
|
|
case "LIGHT" -> Examples::getLight;
|
|
|
|
|
|
|
|
case "CORNELL" -> Examples::getCornellBox;
|
|
|
|
|
|
|
|
case "CORNELL_SMOKE" -> Examples::getCornellBoxSmoke;
|
|
|
|
|
|
|
|
default -> throw fail("unknown example " + str + ", expected one of SIMPLE, SPHERES, SQUARES, LIGHT, CORNELL or CORNELL_SMOKE");
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
default -> throw fail("unknown option " + args[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (example == null) example = Examples::getCornellBoxSmoke;
|
|
|
|
|
|
|
|
if (path == null) path = Path.of("scene-" + System.currentTimeMillis() + ".png");
|
|
|
|
|
|
|
|
return new Config(example.apply(height), path, preview, iterative, samples, depth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
objects.add(new Sphere(new Vec3(0, 1, 0), 1.0, new DielectricMaterial(1.5)));
|
|
|
|
private static @NotNull RuntimeException fail(@NotNull String message) {
|
|
|
|
objects.add(new Sphere(new Vec3(-4, 1, 0), 1.0, new LambertianMaterial(new Color(0.4, 0.2, 0.1))));
|
|
|
|
System.err.println(message);
|
|
|
|
objects.add(new Sphere(new Vec3(4, 1, 0), 1.0, new MetallicMaterial(new Color(0.7, 0.6, 0.5))));
|
|
|
|
System.exit(1);
|
|
|
|
|
|
|
|
return new RuntimeException();
|
|
|
|
var camera = SimpleCamera.builder()
|
|
|
|
}
|
|
|
|
.withImage(1200, 675)
|
|
|
|
|
|
|
|
.withPosition(new Vec3(13, 2, 3))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(0, 0, 0))
|
|
|
|
|
|
|
|
.withFieldOfView(Math.toRadians(20))
|
|
|
|
|
|
|
|
.withFocusDistance(10.0)
|
|
|
|
|
|
|
|
.withBlurAngle(Math.toRadians(0.6))
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new Example(new Scene(getSkyBox(), objects), camera);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull Example getSquares() {
|
|
|
|
private static class Examples {
|
|
|
|
return new Example(
|
|
|
|
public static @NotNull Example getSimpleScene(int height) {
|
|
|
|
new Scene(
|
|
|
|
if (height <= 0) height = 675;
|
|
|
|
getSkyBox(),
|
|
|
|
return new Example(
|
|
|
|
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 Scene(
|
|
|
|
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))),
|
|
|
|
getSkyBox(),
|
|
|
|
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 Sphere(new Vec3(0, -100.5, -1.0), 100.0, new LambertianMaterial(new Color(0.8, 0.8, 0.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 Sphere(new Vec3(0, 0, -1.2), 0.5, new LambertianMaterial(new Color(0.1, 0.2, 0.5))),
|
|
|
|
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)))
|
|
|
|
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)),
|
|
|
|
SimpleCamera.builder()
|
|
|
|
new Sphere(new Vec3(1.0, 0, -1.2), 0.5, new MetallicMaterial(new Color(0.8, 0.6, 0.2), 0.0))
|
|
|
|
.withImage(400, 400)
|
|
|
|
),
|
|
|
|
.withFieldOfView(Math.toRadians(80))
|
|
|
|
SimpleCamera.builder()
|
|
|
|
.withPosition(new Vec3(0, 0, 9))
|
|
|
|
.withImage(height * 16 / 9, height)
|
|
|
|
.withTarget(new Vec3(0, 0, 0))
|
|
|
|
.build()
|
|
|
|
.build()
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull Example getLight() {
|
|
|
|
public static @NotNull Example getSpheres(int height) {
|
|
|
|
return new Example(
|
|
|
|
if (height <= 0) height = 675;
|
|
|
|
new Scene(
|
|
|
|
|
|
|
|
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(400, 225)
|
|
|
|
|
|
|
|
.withFieldOfView(Math.toRadians(20))
|
|
|
|
|
|
|
|
.withPosition(new Vec3(26, 3, 6))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(0, 2, 0))
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull Example getCornellBox() {
|
|
|
|
var rng = new Random(1);
|
|
|
|
var red = new LambertianMaterial(new Color(.65, .05, .05));
|
|
|
|
var objects = new ArrayList<Hittable>();
|
|
|
|
var white = new LambertianMaterial(new Color(.73, .73, .73));
|
|
|
|
objects.add(new Sphere(new Vec3(0, -1000, 0), 1000, new LambertianMaterial(new Color(0.5, 0.5, 0.5))));
|
|
|
|
var green = new LambertianMaterial(new Color(.12, .45, .15));
|
|
|
|
|
|
|
|
var light = new DiffuseLight(new Color(15.0, 15.0, 15.0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new Example(
|
|
|
|
|
|
|
|
new Scene(
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), green),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), red),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(343, 554, 332), new Vec3(-130, 0, 0), new Vec3(0, 0, -105), light),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(555, 0 ,0), new Vec3(0, 0, 555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0 ,0), new Vec3(0, 0, -555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0 ,0), new Vec3(0, 555, 0), white),
|
|
|
|
|
|
|
|
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
|
|
|
|
|
|
|
Hittables.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(600, 600)
|
|
|
|
|
|
|
|
.withFieldOfView(Math.toRadians(40))
|
|
|
|
|
|
|
|
.withPosition(new Vec3(278, 278, -800))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(278, 278, 0))
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull Example getCornellBoxSmoke() {
|
|
|
|
for (int a = -11; a < 11; a++) {
|
|
|
|
var red = new LambertianMaterial(new Color(.65, .05, .05));
|
|
|
|
for (int b = -11; b < 11; b++) {
|
|
|
|
var white = new LambertianMaterial(new Color(.73, .73, .73));
|
|
|
|
var center = new Vec3(a + 0.9 * rng.nextDouble(), 0.2, b + 0.9 * rng.nextDouble());
|
|
|
|
var green = new LambertianMaterial(new Color(.12, .45, .15));
|
|
|
|
if (Vec3.distance(center, new Vec3(4, 0.2, 0)) <= 0.9) continue;
|
|
|
|
var light = new DiffuseLight(new Color(7.0, 7.0, 7.0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new Example(
|
|
|
|
|
|
|
|
new Scene(
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), green),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), red),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(113, 554, 127), new Vec3(330, 0, 0), new Vec3(0, 0, 305), light),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(555, 0 ,0), new Vec3(0, 0, 555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0 ,0), new Vec3(0, 0, -555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0 ,0), new Vec3(0, 555, 0), white),
|
|
|
|
|
|
|
|
new ConstantMedium(
|
|
|
|
|
|
|
|
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
|
|
|
|
|
|
|
0.01, new IsotropicMaterial(Color.BLACK)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
new ConstantMedium(
|
|
|
|
|
|
|
|
Hittables.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(600, 600)
|
|
|
|
|
|
|
|
.withFieldOfView(Math.toRadians(40))
|
|
|
|
|
|
|
|
.withPosition(new Vec3(278, 278, -800))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(278, 278, 0))
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull Scene getSimpleScene() {
|
|
|
|
Material material;
|
|
|
|
return new Scene(
|
|
|
|
var rnd = rng.nextDouble();
|
|
|
|
getSkyBox(),
|
|
|
|
if (rnd < 0.8) {
|
|
|
|
new Sphere(new Vec3(0, -100.5, -1.0), 100.0, new LambertianMaterial(new Color(0.8, 0.8, 0.0))),
|
|
|
|
// diffuse
|
|
|
|
new Sphere(new Vec3(0, 0, -1.2), 0.5, new LambertianMaterial(new Color(0.1, 0.2, 0.5))),
|
|
|
|
var albedo = Color.multiply(Color.random(rng), Color.random(rng));
|
|
|
|
new Sphere(new Vec3(-1.0, 0, -1.2), 0.5, new DielectricMaterial(1.5)),
|
|
|
|
material = new LambertianMaterial(albedo);
|
|
|
|
new Sphere(new Vec3(-1.0, 0, -1.2), 0.4, new DielectricMaterial(1 / 1.5)),
|
|
|
|
} else if (rnd < 0.95) {
|
|
|
|
new Sphere(new Vec3(1.0, 0, -1.2), 0.5, new MetallicMaterial(new Color(0.8, 0.6, 0.2), 0.0))
|
|
|
|
// metal
|
|
|
|
);
|
|
|
|
var albedo = Color.random(rng, 0.5, 1.0);
|
|
|
|
}
|
|
|
|
var fuzz = rng.nextDouble() * 0.5;
|
|
|
|
|
|
|
|
material = new MetallicMaterial(albedo, fuzz);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// glass
|
|
|
|
|
|
|
|
material = new DielectricMaterial(1.5);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
objects.add(new Sphere(center, 0.2, material));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull SkyBox getSkyBox() {
|
|
|
|
objects.add(new Sphere(new Vec3(0, 1, 0), 1.0, new DielectricMaterial(1.5)));
|
|
|
|
return SkyBox.gradient(new Color(0.5, 0.7, 1.0), Color.WHITE);
|
|
|
|
objects.add(new Sphere(new Vec3(-4, 1, 0), 1.0, new LambertianMaterial(new Color(0.4, 0.2, 0.1))));
|
|
|
|
|
|
|
|
objects.add(new Sphere(new Vec3(4, 1, 0), 1.0, new MetallicMaterial(new Color(0.7, 0.6, 0.5))));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var camera = SimpleCamera.builder()
|
|
|
|
|
|
|
|
.withImage(height * 16 / 9, height)
|
|
|
|
|
|
|
|
.withPosition(new Vec3(13, 2, 3))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(0, 0, 0))
|
|
|
|
|
|
|
|
.withFieldOfView(Math.toRadians(20))
|
|
|
|
|
|
|
|
.withFocusDistance(10.0)
|
|
|
|
|
|
|
|
.withBlurAngle(Math.toRadians(0.6))
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new Example(new Scene(getSkyBox(), objects), camera);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static @NotNull Example getSquares(int height) {
|
|
|
|
|
|
|
|
if (height <= 0) height = 600;
|
|
|
|
|
|
|
|
return new Example(
|
|
|
|
|
|
|
|
new Scene(
|
|
|
|
|
|
|
|
getSkyBox(),
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
|
|
|
.withPosition(new Vec3(0, 0, 9))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(0, 0, 0))
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static @NotNull Example getLight(int height) {
|
|
|
|
|
|
|
|
if (height <= 0) height = 225;
|
|
|
|
|
|
|
|
return new Example(
|
|
|
|
|
|
|
|
new Scene(
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
|
|
|
.withPosition(new Vec3(26, 3, 6))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(0, 2, 0))
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static @NotNull Example getCornellBox(int height) {
|
|
|
|
|
|
|
|
if (height <= 0) height = 600;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var red = new LambertianMaterial(new Color(.65, .05, .05));
|
|
|
|
|
|
|
|
var white = new LambertianMaterial(new Color(.73, .73, .73));
|
|
|
|
|
|
|
|
var green = new LambertianMaterial(new Color(.12, .45, .15));
|
|
|
|
|
|
|
|
var light = new DiffuseLight(new Color(15.0, 15.0, 15.0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new Example(
|
|
|
|
|
|
|
|
new Scene(
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), green),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), red),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(343, 554, 332), new Vec3(-130, 0, 0), new Vec3(0, 0, -105), light),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(555, 0 ,0), new Vec3(0, 0, 555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0 ,0), new Vec3(0, 0, -555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0 ,0), new Vec3(0, 555, 0), white),
|
|
|
|
|
|
|
|
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
|
|
|
|
|
|
|
Hittables.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))
|
|
|
|
|
|
|
|
.withPosition(new Vec3(278, 278, -800))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(278, 278, 0))
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static @NotNull Example getCornellBoxSmoke(int height) {
|
|
|
|
|
|
|
|
if (height <= 0) height = 600;
|
|
|
|
|
|
|
|
var red = new LambertianMaterial(new Color(.65, .05, .05));
|
|
|
|
|
|
|
|
var white = new LambertianMaterial(new Color(.73, .73, .73));
|
|
|
|
|
|
|
|
var green = new LambertianMaterial(new Color(.12, .45, .15));
|
|
|
|
|
|
|
|
var light = new DiffuseLight(new Color(7.0, 7.0, 7.0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new Example(
|
|
|
|
|
|
|
|
new Scene(
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), green),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), red),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(113, 554, 127), new Vec3(330, 0, 0), new Vec3(0, 0, 305), light),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 0), new Vec3(555, 0 ,0), new Vec3(0, 0, 555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0 ,0), new Vec3(0, 0, -555), white),
|
|
|
|
|
|
|
|
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0 ,0), new Vec3(0, 555, 0), white),
|
|
|
|
|
|
|
|
new ConstantMedium(
|
|
|
|
|
|
|
|
Hittables.box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
|
|
|
|
|
|
|
0.01, new IsotropicMaterial(Color.BLACK)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
new ConstantMedium(
|
|
|
|
|
|
|
|
Hittables.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))
|
|
|
|
|
|
|
|
.withPosition(new Vec3(278, 278, -800))
|
|
|
|
|
|
|
|
.withTarget(new Vec3(278, 278, 0))
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static @NotNull SkyBox getSkyBox() {
|
|
|
|
|
|
|
|
return SkyBox.gradient(new Color(0.5, 0.7, 1.0), Color.WHITE);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private record Example(@NotNull Scene scene, @NotNull Camera camera) {}
|
|
|
|
private record Example(@NotNull Scene scene, @NotNull Camera camera) {}
|
|
|
|