refactor Scene
This commit is contained in:
parent
8ea894cd3e
commit
36de714f46
@ -1,23 +1,17 @@
|
||||
package eu.jonahbauer.raytracing;
|
||||
|
||||
import eu.jonahbauer.raytracing.render.camera.Camera;
|
||||
import eu.jonahbauer.raytracing.render.material.DielectricMaterial;
|
||||
import eu.jonahbauer.raytracing.render.material.LambertianMaterial;
|
||||
import eu.jonahbauer.raytracing.render.material.Material;
|
||||
import eu.jonahbauer.raytracing.render.material.MetallicMaterial;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import eu.jonahbauer.raytracing.render.Color;
|
||||
import eu.jonahbauer.raytracing.render.ImageFormat;
|
||||
import eu.jonahbauer.raytracing.render.camera.Camera;
|
||||
import eu.jonahbauer.raytracing.render.camera.SimpleCamera;
|
||||
import eu.jonahbauer.raytracing.render.canvas.LiveCanvas;
|
||||
import eu.jonahbauer.raytracing.render.canvas.Image;
|
||||
import eu.jonahbauer.raytracing.render.canvas.LiveCanvas;
|
||||
import eu.jonahbauer.raytracing.render.material.*;
|
||||
import eu.jonahbauer.raytracing.render.renderer.SimpleRenderer;
|
||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||
import eu.jonahbauer.raytracing.scene.flat.Ellipse;
|
||||
import eu.jonahbauer.raytracing.scene.flat.Parallelogram;
|
||||
import eu.jonahbauer.raytracing.scene.Scene;
|
||||
import eu.jonahbauer.raytracing.scene.Sphere;
|
||||
import eu.jonahbauer.raytracing.scene.flat.Triangle;
|
||||
import eu.jonahbauer.raytracing.scene.*;
|
||||
import eu.jonahbauer.raytracing.scene.hittable2d.Parallelogram;
|
||||
import eu.jonahbauer.raytracing.scene.hittable3d.Sphere;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -91,18 +85,19 @@ public class Main {
|
||||
.withBlurAngle(Math.toRadians(0.6))
|
||||
.build();
|
||||
|
||||
return new Example(new Scene(objects), camera);
|
||||
return new Example(new Scene(getSkyBox(), objects), camera);
|
||||
}
|
||||
|
||||
private static @NotNull Example getSquares() {
|
||||
return new Example(
|
||||
new Scene(List.of(
|
||||
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(400, 400)
|
||||
.withFieldOfView(Math.toRadians(80))
|
||||
@ -113,13 +108,18 @@ public class Main {
|
||||
}
|
||||
|
||||
private static @NotNull Scene getSimpleScene() {
|
||||
return new Scene(List.of(
|
||||
return new Scene(
|
||||
getSkyBox(),
|
||||
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))
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
@ -3,8 +3,18 @@ package eu.jonahbauer.raytracing.math;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record BoundingBox(@NotNull Vec3 min, @NotNull Vec3 max) {
|
||||
public BoundingBox {
|
||||
var a = min;
|
||||
var b = max;
|
||||
min = Vec3.min(a, b);
|
||||
max = Vec3.max(a, b);
|
||||
}
|
||||
|
||||
public @NotNull Vec3 center() {
|
||||
return Vec3.average(min, max, 2);
|
||||
}
|
||||
|
||||
public @NotNull BoundingBox expand(@NotNull BoundingBox box) {
|
||||
return new BoundingBox(Vec3.min(this.min, box.min), Vec3.max(this.max, box.max));
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import java.util.Random;
|
||||
public record Color(double r, double g, double b) {
|
||||
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 SKY = new Color(0.5, 0.7, 1.0);
|
||||
public static final @NotNull Color RED = new Color(1.0, 0.0, 0.0);
|
||||
public static final @NotNull Color GREEN = new Color(0.0, 1.0, 0.0);
|
||||
public static final @NotNull Color BLUE = new Color(0.0, 0.0, 1.0);
|
||||
@ -65,25 +64,25 @@ public record Color(double r, double g, double b) {
|
||||
}
|
||||
}
|
||||
|
||||
public Color {
|
||||
if (r < 0 || r > 1 || g < 0 || g > 1 || b < 0 || b > 1) {
|
||||
throw new IllegalArgumentException("r, g and b must be in the range 0 to 1");
|
||||
}
|
||||
}
|
||||
public Color {}
|
||||
|
||||
public Color(int red, int green, int blue) {
|
||||
this(red / 255f, green / 255f, blue / 255f);
|
||||
}
|
||||
|
||||
public int red() {
|
||||
return (int) (255.99 * r);
|
||||
return toInt(r);
|
||||
}
|
||||
|
||||
public int green() {
|
||||
return (int) (255.99 * g);
|
||||
return toInt(g);
|
||||
}
|
||||
|
||||
public int blue() {
|
||||
return (int) (255.99 * b);
|
||||
return toInt(b);
|
||||
}
|
||||
|
||||
private static int toInt(double value) {
|
||||
return Math.max(0, Math.min(255, (int) (255.99 * value)));
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ public final class SimpleRenderer implements Renderer {
|
||||
.map(scatter -> Color.multiply(scatter.attenuation(), getColor0(scene, scatter.ray(), depth - 1)))
|
||||
.orElse(Color.BLACK);
|
||||
} else {
|
||||
return getSkyboxColor(ray);
|
||||
return scene.getBackgroundColor(ray);
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,19 +111,6 @@ public final class SimpleRenderer implements Renderer {
|
||||
return parallel ? stream.parallel() : stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the color of the skybox for a given ray} The skybox color is a linear gradient based on the altitude of
|
||||
* the ray above the horizon with {@link Color#SKY} at the top and {@link Color#WHITE} at the bottom.
|
||||
*/
|
||||
private static @NotNull Color getSkyboxColor(@NotNull Ray ray) {
|
||||
// altitude from -pi/2 to pi/2
|
||||
var alt = Math.copySign(
|
||||
Math.acos(ray.direction().withY(0).unit().times(ray.direction().unit())),
|
||||
ray.direction().y()
|
||||
);
|
||||
return Color.lerp(Color.WHITE, Color.SKY, alt / Math.PI + 0.5);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private int samplesPerPixel = 100;
|
||||
private int maxDepth = 10;
|
||||
|
@ -1,85 +1,64 @@
|
||||
package eu.jonahbauer.raytracing.scene;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Octree;
|
||||
import eu.jonahbauer.raytracing.math.Range;
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import eu.jonahbauer.raytracing.render.Color;
|
||||
import eu.jonahbauer.raytracing.scene.util.HittableCollection;
|
||||
import eu.jonahbauer.raytracing.scene.util.HittableList;
|
||||
import eu.jonahbauer.raytracing.scene.util.HittableOctree;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class Scene implements Hittable {
|
||||
private final @NotNull Octree<@NotNull Hittable> octree;
|
||||
private final @NotNull List<@NotNull Hittable> list;
|
||||
public final class Scene extends HittableCollection {
|
||||
private final @NotNull HittableOctree octree;
|
||||
private final @NotNull HittableList list;
|
||||
private final @NotNull SkyBox background;
|
||||
|
||||
public Scene(@NotNull List<? extends @NotNull Hittable> objects) {
|
||||
this.octree = newOctree(objects);
|
||||
this.list = new ArrayList<>();
|
||||
this(Color.BLACK, objects);
|
||||
}
|
||||
|
||||
for (Hittable object : objects) {
|
||||
var bbox = object.getBoundingBox();
|
||||
if (bbox.isPresent()) {
|
||||
octree.add(bbox.get(), object);
|
||||
public Scene(@NotNull Color background, @NotNull List<? extends @NotNull Hittable> objects) {
|
||||
this(SkyBox.solid(background), objects);
|
||||
}
|
||||
|
||||
public Scene(@NotNull SkyBox background, @NotNull List<? extends @NotNull Hittable> objects) {
|
||||
var bounded = new ArrayList<Hittable>();
|
||||
var unbounded = new ArrayList<Hittable>();
|
||||
|
||||
objects.forEach(object -> {
|
||||
if (object.getBoundingBox().isPresent()) {
|
||||
bounded.add(object);
|
||||
} else {
|
||||
list.add(object);
|
||||
unbounded.add(object);
|
||||
}
|
||||
});
|
||||
|
||||
this.octree = new HittableOctree(bounded);
|
||||
this.list = new HittableList(unbounded);
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
|
||||
var state = new State();
|
||||
state.range = range;
|
||||
|
||||
octree.hit(ray, object -> hit(state, ray, object));
|
||||
list.forEach(object -> hit(state, ray, object));
|
||||
|
||||
return Optional.ofNullable(state.result);
|
||||
public void hit(@NotNull Ray ray, @NotNull State state) {
|
||||
octree.hit(ray, state);
|
||||
list.hit(ray, state);
|
||||
}
|
||||
|
||||
private boolean hit(@NotNull State state, @NotNull Ray ray, @NotNull Hittable object) {
|
||||
var r = object.hit(ray, state.range);
|
||||
if (r.isPresent()) {
|
||||
if (state.range.surrounds(r.get().t())){
|
||||
state.result = r.get();
|
||||
state.range = new Range(state.range.min(), state.result.t());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull Octree<Hittable> newOctree(@NotNull List<? extends Hittable> objects) {
|
||||
Vec3 center = Vec3.ZERO, max = Vec3.MIN, min = Vec3.MAX;
|
||||
|
||||
int i = 1;
|
||||
for (Hittable object : objects) {
|
||||
var bbox = object.getBoundingBox();
|
||||
if (bbox.isPresent()) {
|
||||
center = Vec3.average(center, bbox.get().center(), i++);
|
||||
max = Vec3.max(max, bbox.get().max());
|
||||
min = Vec3.min(min, bbox.get().min());
|
||||
}
|
||||
}
|
||||
|
||||
var dimension = Arrays.stream(new double[] {
|
||||
Math.abs(max.x() - center.x()),
|
||||
Math.abs(max.y() - center.y()),
|
||||
Math.abs(max.z() - center.z()),
|
||||
Math.abs(min.x() - center.x()),
|
||||
Math.abs(min.y() - center.y()),
|
||||
Math.abs(min.z() - center.z())
|
||||
}).max().orElse(10);
|
||||
|
||||
return new Octree<>(center, dimension);
|
||||
}
|
||||
|
||||
private static class State {
|
||||
HitResult result;
|
||||
Range range;
|
||||
public @NotNull Color getBackgroundColor(@NotNull Ray ray) {
|
||||
return background.getColor(ray);
|
||||
}
|
||||
}
|
||||
|
25
src/main/java/eu/jonahbauer/raytracing/scene/SkyBox.java
Normal file
25
src/main/java/eu/jonahbauer/raytracing/scene/SkyBox.java
Normal file
@ -0,0 +1,25 @@
|
||||
package eu.jonahbauer.raytracing.scene;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import eu.jonahbauer.raytracing.render.Color;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SkyBox {
|
||||
@NotNull Color getColor(@NotNull Ray ray);
|
||||
|
||||
static @NotNull SkyBox gradient(@NotNull Color top, @NotNull Color bottom) {
|
||||
return ray -> {
|
||||
// altitude from -pi/2 to pi/2
|
||||
var alt = Math.copySign(
|
||||
Math.acos(ray.direction().withY(0).unit().times(ray.direction().unit())),
|
||||
ray.direction().y()
|
||||
);
|
||||
return Color.lerp(bottom, top, alt / Math.PI + 0.5);
|
||||
};
|
||||
}
|
||||
|
||||
static @NotNull SkyBox solid(@NotNull Color color) {
|
||||
return _ -> color;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package eu.jonahbauer.raytracing.scene.flat;
|
||||
package eu.jonahbauer.raytracing.scene.hittable2d;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.BoundingBox;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
@ -1,4 +1,4 @@
|
||||
package eu.jonahbauer.raytracing.scene.flat;
|
||||
package eu.jonahbauer.raytracing.scene.hittable2d;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Range;
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
@ -1,4 +1,4 @@
|
||||
package eu.jonahbauer.raytracing.scene.flat;
|
||||
package eu.jonahbauer.raytracing.scene.hittable2d;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.BoundingBox;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
@ -1,4 +1,4 @@
|
||||
package eu.jonahbauer.raytracing.scene.flat;
|
||||
package eu.jonahbauer.raytracing.scene.hittable2d;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import eu.jonahbauer.raytracing.render.material.Material;
|
@ -1,4 +1,4 @@
|
||||
package eu.jonahbauer.raytracing.scene.flat;
|
||||
package eu.jonahbauer.raytracing.scene.hittable2d;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.BoundingBox;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
@ -1,10 +1,12 @@
|
||||
package eu.jonahbauer.raytracing.scene;
|
||||
package eu.jonahbauer.raytracing.scene.hittable3d;
|
||||
|
||||
import eu.jonahbauer.raytracing.render.material.Material;
|
||||
import eu.jonahbauer.raytracing.math.BoundingBox;
|
||||
import eu.jonahbauer.raytracing.math.Range;
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import eu.jonahbauer.raytracing.scene.HitResult;
|
||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
@ -0,0 +1,65 @@
|
||||
package eu.jonahbauer.raytracing.scene.util;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.BoundingBox;
|
||||
import eu.jonahbauer.raytracing.math.Range;
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import eu.jonahbauer.raytracing.scene.HitResult;
|
||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class HittableCollection implements Hittable {
|
||||
|
||||
@Override
|
||||
public final @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
|
||||
var state = new State(range);
|
||||
hit(ray, state);
|
||||
return state.getResult();
|
||||
}
|
||||
|
||||
public abstract void hit(@NotNull Ray ray, @NotNull State state);
|
||||
|
||||
protected static @NotNull Optional<BoundingBox> getBoundingBox(@NotNull Collection<? extends @NotNull Hittable> objects) {
|
||||
var bbox = new BoundingBox(Vec3.ZERO, Vec3.ZERO);
|
||||
for (var object : objects) {
|
||||
var b = object.getBoundingBox();
|
||||
if (b.isPresent()) {
|
||||
bbox = bbox.expand(b.get());
|
||||
} else {
|
||||
bbox = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Optional.ofNullable(bbox);
|
||||
}
|
||||
|
||||
protected static boolean hit(@NotNull State state, @NotNull Ray ray, @NotNull Hittable object) {
|
||||
var r = object.hit(ray, state.range);
|
||||
if (r.isPresent()) {
|
||||
if (state.range.surrounds(r.get().t())){
|
||||
state.result = r.get();
|
||||
state.range = new Range(state.range.min(), state.result.t());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class State {
|
||||
private @NotNull Range range;
|
||||
private HitResult result;
|
||||
|
||||
private State(@NotNull Range range) {
|
||||
this.range = Objects.requireNonNull(range);
|
||||
}
|
||||
|
||||
private @NotNull Optional<HitResult> getResult() {
|
||||
return Optional.ofNullable(result);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package eu.jonahbauer.raytracing.scene.util;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.BoundingBox;
|
||||
import eu.jonahbauer.raytracing.math.Ray;
|
||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class HittableList extends HittableCollection {
|
||||
private final @NotNull List<Hittable> objects;
|
||||
private final @NotNull Optional<BoundingBox> bbox;
|
||||
|
||||
public HittableList(@NotNull List<? extends @NotNull Hittable> objects) {
|
||||
this.objects = List.copyOf(objects);
|
||||
this.bbox = getBoundingBox(this.objects);
|
||||
}
|
||||
|
||||
public HittableList(@NotNull Hittable @NotNull... objects) {
|
||||
this(List.of(objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(@NotNull Ray ray, @NotNull State state) {
|
||||
objects.forEach(object -> hit(state, ray, object));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Optional<BoundingBox> getBoundingBox() {
|
||||
return bbox;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package eu.jonahbauer.raytracing.scene.util;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.*;
|
||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class HittableOctree extends HittableCollection {
|
||||
private final @NotNull Octree<Hittable> objects;
|
||||
private final @NotNull Optional<BoundingBox> bbox;
|
||||
|
||||
public HittableOctree(@NotNull List<? extends @NotNull Hittable> objects) {
|
||||
var result = newOctree(objects);
|
||||
this.objects = result.getKey();
|
||||
this.bbox = Optional.of(result.getValue());
|
||||
}
|
||||
|
||||
public HittableOctree(@NotNull Hittable @NotNull... objects) {
|
||||
this(List.of(objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(@NotNull Ray ray, @NotNull State state) {
|
||||
objects.hit(ray, object -> hit(state, ray, object));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Optional<BoundingBox> getBoundingBox() {
|
||||
return bbox;
|
||||
}
|
||||
|
||||
private static @NotNull Entry<@NotNull Octree<Hittable>, @NotNull BoundingBox> newOctree(@NotNull List<? extends Hittable> objects) {
|
||||
Vec3 center = Vec3.ZERO, max = Vec3.MIN, min = Vec3.MAX;
|
||||
|
||||
int i = 1;
|
||||
for (var object : objects) {
|
||||
var bbox = object.getBoundingBox().orElseThrow();
|
||||
center = Vec3.average(center, bbox.center(), i++);
|
||||
max = Vec3.max(max, bbox.max());
|
||||
min = Vec3.min(min, bbox.min());
|
||||
}
|
||||
|
||||
var dimension = Arrays.stream(new double[] {
|
||||
Math.abs(max.x() - center.x()),
|
||||
Math.abs(max.y() - center.y()),
|
||||
Math.abs(max.z() - center.z()),
|
||||
Math.abs(min.x() - center.x()),
|
||||
Math.abs(min.y() - center.y()),
|
||||
Math.abs(min.z() - center.z())
|
||||
}).max().orElse(10);
|
||||
|
||||
var out = new Octree<Hittable>(center, dimension);
|
||||
objects.forEach(object -> out.add(object.getBoundingBox().get(), object));
|
||||
return Map.entry(out, new BoundingBox(min, max));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user