move render method to Camera
This commit is contained in:
parent
7757b3d573
commit
1113b91077
@ -2,7 +2,7 @@ package eu.jonahbauer.raytracing;
|
|||||||
|
|
||||||
import eu.jonahbauer.raytracing.render.Camera;
|
import eu.jonahbauer.raytracing.render.Camera;
|
||||||
import eu.jonahbauer.raytracing.render.ImageIO;
|
import eu.jonahbauer.raytracing.render.ImageIO;
|
||||||
import eu.jonahbauer.raytracing.render.Scene;
|
import eu.jonahbauer.raytracing.shape.Scene;
|
||||||
import eu.jonahbauer.raytracing.shape.Sphere;
|
import eu.jonahbauer.raytracing.shape.Sphere;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -16,7 +16,7 @@ public class Main {
|
|||||||
);
|
);
|
||||||
var camera = new Camera(256, 2, 16 / 9d);
|
var camera = new Camera(256, 2, 16 / 9d);
|
||||||
|
|
||||||
var image = scene.render(camera);
|
var image = camera.render(scene);
|
||||||
ImageIO.write(image, Path.of("scene-" + System.currentTimeMillis() + ".ppm"));
|
ImageIO.write(image, Path.of("scene-" + System.currentTimeMillis() + ".ppm"));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package eu.jonahbauer.raytracing.render;
|
|||||||
|
|
||||||
import eu.jonahbauer.raytracing.math.Ray;
|
import eu.jonahbauer.raytracing.math.Ray;
|
||||||
import eu.jonahbauer.raytracing.math.Vec3;
|
import eu.jonahbauer.raytracing.math.Vec3;
|
||||||
|
import eu.jonahbauer.raytracing.shape.Scene;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -43,6 +44,34 @@ public record Camera(
|
|||||||
this(width, height, viewportWidth, viewportHeight, Vec3.ZERO, Vec3.UNIT_Z);
|
this(width, height, viewportWidth, viewportHeight, Vec3.ZERO, Vec3.UNIT_Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull Image render(@NotNull Scene scene) {
|
||||||
|
var image = new Image(width(), height());
|
||||||
|
|
||||||
|
pixels().forEach(pixel -> {
|
||||||
|
var x = pixel.x();
|
||||||
|
var y = pixel.y();
|
||||||
|
var ray = pixel.ray();
|
||||||
|
|
||||||
|
var result = scene.hit(ray);
|
||||||
|
if (result.isPresent()) {
|
||||||
|
var normal = result.get().normal();
|
||||||
|
image.set(x, y, getNormalColor(normal));
|
||||||
|
} else {
|
||||||
|
image.set(x, y, scene.getSkyboxColor(ray));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull Color getNormalColor(@NotNull Vec3 normal) {
|
||||||
|
return new Color(
|
||||||
|
0.5 * (normal.x() + 1),
|
||||||
|
0.5 * (normal.y() + 1),
|
||||||
|
0.5 * (normal.z() + 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull Stream<Pixel> pixels() {
|
public @NotNull Stream<Pixel> pixels() {
|
||||||
// project direction onto xz-plane
|
// project direction onto xz-plane
|
||||||
var d = direction.unit();
|
var d = direction.unit();
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
package eu.jonahbauer.raytracing.render;
|
|
||||||
|
|
||||||
import eu.jonahbauer.raytracing.math.Range;
|
|
||||||
import eu.jonahbauer.raytracing.math.Ray;
|
|
||||||
import eu.jonahbauer.raytracing.math.Vec3;
|
|
||||||
import eu.jonahbauer.raytracing.shape.HitResult;
|
|
||||||
import eu.jonahbauer.raytracing.shape.Shape;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public record Scene(@NotNull List<@NotNull Shape> shapes) {
|
|
||||||
|
|
||||||
public Scene {
|
|
||||||
shapes = List.copyOf(shapes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Scene(@NotNull Shape @NotNull ... shapes) {
|
|
||||||
this(List.of(shapes));
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull Image render(@NotNull Camera camera) {
|
|
||||||
var image = new Image(camera.width(), camera.height());
|
|
||||||
|
|
||||||
camera.pixels().forEach(pixel -> {
|
|
||||||
var x = pixel.x();
|
|
||||||
var y = pixel.y();
|
|
||||||
var ray = pixel.ray();
|
|
||||||
|
|
||||||
var result = hit(ray);
|
|
||||||
if (result.isPresent()) {
|
|
||||||
var normal = result.get().normal();
|
|
||||||
image.set(x, y, getNormalColor(normal));
|
|
||||||
} else {
|
|
||||||
image.set(x, y, getSkyboxColor(ray));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
private @NotNull Optional<HitResult> hit(@NotNull Ray ray) {
|
|
||||||
var range = new Range(0, Double.POSITIVE_INFINITY);
|
|
||||||
var result = (HitResult) null;
|
|
||||||
for (var shape : shapes) {
|
|
||||||
var r = shape.hit(ray, range);
|
|
||||||
if (r.isPresent() && (result == null || r.get().t() < result.t())) {
|
|
||||||
result = r.get();
|
|
||||||
range = new Range(0, result.t());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.ofNullable(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @NotNull Color getNormalColor(@NotNull Vec3 normal) {
|
|
||||||
return new Color(
|
|
||||||
0.5 * (normal.x() + 1),
|
|
||||||
0.5 * (normal.y() + 1),
|
|
||||||
0.5 * (normal.z() + 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @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);
|
|
||||||
}
|
|
||||||
}
|
|
42
src/main/java/eu/jonahbauer/raytracing/shape/Scene.java
Normal file
42
src/main/java/eu/jonahbauer/raytracing/shape/Scene.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package eu.jonahbauer.raytracing.shape;
|
||||||
|
|
||||||
|
import eu.jonahbauer.raytracing.math.Range;
|
||||||
|
import eu.jonahbauer.raytracing.math.Ray;
|
||||||
|
import eu.jonahbauer.raytracing.render.Color;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public record Scene(@NotNull List<@NotNull Shape> shapes) {
|
||||||
|
|
||||||
|
public Scene {
|
||||||
|
shapes = List.copyOf(shapes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Scene(@NotNull Shape @NotNull ... shapes) {
|
||||||
|
this(List.of(shapes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Optional<HitResult> hit(@NotNull Ray ray) {
|
||||||
|
var range = new Range(0, Double.POSITIVE_INFINITY);
|
||||||
|
var result = (HitResult) null;
|
||||||
|
for (var shape : shapes) {
|
||||||
|
var r = shape.hit(ray, range);
|
||||||
|
if (r.isPresent() && (result == null || r.get().t() < result.t())) {
|
||||||
|
result = r.get();
|
||||||
|
range = new Range(0, result.t());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user