From b8aae8c2e5533159113d46978f749bc45de420d9 Mon Sep 17 00:00:00 2001 From: jbb01 <32650546+jbb01@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:45:59 +0200 Subject: [PATCH] rework interface between materials and rgb colors --- .../eu/jonahbauer/raytracing/Examples.java | 92 +++++++++---------- .../raytracing/render/color/ColorRGB.java | 6 +- .../raytracing/render/color/ColorSpace.java | 37 +++++++- .../render/material/DielectricMaterial.java | 62 ++++++++++--- .../render/material/DiffuseLight.java | 7 -- .../render/material/IsotropicMaterial.java | 7 -- .../render/material/LambertianMaterial.java | 7 -- .../raytracing/render/material/Materials.java | 25 +++++ .../render/material/MetallicMaterial.java | 11 --- .../render/spectrum/RGBAlbedoSpectrum.java | 2 +- .../spectrum/RGBIlluminantSpectrum.java | 2 +- .../render/spectrum/RGBUnboundedSpectrum.java | 2 +- .../raytracing/render/spectrum/Spectrum.java | 4 + .../render/texture/ImageTexture.java | 26 +----- 14 files changed, 164 insertions(+), 126 deletions(-) create mode 100644 src/main/java/eu/jonahbauer/raytracing/render/material/Materials.java diff --git a/src/main/java/eu/jonahbauer/raytracing/Examples.java b/src/main/java/eu/jonahbauer/raytracing/Examples.java index c238794..7818ad2 100644 --- a/src/main/java/eu/jonahbauer/raytracing/Examples.java +++ b/src/main/java/eu/jonahbauer/raytracing/Examples.java @@ -55,11 +55,11 @@ public class Examples { var cs = ColorSpaces.sRGB; return new Example( new Scene(getSkyBox(), List.of( - new Sphere(new Vec3(0, -100.5, -1.0), 100.0, new LambertianMaterial(new ColorRGB(0.8, 0.8, 0.0), cs)), - new Sphere(new Vec3(0, 0, -1.2), 0.5, new LambertianMaterial(new ColorRGB(0.1, 0.2, 0.5), cs)), + new Sphere(new Vec3(0, -100.5, -1.0), 100.0, new LambertianMaterial(cs.albedo(0.8, 0.8, 0.0))), + new Sphere(new Vec3(0, 0, -1.2), 0.5, new LambertianMaterial(cs.albedo(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 ColorRGB(0.8, 0.6, 0.2), cs, 0.0)) + new Sphere(new Vec3(1.0, 0, -1.2), 0.5, new MetallicMaterial(cs.albedo(0.8, 0.6, 0.2))) )), SimpleCamera.builder() .withImage(height * 16 / 9, height) @@ -92,12 +92,12 @@ public class Examples { if (rnd < 0.8) { // diffuse var albedo = ColorRGB.random(rng).times(ColorRGB.random(rng)); - material = new LambertianMaterial(albedo, cs); + material = new LambertianMaterial(cs.albedo(albedo)); } else if (rnd < 0.95) { // metal var albedo = ColorRGB.random(rng, 0.5, 1.0); var fuzz = rng.nextDouble() * 0.5; - material = new MetallicMaterial(albedo, cs, fuzz); + material = new MetallicMaterial(cs.albedo(albedo), fuzz); } else { // glass material = new DielectricMaterial(1.5); @@ -108,8 +108,8 @@ public class Examples { } 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 ColorRGB(0.4, 0.2, 0.1), cs))); - objects.add(new Sphere(new Vec3(4, 1, 0), 1.0, new MetallicMaterial(new ColorRGB(0.7, 0.6, 0.5), cs))); + objects.add(new Sphere(new Vec3(-4, 1, 0), 1.0, new LambertianMaterial(cs.albedo(0.4, 0.2, 0.1)))); + objects.add(new Sphere(new Vec3(4, 1, 0), 1.0, new MetallicMaterial(cs.albedo(0.7, 0.6, 0.5)))); var camera = SimpleCamera.builder() .withImage(height * 16 / 9, height) @@ -128,11 +128,11 @@ public class Examples { var cs = ColorSpaces.sRGB; return new Example( 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 ColorRGB(1.0, 0.2, 0.2), cs)), - new Parallelogram(new Vec3(-2, -2, 0), new Vec3(4, 0, 0), new Vec3(0, 4, 0), new LambertianMaterial(new ColorRGB(0.2, 1.0, 0.2), cs)), - new Parallelogram(new Vec3(3, -2, 1), new Vec3(0, 0, 4), new Vec3(0, 4, 0), new LambertianMaterial(new ColorRGB(0.2, 0.2, 1.0), cs)), - new Parallelogram(new Vec3(-2, 3, 1), new Vec3(4, 0, 0), new Vec3(0, 0, 4), new LambertianMaterial(new ColorRGB(1.0, 0.5, 0.0), cs)), - new Parallelogram(new Vec3(-2, -3, 5), new Vec3(4, 0, 0), new Vec3(0, 0, -4), new LambertianMaterial(new ColorRGB(0.2, 0.8, 0.8), cs)) + new Parallelogram(new Vec3(-3, -2, 5), new Vec3(0, 0, -4), new Vec3(0, 4, 0), new LambertianMaterial(cs.albedo(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(cs.albedo(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(cs.albedo(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(cs.albedo(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(cs.albedo(0.2, 0.8, 0.8))) )), SimpleCamera.builder() .withImage(height, height) @@ -148,10 +148,10 @@ public class Examples { var cs = ColorSpaces.sRGB; return new Example( new Scene(List.of( - new Sphere(new Vec3(0, -1000, 0), 1000, new LambertianMaterial(new ColorRGB(0.2, 0.2, 0.2), cs)), - new Sphere(new Vec3(0, 2, 0), 2, new LambertianMaterial(new ColorRGB(0.2, 0.2, 0.2), cs)), - new Parallelogram(new Vec3(3, 1, -2), new Vec3(2, 0, 0), new Vec3(0, 2, 0), new DiffuseLight(new ColorRGB(4.0, 4.0, 4.0), cs)), - new Sphere(new Vec3(0, 7, 0), 2, new DiffuseLight(new ColorRGB(4.0, 4.0, 4.0), cs)) + new Sphere(new Vec3(0, -1000, 0), 1000, new LambertianMaterial(cs.albedo(0.2, 0.2, 0.2))), + new Sphere(new Vec3(0, 2, 0), 2, new LambertianMaterial(cs.albedo(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(cs.illuminant(4.0))), + new Sphere(new Vec3(0, 7, 0), 2, new DiffuseLight(cs.illuminant(4.0))) )), SimpleCamera.builder() .withImage(height * 16 / 9, height) @@ -166,10 +166,10 @@ public class Examples { if (height <= 0) height = 600; var cs = ColorSpaces.sRGB; - var red = new LambertianMaterial(new ColorRGB(.65, .05, .05), cs); - var white = new LambertianMaterial(new ColorRGB(.73, .73, .73), cs); - var green = new LambertianMaterial(new ColorRGB(.12, .45, .15), cs); - var light = new DiffuseLight(new ColorRGB(15.0, 15.0, 15.0), cs); + var red = new LambertianMaterial(cs.albedo(.65, .05, .05)); + var white = new LambertianMaterial(cs.albedo(.73, .73, .73)); + var green = new LambertianMaterial(cs.albedo(.12, .45, .15)); + var light = new DiffuseLight(cs.illuminant(15.0)); return new Example( new Scene(List.of( @@ -194,10 +194,10 @@ public class Examples { public static @NotNull Example getCornellBoxSmoke(int height) { if (height <= 0) height = 600; var cs = ColorSpaces.sRGB; - var red = new LambertianMaterial(new ColorRGB(.65, .05, .05), cs); - var white = new LambertianMaterial(new ColorRGB(.73, .73, .73), cs); - var green = new LambertianMaterial(new ColorRGB(.12, .45, .15), cs); - var light = new DiffuseLight(new ColorRGB(15.0, 15.0, 15.0), cs); + var red = new LambertianMaterial(cs.albedo(.65, .05, .05)); + var white = new LambertianMaterial(cs.albedo(.73, .73, .73)); + var green = new LambertianMaterial(cs.albedo(.12, .45, .15)); + var light = new DiffuseLight(cs.illuminant(15.0)); return new Example( new Scene(List.of( @@ -207,13 +207,13 @@ public class Examples { new 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(ColorRGB.BLACK, cs) + 0.01, new IsotropicMaterial(cs.albedo(ColorRGB.BLACK)) ), new ConstantMedium( 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(ColorRGB.WHITE, cs) + 0.01, new IsotropicMaterial(cs.albedo(ColorRGB.WHITE)) ) )), SimpleCamera.builder() @@ -229,10 +229,10 @@ public class Examples { if (height <= 0) height = 600; var cs = ColorSpaces.sRGB; - var red = new LambertianMaterial(new ColorRGB(.65, .05, .05), cs); - var white = new LambertianMaterial(new ColorRGB(.73, .73, .73), cs); - var green = new LambertianMaterial(new ColorRGB(.12, .45, .15), cs); - var light = new DiffuseLight(new ColorRGB(7.0, 7.0, 7.0), cs); + var red = new LambertianMaterial(cs.albedo(.65, .05, .05)); + var white = new LambertianMaterial(cs.albedo(.73, .73, .73)); + var green = new LambertianMaterial(cs.albedo(.12, .45, .15)); + var light = new DiffuseLight(cs.illuminant(7.0)); var glass = new DielectricMaterial(1.5); var room = new Box(new Vec3(0, 0, 0), new Vec3(555, 555, 555), white, white, red, green, white, null); @@ -259,15 +259,15 @@ public class Examples { var cs = ColorSpaces.sRGB; record Partei(String name, ColorRGB color, double stimmen) { } var data = List.of( - new Partei("CDU", new ColorRGB(0x00, 0x4B, 0x76), 18.9), - new Partei("SPD", new ColorRGB(0xC0, 0x00, 0x3C), 25.7), - new Partei("AfD", new ColorRGB(0x80, 0xCD, 0xEC), 10.3), - new Partei("FDP", new ColorRGB(0xF7, 0xBB, 0x3D), 11.5), - new Partei("DIE LINKE", new ColorRGB(0x5F, 0x31, 0x6E), 4.9), - new Partei("GRÜNE", new ColorRGB(0x00, 0x85, 0x4A), 14.8), - new Partei("CSU", new ColorRGB(0x00, 0x77, 0xB6), 5.2) + new Partei("CDU", new ColorRGB(0x004B76), 18.9), + new Partei("SPD", new ColorRGB(0xC0003C), 25.7), + new Partei("AfD", new ColorRGB(0x80CDEC), 10.3), + new Partei("FDP", new ColorRGB(0xF7BB3D), 11.5), + new Partei("DIE LINKE", new ColorRGB(0x5F316E), 4.9), + new Partei("GRÜNE", new ColorRGB(0x00854A), 14.8), + new Partei("CSU", new ColorRGB(0x0077B6), 5.2) ); - var white = new LambertianMaterial(new ColorRGB(.99, .99, .99), cs); + var white = new LambertianMaterial(cs.albedo(.99, .99, .99)); var count = data.size(); var size = 75d; @@ -287,7 +287,7 @@ public class Examples { objects.add(new Box( new Vec3((i + 1) * spacing + i * size, 0, spacing), new Vec3((i + 1) * spacing + (i + 1) * size, partei.stimmen() * 15, spacing + size), - new DielectricMaterial(1.5, partei.color(), cs) + new DielectricMaterial(1.5, cs.albedo(partei.color())) )); } @@ -346,7 +346,7 @@ public class Examples { // boxes var boxes = new ArrayList(); - var ground = new LambertianMaterial(new ColorRGB(0.48, 0.83, 0.53), cs); + var ground = new LambertianMaterial(cs.albedo(0.48, 0.83, 0.53)); for (int i = 0; i < 20; i++) { for (int j = 0; j < 20; j++) { var w = 100.0; @@ -364,23 +364,23 @@ public class Examples { // light objects.add(new Parallelogram( new Vec3(123, 554, 147), new Vec3(300, 0, 0), new Vec3(0, 0, 265), - new DiffuseLight(new ColorRGB(7., 7., 7.), cs) + new DiffuseLight(cs.illuminant(7.0)) )); // spheres with different materials - objects.add(new Sphere(new Vec3(400, 400, 200), 50, new LambertianMaterial(new ColorRGB(0.7, 0.3, 0.1), cs))); + objects.add(new Sphere(new Vec3(400, 400, 200), 50, new LambertianMaterial(cs.albedo(0.7, 0.3, 0.1)))); objects.add(new Sphere(new Vec3(260, 150, 45), 50, new DielectricMaterial(1.5))); - objects.add(new Sphere(new Vec3(0, 150, 145), 50, new MetallicMaterial(new ColorRGB(0.8, 0.8, 0.9), cs, 1.0))); + objects.add(new Sphere(new Vec3(0, 150, 145), 50, new MetallicMaterial(cs.albedo(0.8, 0.8, 0.9), 1.0))); // glass sphere filled with gas var boundary = new Sphere(new Vec3(360, 150, 145), 70, new DielectricMaterial(1.5)); objects.add(boundary); - objects.add(new ConstantMedium(boundary, 0.2, new IsotropicMaterial(new ColorRGB(0.2, 0.4, 0.9), cs))); + objects.add(new ConstantMedium(boundary, 0.2, new IsotropicMaterial(cs.albedo(0.2, 0.4, 0.9)))); // put the world in a glass sphere objects.add(new ConstantMedium( new Sphere(new Vec3(0, 0, 0), 5000, new DielectricMaterial(1.5)), - 0.0001, new IsotropicMaterial(new ColorRGB(1., 1., 1.), cs) + 0.0001, new IsotropicMaterial(cs.albedo(1.0, 1.0, 1.0)) )); // textures spheres @@ -388,7 +388,7 @@ public class Examples { objects.add(new Sphere(new Vec3(220, 280, 300), 80, new LambertianMaterial(new PerlinTexture(0.2)))); // box from spheres - var white = new LambertianMaterial(new ColorRGB(.73, .73, .73), cs); + var white = new LambertianMaterial(cs.albedo(.73, .73, .73)); var spheres = new ArrayList(); for (int j = 0; j < 1000; j++) { spheres.add(new Sphere(new Vec3(random.nextDouble(165), random.nextDouble(165), random.nextDouble(165)), 10, white)); diff --git a/src/main/java/eu/jonahbauer/raytracing/render/color/ColorRGB.java b/src/main/java/eu/jonahbauer/raytracing/render/color/ColorRGB.java index fb4b460..012cbd4 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/color/ColorRGB.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/color/ColorRGB.java @@ -23,11 +23,7 @@ public record ColorRGB(double r, double g, double b) implements IVec3 } public ColorRGB(int rgb) { - this((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF); - } - - public ColorRGB(int red, int green, int blue) { - this(red / 255f, green / 255f, blue / 255f); + this(((rgb >> 16) & 0xFF) / 255d, ((rgb >> 8) & 0xFF) / 255d, (rgb & 0xFF) / 255d); } public ColorRGB { diff --git a/src/main/java/eu/jonahbauer/raytracing/render/color/ColorSpace.java b/src/main/java/eu/jonahbauer/raytracing/render/color/ColorSpace.java index 9d6b737..753d385 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/color/ColorSpace.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/color/ColorSpace.java @@ -2,8 +2,7 @@ package eu.jonahbauer.raytracing.render.color; import eu.jonahbauer.raytracing.math.Matrix3; import eu.jonahbauer.raytracing.math.Vec3; -import eu.jonahbauer.raytracing.render.spectrum.DenselySampledSpectrum; -import eu.jonahbauer.raytracing.render.spectrum.Spectrum; +import eu.jonahbauer.raytracing.render.spectrum.*; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -85,7 +84,7 @@ public final class ColorSpace { } } - public @NotNull SigmoidPolynomial toSpectrum(@NotNull ColorRGB rgb) { + public @NotNull SigmoidPolynomial toPolynomial(@NotNull ColorRGB rgb) { return RGBtoSpectrumTable.get(new ColorRGB( Math.max(0, rgb.r()), Math.max(0, rgb.g()), @@ -93,6 +92,38 @@ public final class ColorSpace { )); } + public @NotNull Spectrum toSpectrum(@NotNull ColorRGB rgb, @NotNull Spectrum.Type type) { + return switch (type) { + case ALBEDO -> new RGBAlbedoSpectrum(this, rgb); + case ILLUMINANT -> new RGBIlluminantSpectrum(this, rgb); + case UNBOUNDED -> new RGBUnboundedSpectrum(this, rgb); + }; + } + + public @NotNull Spectrum albedo(double r, double g, double b) { + return albedo(new ColorRGB(r, g, b)); + } + + public @NotNull Spectrum albedo(@NotNull ColorRGB rgb) { + return toSpectrum(rgb, Spectrum.Type.ALBEDO); + } + + public @NotNull Spectrum illuminant(double intensity) { + return illuminant.scale(intensity); + } + + public @NotNull Spectrum illuminant(double r, double g, double b) { + return illuminant(new ColorRGB(r, g, b)); + } + + public @NotNull Spectrum illuminant(@NotNull ColorRGB rgb) { + return toSpectrum(rgb, Spectrum.Type.ILLUMINANT); + } + + /* + * Accessors + */ + public @NotNull Chromaticity r() { return r; } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java b/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java index 507c007..55c2d72 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/DielectricMaterial.java @@ -2,9 +2,6 @@ package eu.jonahbauer.raytracing.render.material; import eu.jonahbauer.raytracing.math.Ray; import eu.jonahbauer.raytracing.math.Vec3; -import eu.jonahbauer.raytracing.render.color.ColorRGB; -import eu.jonahbauer.raytracing.render.color.ColorSpace; -import eu.jonahbauer.raytracing.render.spectrum.RGBAlbedoSpectrum; import eu.jonahbauer.raytracing.render.spectrum.Spectra; import eu.jonahbauer.raytracing.render.texture.Texture; import eu.jonahbauer.raytracing.scene.HitResult; @@ -14,25 +11,34 @@ import java.util.Objects; import java.util.Optional; import java.util.random.RandomGenerator; -public record DielectricMaterial(double refractionIndex, @NotNull Texture texture) implements Material { - public DielectricMaterial(double refractionIndex) { - this(refractionIndex, Spectra.WHITE); - } - +public record DielectricMaterial(@NotNull RefractiveIndex ri, @NotNull Texture texture) implements Material { public DielectricMaterial { + Objects.requireNonNull(ri, "ri"); Objects.requireNonNull(texture, "texture"); } - public DielectricMaterial(double refractionIndex, @NotNull ColorRGB color, @NotNull ColorSpace cs) { - this(refractionIndex, new RGBAlbedoSpectrum(cs, color)); + public DielectricMaterial(@NotNull RefractiveIndex ri) { + this(ri, Spectra.WHITE); + } + + public DielectricMaterial(double ri) { + this(new ConstantRefractiveIndex(ri), Spectra.WHITE); + } + + public DielectricMaterial(double ri, @NotNull Texture texture) { + this(new ConstantRefractiveIndex(ri), texture); } @Override public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { - var ri = hit.isFrontFace() ? (1 / refractionIndex) : refractionIndex; + var ri = switch (this.ri) { + case ConstantRefractiveIndex(var x) -> x; + case RefractiveIndex x -> x.get(ray.lambda().collapse()); + }; + if (hit.isFrontFace()) ri = 1 / ri; var cosTheta = Math.min(- ray.direction().unit().dot(hit.normal()), 1.0); - var reflectance = reflectance(cosTheta); + var reflectance = reflectance(cosTheta, ri); var reflect = reflectance > random.nextDouble(); var newDirection = (reflect ? Optional.empty() : Vec3.refract(ray.direction(), hit.normal(), ri)) @@ -42,10 +48,38 @@ public record DielectricMaterial(double refractionIndex, @NotNull Texture textur return Optional.of(new SpecularScatterResult(attenuation, new Ray(hit.position(), newDirection, ray.lambda()))); } - private double reflectance(double cos) { + private double reflectance(double cos, double ri) { // use schlick's approximation for reflectance - var r0 = (1 - refractionIndex) / (1 + refractionIndex); + var r0 = (1 - ri) / (1 + ri); r0 = r0 * r0; return r0 + (1 - r0) * (1 - cos) * (1 - cos) * (1 - cos) * (1 - cos) * (1 - cos); } + + @FunctionalInterface + public interface RefractiveIndex { + double get(double lambda); + } + + public record ConstantRefractiveIndex(double ri) implements RefractiveIndex { + + @Override + public double get(double lambda) { + return ri; + } + } + + public record SellmeierRefractiveIndex( + double B1, double B2, double B3, + double C1, double C2, double C3 + ) implements RefractiveIndex { + + @Override + public double get(double lambda) { + var l2 = lambda * lambda * 1E-6; // square and convert to µm + var x = 1 + B1 * l2 / (l2 - C1) + + B2 * l2 / (l2 - C2) + + B3 * l2 / (l2 - C3); + return Math.sqrt(x); + } + } } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/DiffuseLight.java b/src/main/java/eu/jonahbauer/raytracing/render/material/DiffuseLight.java index 09d7755..86d9ec1 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/material/DiffuseLight.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/DiffuseLight.java @@ -1,9 +1,6 @@ package eu.jonahbauer.raytracing.render.material; import eu.jonahbauer.raytracing.math.Ray; -import eu.jonahbauer.raytracing.render.color.ColorRGB; -import eu.jonahbauer.raytracing.render.color.ColorSpace; -import eu.jonahbauer.raytracing.render.spectrum.RGBIlluminantSpectrum; import eu.jonahbauer.raytracing.render.spectrum.Spectrum; import eu.jonahbauer.raytracing.render.texture.Texture; import eu.jonahbauer.raytracing.scene.HitResult; @@ -18,10 +15,6 @@ public record DiffuseLight(@NotNull Texture texture) implements Material { Objects.requireNonNull(texture, "texture"); } - public DiffuseLight(@NotNull ColorRGB color, @NotNull ColorSpace cs) { - this(new RGBIlluminantSpectrum(cs, color)); - } - @Override public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { return Optional.empty(); diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/IsotropicMaterial.java b/src/main/java/eu/jonahbauer/raytracing/render/material/IsotropicMaterial.java index 76a717d..02e6f55 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/material/IsotropicMaterial.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/IsotropicMaterial.java @@ -2,9 +2,6 @@ package eu.jonahbauer.raytracing.render.material; import eu.jonahbauer.raytracing.math.Ray; import eu.jonahbauer.raytracing.render.renderer.pdf.SphereProbabilityDensityFunction; -import eu.jonahbauer.raytracing.render.color.ColorRGB; -import eu.jonahbauer.raytracing.render.color.ColorSpace; -import eu.jonahbauer.raytracing.render.spectrum.RGBAlbedoSpectrum; import eu.jonahbauer.raytracing.render.spectrum.Spectrum; import eu.jonahbauer.raytracing.render.texture.Texture; import eu.jonahbauer.raytracing.scene.HitResult; @@ -19,10 +16,6 @@ public record IsotropicMaterial(@NotNull Spectrum albedo) implements Material { Objects.requireNonNull(albedo, "albedo"); } - public IsotropicMaterial(@NotNull ColorRGB color, @NotNull ColorSpace cs) { - this(new RGBAlbedoSpectrum(cs, color)); - } - @Override public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { return Optional.of(new PdfScatterResult(albedo(), new SphereProbabilityDensityFunction())); diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/LambertianMaterial.java b/src/main/java/eu/jonahbauer/raytracing/render/material/LambertianMaterial.java index dd76182..ffa218e 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/material/LambertianMaterial.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/LambertianMaterial.java @@ -2,9 +2,6 @@ package eu.jonahbauer.raytracing.render.material; import eu.jonahbauer.raytracing.math.Ray; import eu.jonahbauer.raytracing.render.renderer.pdf.CosineProbabilityDensityFunction; -import eu.jonahbauer.raytracing.render.color.ColorRGB; -import eu.jonahbauer.raytracing.render.color.ColorSpace; -import eu.jonahbauer.raytracing.render.spectrum.RGBAlbedoSpectrum; import eu.jonahbauer.raytracing.render.texture.Texture; import eu.jonahbauer.raytracing.scene.HitResult; import org.jetbrains.annotations.NotNull; @@ -18,10 +15,6 @@ public record LambertianMaterial(@NotNull Texture texture) implements Material { Objects.requireNonNull(texture, "texture"); } - public LambertianMaterial(@NotNull ColorRGB color, @NotNull ColorSpace cs) { - this(new RGBAlbedoSpectrum(cs, color)); - } - @Override public @NotNull Optional scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) { var attenuation = texture.get(hit); diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/Materials.java b/src/main/java/eu/jonahbauer/raytracing/render/material/Materials.java new file mode 100644 index 0000000..52f6c29 --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/Materials.java @@ -0,0 +1,25 @@ +package eu.jonahbauer.raytracing.render.material; + +import eu.jonahbauer.raytracing.render.color.ColorSpaces; +import eu.jonahbauer.raytracing.render.material.DielectricMaterial.SellmeierRefractiveIndex; +import eu.jonahbauer.raytracing.render.spectrum.Spectra; +import eu.jonahbauer.raytracing.render.texture.CheckerTexture; +import org.jetbrains.annotations.NotNull; + +public final class Materials { + public static final @NotNull Material GLASS = new DielectricMaterial(new SellmeierRefractiveIndex( + 1.0361212, 0.231792344, 1.01046945, + 6.00069867E-3, 2.00179144E-2, 1.03560653E2 + )); + + public static final @NotNull Material MIRROR = new MetallicMaterial(ColorSpaces.sRGB.albedo(0.7, 0.7, 0.7)); + + public static final @NotNull Material DEBUG = new DirectionalMaterial( + new LambertianMaterial(new CheckerTexture(50.0, ColorSpaces.sRGB.albedo(1.0, 0.0, 1.0), Spectra.BLACK)), + new LambertianMaterial(new CheckerTexture(50.0, ColorSpaces.sRGB.albedo(1.0, 1.0, 1.0), Spectra.BLACK)) + ); + + private Materials() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java b/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java index 5024423..bb48815 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/material/MetallicMaterial.java @@ -2,9 +2,6 @@ package eu.jonahbauer.raytracing.render.material; import eu.jonahbauer.raytracing.math.Ray; import eu.jonahbauer.raytracing.math.Vec3; -import eu.jonahbauer.raytracing.render.color.ColorRGB; -import eu.jonahbauer.raytracing.render.color.ColorSpace; -import eu.jonahbauer.raytracing.render.spectrum.RGBAlbedoSpectrum; import eu.jonahbauer.raytracing.render.texture.Texture; import eu.jonahbauer.raytracing.scene.HitResult; import org.jetbrains.annotations.NotNull; @@ -19,14 +16,6 @@ public record MetallicMaterial(@NotNull Texture texture, double fuzz) implements this(texture, 0); } - public MetallicMaterial(@NotNull ColorRGB color, @NotNull ColorSpace cs) { - this(color, cs, 0); - } - - public MetallicMaterial(@NotNull ColorRGB color, @NotNull ColorSpace cs, double fuzz) { - this(new RGBAlbedoSpectrum(cs, color), fuzz); - } - public MetallicMaterial { Objects.requireNonNull(texture, "texture"); if (fuzz < 0 || !Double.isFinite(fuzz)) throw new IllegalArgumentException("fuzz must be non-negative"); diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBAlbedoSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBAlbedoSpectrum.java index 9007e70..ffbb033 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBAlbedoSpectrum.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBAlbedoSpectrum.java @@ -12,7 +12,7 @@ public final class RGBAlbedoSpectrum implements Spectrum { if (rgb.r() < 0 || rgb.r() > 1 || rgb.g() < 0 || rgb.g() > 1 || rgb.b() < 0 || rgb.b() > 1) { throw new IllegalArgumentException(); } - this.polynomial = cs.toSpectrum(rgb); + this.polynomial = cs.toPolynomial(rgb); } @Override diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBIlluminantSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBIlluminantSpectrum.java index 52b9781..222eddf 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBIlluminantSpectrum.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBIlluminantSpectrum.java @@ -20,7 +20,7 @@ public final class RGBIlluminantSpectrum implements Spectrum { } var max = Math.max(rgb.r(), Math.max(rgb.g(), rgb.b())); this.scale = 2 * max; - this.polynomial = cs.toSpectrum(scale != 0 ? rgb.div(scale) : ColorRGB.BLACK); + this.polynomial = cs.toPolynomial(scale != 0 ? rgb.div(scale) : ColorRGB.BLACK); this.illuminant = cs.illuminant(); } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBUnboundedSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBUnboundedSpectrum.java index 232c7fa..ab5b155 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBUnboundedSpectrum.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/RGBUnboundedSpectrum.java @@ -15,7 +15,7 @@ public final class RGBUnboundedSpectrum implements Spectrum { } var max = Math.max(rgb.r(), Math.max(rgb.g(), rgb.b())); this.scale = 2 * max; - this.polynomial = cs.toSpectrum(scale != 0 ? rgb.div(scale) : ColorRGB.BLACK); + this.polynomial = cs.toPolynomial(scale != 0 ? rgb.div(scale) : ColorRGB.BLACK); } @Override diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/Spectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/Spectrum.java index c96a110..ccdb38e 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/spectrum/Spectrum.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectrum/Spectrum.java @@ -72,4 +72,8 @@ public interface Spectrum extends Texture, SkyBox { default @NotNull SampledSpectrum getColor(@NotNull Ray ray) { return this.sample(ray.lambda()); } + + enum Type { + ALBEDO, ILLUMINANT, UNBOUNDED + } } diff --git a/src/main/java/eu/jonahbauer/raytracing/render/texture/ImageTexture.java b/src/main/java/eu/jonahbauer/raytracing/render/texture/ImageTexture.java index 08cf60a..c4b9db8 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/texture/ImageTexture.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/texture/ImageTexture.java @@ -3,8 +3,6 @@ package eu.jonahbauer.raytracing.render.texture; import eu.jonahbauer.raytracing.math.Vec3; import eu.jonahbauer.raytracing.render.color.ColorRGB; import eu.jonahbauer.raytracing.render.color.ColorSpace; -import eu.jonahbauer.raytracing.render.spectrum.RGBAlbedoSpectrum; -import eu.jonahbauer.raytracing.render.spectrum.RGBIlluminantSpectrum; import eu.jonahbauer.raytracing.render.spectrum.Spectrum; import org.jetbrains.annotations.NotNull; @@ -21,7 +19,7 @@ public final class ImageTexture implements Texture { private final int height; private final @NotNull Spectrum[][] spectra; - public ImageTexture(@NotNull BufferedImage image, @NotNull ColorSpace cs, @NotNull Type type, boolean gamma) { + public ImageTexture(@NotNull BufferedImage image, @NotNull ColorSpace cs, @NotNull Spectrum.Type type, boolean gamma) { this.width = image.getWidth(); this.height = image.getHeight(); this.spectra = new Spectrum[height][width]; @@ -30,13 +28,13 @@ public final class ImageTexture implements Texture { for (int x = 0; x < width; x++) { var rgb = new ColorRGB(image.getRGB(x, y)); if (gamma) rgb = ColorRGB.inverseGamma(rgb); - spectra[y][x] = type.newSpectrum(cs, rgb); + spectra[y][x] = cs.toSpectrum(rgb, type); } } } public ImageTexture(@NotNull String path, @NotNull ColorSpace cs) { - this(read(path), cs, Type.ALBEDO, true); + this(read(path), cs, Spectrum.Type.ALBEDO, true); } private static @NotNull BufferedImage read(@NotNull String path) { @@ -55,22 +53,4 @@ public final class ImageTexture implements Texture { int y = (int) (v * (height - 1)); return spectra[y][x]; } - - public enum Type { - ALBEDO { - @Override - protected @NotNull Spectrum newSpectrum(@NotNull ColorSpace cs, @NotNull ColorRGB rgb) { - return new RGBAlbedoSpectrum(cs, rgb); - } - }, - ILLUMINANT { - @Override - protected @NotNull Spectrum newSpectrum(@NotNull ColorSpace cs, @NotNull ColorRGB rgb) { - return new RGBIlluminantSpectrum(cs, rgb); - } - }, - ; - - protected abstract @NotNull Spectrum newSpectrum(@NotNull ColorSpace cs, @NotNull ColorRGB rgb); - } }