From b40cc15a9fd3f7bf9f4633b2481dc6e465b297aa Mon Sep 17 00:00:00 2001 From: jbb01 <32650546+jbb01@users.noreply.github.com> Date: Sun, 4 Aug 2024 01:28:28 +0200 Subject: [PATCH] add final scene and live preview --- .../java/eu/jonahbauer/raytracing/Main.java | 85 +++++++++++++++---- .../eu/jonahbauer/raytracing/math/Vec3.java | 4 + .../jonahbauer/raytracing/render/Color.java | 13 +++ 3 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/main/java/eu/jonahbauer/raytracing/Main.java b/src/main/java/eu/jonahbauer/raytracing/Main.java index 43be90b..8de1518 100644 --- a/src/main/java/eu/jonahbauer/raytracing/Main.java +++ b/src/main/java/eu/jonahbauer/raytracing/Main.java @@ -2,37 +2,88 @@ package eu.jonahbauer.raytracing; import eu.jonahbauer.raytracing.material.DielectricMaterial; import eu.jonahbauer.raytracing.material.LambertianMaterial; +import eu.jonahbauer.raytracing.material.Material; import eu.jonahbauer.raytracing.material.MetallicMaterial; import eu.jonahbauer.raytracing.math.Vec3; -import eu.jonahbauer.raytracing.render.Camera; +import eu.jonahbauer.raytracing.render.*; import eu.jonahbauer.raytracing.render.Color; -import eu.jonahbauer.raytracing.render.ImageFormat; +import eu.jonahbauer.raytracing.scene.Hittable; import eu.jonahbauer.raytracing.scene.Scene; import eu.jonahbauer.raytracing.scene.Sphere; +import javax.swing.*; +import java.awt.*; import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; public class Main { - public static void main(String[] args) throws IOException { - var scene = new Scene( - new Sphere(0, -100.5, - 1, 100, new LambertianMaterial(new Color(0.8, 0.8, 0.0))), - new Sphere(0, 0, - 1.2, 0.5, new LambertianMaterial(new Color(0.1, 0.2, 0.5))), - new Sphere(-1, 0, - 1, 0.5, new DielectricMaterial(1.5)), - new Sphere(-1, 0, - 1, 0.4, new DielectricMaterial(1 / 1.5)), - new Sphere(1, 0, - 1, 0.5, new MetallicMaterial(new Color(0.8, 0.6, 0.2), 1.0)) - ); + public static void main(String[] args) throws IOException, InterruptedException { + var objects = new ArrayList(); + 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 * Math.random(), 0.2, b + 0.9 * Math.random()); + if (Vec3.distance(center, new Vec3(4, 0.2, 0)) <= 0.9) continue; + + Material material; + var rnd = Math.random(); + if (rnd < 0.8) { + // diffuse + var albedo = Color.multiply(Color.random(), Color.random()); + material = new LambertianMaterial(albedo); + } else if (rnd < 0.95) { + // metal + var albedo = Color.random(0.5, 1.0); + var fuzz = Math.random() * 0.5; + material = new MetallicMaterial(albedo, fuzz); + } else { + // glass + material = new DielectricMaterial(1.5); + } + + objects.add(new Sphere(center, 0.2, material)); + } + } + + objects.add(new Sphere(new Vec3(0, 1, 0), 1.0, new DielectricMaterial(1.5))); + 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 scene = new Scene(objects); var camera = Camera.builder() - .withImage(800, 450) - .withPosition(new Vec3(-2, 2, 1)) - .withTarget(new Vec3(0, 0, -1)) + .withImage(1280, 720) + .withPosition(new Vec3(13, 2, 3)) + .withTarget(new Vec3(0, 0, 0)) + .withSamplesPerPixel(100) + .withMaxDepth(10) .withFieldOfView(Math.toRadians(20)) - .withFocusDistance(3.4) - .withBlurAngle(Math.toRadians(10)) + .withBlurAngle(Math.toRadians(0.6)) + .withFocusDistance(10.0) .build(); - var image = camera.render(scene); - ImageFormat.PNG.write(image, Path.of("scene-" + System.currentTimeMillis() + ".png")); + var canvas = new BufferedImageCanvas(camera.width(), camera.height()); + var thread = Thread.ofVirtual().start(() -> camera.render(scene, canvas)); + + var frame = new JFrame(); + frame.setSize(camera.width(), camera.height()); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setContentPane(new JPanel() { + @Override + protected void paintComponent(Graphics g) { + g.drawImage(canvas.getImage(), 0, 0, null); + } + }); + frame.setResizable(false); + frame.setVisible(true); + + while (thread.isAlive()) { + Thread.sleep(1000); + frame.repaint(); + } + + ImageFormat.PNG.write(canvas, Path.of("scene-" + System.currentTimeMillis() + ".png")); } } \ No newline at end of file diff --git a/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java b/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java index 4646246..adbfbb4 100644 --- a/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java +++ b/src/main/java/eu/jonahbauer/raytracing/math/Vec3.java @@ -50,6 +50,10 @@ public record Vec3(double x, double y, double z) { return vec.plus(vxp.times(Math.sin(angle))).plus(vxvxp.times(1 - Math.cos(angle))); } + public static double distance(@NotNull Vec3 a, @NotNull Vec3 b) { + return a.minus(b).length(); + } + public @NotNull Vec3 plus(@NotNull Vec3 b) { return new Vec3(this.x + b.x, this.y + b.y, this.z + b.z); } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/Color.java b/src/main/java/eu/jonahbauer/raytracing/render/Color.java index 1dc1211..b56e572 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/Color.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/Color.java @@ -24,6 +24,19 @@ public record Color(double r, double g, double b) { return new Color(a.r() * b.r(), a.g() * b.g(), a.b() * b.b()); } + public static @NotNull Color random() { + return new Color(Math.random(), Math.random(), Math.random()); + } + + public static @NotNull Color random(double min, double max) { + var span = max - min; + return new Color( + Math.fma(Math.random(), span, min), + Math.fma(Math.random(), span, min), + Math.fma(Math.random(), span, min) + ); + } + 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");