diff --git a/src/main/java/eu/jonahbauer/raytracing/Examples.java b/src/main/java/eu/jonahbauer/raytracing/Examples.java index 401be82..bb545d2 100644 --- a/src/main/java/eu/jonahbauer/raytracing/Examples.java +++ b/src/main/java/eu/jonahbauer/raytracing/Examples.java @@ -1,6 +1,5 @@ package eu.jonahbauer.raytracing; -import eu.jonahbauer.raytracing.math.AABB; import eu.jonahbauer.raytracing.math.Vec3; import eu.jonahbauer.raytracing.render.texture.CheckerTexture; import eu.jonahbauer.raytracing.render.texture.Color; @@ -293,7 +292,7 @@ public class Examples { return new Example( new Scene(getSkyBox(), List.of( - new Sphere(Vec3.ZERO, 2, new LambertianMaterial(new ImageTexture("/earthmap.jpg"))) + new Sphere(Vec3.ZERO, 2, new LambertianMaterial(new ImageTexture("/eu/jonahbauer/raytracing/textures/earthmap.jpg"))) )), SimpleCamera.builder() .withImage(height * 16 / 9, height) @@ -369,7 +368,7 @@ public class Examples { )); // textures spheres - objects.add(new Sphere(new Vec3(400, 200, 400), 100, new LambertianMaterial(new ImageTexture("/earthmap.jpg")))); + objects.add(new Sphere(new Vec3(400, 200, 400), 100, new LambertianMaterial(new ImageTexture("/eu/jonahbauer/raytracing/textures/earthmap.jpg")))); objects.add(new Sphere(new Vec3(220, 280, 300), 80, new LambertianMaterial(new PerlinTexture(0.2)))); // box from spheres diff --git a/src/main/java/eu/jonahbauer/raytracing/math/Matrix3.java b/src/main/java/eu/jonahbauer/raytracing/math/Matrix3.java new file mode 100644 index 0000000..e69f0bd --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/math/Matrix3.java @@ -0,0 +1,72 @@ +package eu.jonahbauer.raytracing.math; + +import org.jetbrains.annotations.NotNull; + +public record Matrix3( + double a11, double a12, double a13, + double a21, double a22, double a23, + double a31, double a32, double a33 +) { + + public Matrix3() { + this(1, 1, 1); + } + + public Matrix3(double a11, double a22, double a33) { + this(a11, 0, 0, 0, a22, 0, 0, 0, a33); + } + + public @NotNull Matrix3 times(@NotNull Matrix3 other) { + return new Matrix3( + a11 * other.a11 + a12 * other.a21 + a13 * other.a31, + a11 * other.a12 + a12 * other.a22 + a13 * other.a32, + a11 * other.a13 + a12 * other.a23 + a13 * other.a33, + a21 * other.a11 + a22 * other.a21 + a23 * other.a31, + a21 * other.a12 + a22 * other.a22 + a23 * other.a32, + a21 * other.a13 + a22 * other.a23 + a23 * other.a33, + a31 * other.a11 + a32 * other.a21 + a33 * other.a31, + a31 * other.a12 + a32 * other.a22 + a33 * other.a32, + a31 * other.a13 + a32 * other.a23 + a33 * other.a33 + ); + } + + public @NotNull Matrix3 times(double other) { + return new Matrix3( + a11 * other, a12 * other, a13 * other, + a21 * other, a22 * other, a23 * other, + a31 * other, a32 * other, a33 * other + ); + } + + public @NotNull Vec3 times(@NotNull Vec3 other) { + return new Vec3( + a11 * other.x() + a12 * other.y() + a13 * other.z(), + a21 * other.x() + a22 * other.y() + a23 * other.z(), + a31 * other.x() + a32 * other.y() + a33 * other.z() + ); + } + + public @NotNull Matrix3 plus(@NotNull Matrix3 other) { + return new Matrix3( + a11 + other.a11, a12 + other.a12, a13 + other.a13, + a21 + other.a21, a22 + other.a22, a23 + other.a23, + a31 + other.a31, a32 + other.a32, a33 + other.a33 + ); + } + + public double det() { + return a11 * a22 * a33 + a12 * a23 * a31 + a13 * a21 * a32 + - a13 * a22 * a31 - a23 * a32 * a11 - a33 * a12 * a21; + } + + public @NotNull Matrix3 invert() { + var det = det(); + if (det == 0) throw new IllegalStateException(); + var t = 1 / det; + return new Matrix3( + t * (a22 * a33 - a23 * a32), t * (-a12 * a33 + a13 * a32), t * (a12 * a23 - a13 * a22), + t * (-a21 * a33 + a23 * a31), t * (a11 * a33 - a13 * a31), t * (-a11 * a23 + a13 * a21), + t * (a21 * a32 - a22 * a31), t * (a11 * a32 + a12 * a31), t * (a11 * a22 - a12 * a21) + ); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/SampledSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/SampledSpectrum.java new file mode 100644 index 0000000..df65d0b --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/SampledSpectrum.java @@ -0,0 +1,76 @@ +package eu.jonahbauer.raytracing.render.spectral; + +import eu.jonahbauer.raytracing.render.spectral.colors.ColorSpace; +import eu.jonahbauer.raytracing.render.spectral.colors.ColorXYZ; +import eu.jonahbauer.raytracing.render.spectral.spectrum.Spectrum; +import eu.jonahbauer.raytracing.render.texture.Color; +import org.jetbrains.annotations.NotNull; + +public final class SampledSpectrum { + private final double @NotNull[] values; + + + public static void main(String[] args) { + System.out.println(); + } + + public SampledSpectrum(@NotNull SampledWavelengths lambdas, @NotNull Spectrum spectrum) { + var values = new double[lambdas.size()]; + for (int i = 0; i < values.length; i++) { + values[i] = spectrum.get(lambdas.get(i)); + } + this.values = values; + } + + private SampledSpectrum(double @NotNull[] values) { + this.values = values; + } + + public static @NotNull SampledSpectrum multiply(@NotNull SampledSpectrum a, @NotNull SampledSpectrum b) { + var out = new double[a.values.length]; + for (int i = 0; i < a.values.length; i++) { + out[i] = a.values[i] * b.values[i]; + } + return new SampledSpectrum(out); + } + + public static @NotNull SampledSpectrum multiply(@NotNull SampledSpectrum a, double b) { + var out = new double[a.values.length]; + for (int i = 0; i < a.values.length; i++) { + out[i] = a.values[i] * b; + } + return new SampledSpectrum(out); + } + + public static @NotNull SampledSpectrum add(@NotNull SampledSpectrum a, @NotNull SampledSpectrum b) { + var out = new double[a.values.length]; + for (int i = 0; i < a.values.length; i++) { + out[i] = a.values[i] + b.values[i]; + } + return new SampledSpectrum(out); + } + + public double get(int index) { + return values[index]; + } + + public int size() { + return values.length; + } + + public double average() { + double avg = 0; + for (int i = 0; i < values.length; i++) { + avg = Math.fma(1d / (i + 1), values[i] - avg, avg); + } + return avg; + } + + public @NotNull ColorXYZ toXYZ(@NotNull SampledWavelengths lambdas) { + return lambdas.toXYZ(this); + } + + public @NotNull Color toRGB(@NotNull SampledWavelengths lambdas, @NotNull ColorSpace cs) { + return cs.toRGB(toXYZ(lambdas)); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/SampledWavelengths.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/SampledWavelengths.java new file mode 100644 index 0000000..a22f21f --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/SampledWavelengths.java @@ -0,0 +1,91 @@ +package eu.jonahbauer.raytracing.render.spectral; + +import eu.jonahbauer.raytracing.render.spectral.colors.ColorXYZ; +import eu.jonahbauer.raytracing.render.spectral.spectrum.Spectra; +import eu.jonahbauer.raytracing.render.spectral.spectrum.Spectrum; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * A set of sampled wavelength that can be tracked together. + */ +public final class SampledWavelengths { + private final double @NotNull[] lambdas; + private final double @NotNull[] pdf; + + public static @NotNull SampledWavelengths uniform(double rng) { + return uniform(rng, Spectrum.LAMBDA_MIN, Spectrum.LAMBDA_MAX); + } + + public static @NotNull SampledWavelengths uniform(double rng, double min, double max) { + var lambdas = new double[Spectrum.SAMPLES]; + + // choose first sample at random + lambdas[0] = (1 - rng) * min + rng * max; + + // choose next samples in equal intervals, wrapping if necessary + var delta = (max - min) / Spectrum.SAMPLES; + for (int i = 1; i < Spectrum.SAMPLES; i++) { + lambdas[i] = lambdas[i - 1] + delta; + if (lambdas[i] > max) { + lambdas[i] = min + (lambdas[i] - max); + } + } + + var pdf = new double[Spectrum.SAMPLES]; + Arrays.fill(pdf, 1 / (max - min)); + return new SampledWavelengths(lambdas, pdf); + } + + private SampledWavelengths(double @NotNull[] lambdas, double @NotNull[] pdf) { + this.lambdas = lambdas; + this.pdf = pdf; + } + + public double get(int index) { + return lambdas[index]; + } + + public int size() { + return lambdas.length; + } + + /** + * Terminates the secondary wavelengths. This method should be called after a wavelength-dependent operation like + * refraction that makes it incorrect to track multiple wavelengths together. + */ + public void terminateSecondary() { + if (pdf.length < 2 || pdf[1] == 0) return; + Arrays.fill(pdf, 1, pdf.length, 0d); + pdf[0] /= pdf.length; + } + + @NotNull + ColorXYZ toXYZ(@NotNull SampledSpectrum spectrum) { + var x = Spectra.X.sample(this); + var y = Spectra.Y.sample(this); + var z = Spectra.Z.sample(this); + + return new ColorXYZ( + toXYZ0(spectrum, x) / ColorXYZ.CIE_Y_INTEGRAL, + toXYZ0(spectrum, y) / ColorXYZ.CIE_Y_INTEGRAL, + toXYZ0(spectrum, z) / ColorXYZ.CIE_Y_INTEGRAL + ); + } + + private double toXYZ0(@NotNull SampledSpectrum spectrum, @NotNull SampledSpectrum cie) { + var avg = 0d; + for (int i = 0; i < spectrum.size(); i++) { + var pdf = this.pdf[i]; + double value; + if (pdf == 0) { + value = 0; + } else { + value = spectrum.get(i) * cie.get(i) / pdf; + } + avg = Math.fma(1d / (i + 1), value - avg, avg); + } + return avg; + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/Chromaticity.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/Chromaticity.java new file mode 100644 index 0000000..24dea8a --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/Chromaticity.java @@ -0,0 +1,4 @@ +package eu.jonahbauer.raytracing.render.spectral.colors; + +public record Chromaticity(double x, double y) { +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorSpace.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorSpace.java new file mode 100644 index 0000000..657502e --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorSpace.java @@ -0,0 +1,90 @@ +package eu.jonahbauer.raytracing.render.spectral.colors; + +import eu.jonahbauer.raytracing.math.Matrix3; +import eu.jonahbauer.raytracing.render.spectral.spectrum.DenselySampledSpectrum; +import eu.jonahbauer.raytracing.render.spectral.spectrum.Spectrum; +import eu.jonahbauer.raytracing.render.texture.Color; +import org.jetbrains.annotations.NotNull; + +import java.util.NoSuchElementException; +import java.util.Objects; + +/** + * An RGB color space. + */ +public final class ColorSpace { + private final @NotNull Chromaticity r; + private final @NotNull Chromaticity g; + private final @NotNull Chromaticity b; + private final @NotNull Chromaticity w; + private final @NotNull DenselySampledSpectrum illuminant; + + private final @NotNull Matrix3 XYZfromRGB; + private final @NotNull Matrix3 RGBfromXYZ; + private final @NotNull SpectrumTable RGBtoSpectrumTable; + + public ColorSpace( + @NotNull Chromaticity r, @NotNull Chromaticity g, @NotNull Chromaticity b, + @NotNull Spectrum illuminant, @NotNull SpectrumTable table + ) { + this.r = Objects.requireNonNull(r, "r"); + this.g = Objects.requireNonNull(r, "g"); + this.b = Objects.requireNonNull(r, "b"); + this.illuminant = new DenselySampledSpectrum(illuminant); + this.RGBtoSpectrumTable = table; + + var W = illuminant.toXYZ(); + this.w = W.xy(); + + var R = new ColorXYZ(r); + var G = new ColorXYZ(g); + var B = new ColorXYZ(b); + var rgb = new Matrix3( + R.x(), G.x(), B.x(), + R.y(), G.y(), B.y(), + R.z(), G.z(), B.z() + ); + var C = rgb.invert().times(W.toVec3()); + + this.XYZfromRGB = rgb.times(new Matrix3(C.x(), C.y(), C.z())); + this.RGBfromXYZ = XYZfromRGB.invert(); + } + + public @NotNull Color toRGB(@NotNull ColorXYZ xyz) { + var out = RGBfromXYZ.times(xyz.toVec3()); + return new Color(out.x(), out.y(), out.z()); + } + + public @NotNull ColorXYZ toXYZ(@NotNull Color rgb) { + var out = XYZfromRGB.times(rgb.toVec3()); + return new ColorXYZ(out); + } + + public @NotNull SigmoidPolynomial toSpectrum(@NotNull Color rgb) { + return RGBtoSpectrumTable.get(new Color( + Math.max(0, rgb.r()), + Math.max(0, rgb.g()), + Math.max(0, rgb.b()) + )); + } + + public @NotNull Chromaticity r() { + return r; + } + + public @NotNull Chromaticity g() { + return g; + } + + public @NotNull Chromaticity b() { + return b; + } + + public @NotNull Chromaticity w() { + return w; + } + + public @NotNull DenselySampledSpectrum illuminant() { + return illuminant; + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorSpaces.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorSpaces.java new file mode 100644 index 0000000..c1509c2 --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorSpaces.java @@ -0,0 +1,29 @@ +package eu.jonahbauer.raytracing.render.spectral.colors; + +import eu.jonahbauer.raytracing.render.spectral.spectrum.Spectra; +import org.jetbrains.annotations.NotNull; + +public final class ColorSpaces { + public static final @NotNull ColorSpace sRGB = new ColorSpace( + new Chromaticity(0.6400, 0.3300), + new Chromaticity(0.3000, 0.6000), + new Chromaticity(0.1500, 0.0600), + Spectra.D65, null + ); + public static final @NotNull ColorSpace DCI_P3 = new ColorSpace( + new Chromaticity(0.680, 0.320), + new Chromaticity(0.265, 0.690), + new Chromaticity(0.150, 0.060), + Spectra.D65, null + ); + public static final @NotNull ColorSpace Rec2020 = new ColorSpace( + new Chromaticity(0.708, 0.292), + new Chromaticity(0.170, 0.797), + new Chromaticity(0.131, 0.046), + Spectra.D65, null + ); + + private ColorSpaces() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorXYZ.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorXYZ.java new file mode 100644 index 0000000..eb0147b --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/ColorXYZ.java @@ -0,0 +1,52 @@ +package eu.jonahbauer.raytracing.render.spectral.colors; + +import eu.jonahbauer.raytracing.math.Vec3; +import org.jetbrains.annotations.NotNull; + +/** + * A CIE XYZ color + */ +public record ColorXYZ(double x, double y, double z) { + public static final double CIE_Y_INTEGRAL = 106.85689500000002; + + public ColorXYZ(@NotNull Chromaticity chromaticity) { + this(chromaticity, 1); + } + + public ColorXYZ(@NotNull Chromaticity chromaticity, double Y) { + this( + chromaticity.y() == 0 ? 0 : Y * chromaticity.x() / chromaticity.y(), + chromaticity.y() == 0 ? 0 : Y, + chromaticity.y() == 0 ? 0 : Y * (1 - chromaticity.x() - chromaticity.y()) / chromaticity.y() + ); + } + + public ColorXYZ(@NotNull Vec3 vec) { + this(vec.x(), vec.y(), vec.z()); + } + + public double average() { + return (x + y + z) / 3; + } + + public @NotNull Chromaticity xy() { + var factor = 1 / (x + y + z); + return new Chromaticity(factor * x, factor * y); + } + + public @NotNull Vec3 toVec3() { + return new Vec3(x, y, z); + } + + public static @NotNull ColorXYZ multiply(@NotNull ColorXYZ a, @NotNull ColorXYZ b) { + return new ColorXYZ(a.x * b.x, a.y * b.y, a.z * b.z); + } + + public static @NotNull ColorXYZ multiply(@NotNull ColorXYZ a, double b) { + return new ColorXYZ(a.x * b, a.y * b, a.z * b); + } + + public static @NotNull ColorXYZ add(@NotNull ColorXYZ a, @NotNull ColorXYZ b) { + return new ColorXYZ(a.x + b.x, a.y + b.y, a.z + b.z); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/SigmoidPolynomial.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/SigmoidPolynomial.java new file mode 100644 index 0000000..ca9aa7c --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/SigmoidPolynomial.java @@ -0,0 +1,34 @@ +package eu.jonahbauer.raytracing.render.spectral.colors; + +import eu.jonahbauer.raytracing.render.spectral.spectrum.Spectrum; + +/** + * A function of the form {@code s(p(x))} where {@code p} is a polynomial of second degree and {@code s} is the sigmoid + * function s(x) = 0.5 + x / (2 * sqrt(1 + x^2)). + *

+ * A function of this form is used to generate a {@link Spectrum} from an RGB value. + * + * @param c0 the coefficient of the quadratic term + * @param c1 the coefficient of the linear term + * @param c2 the coefficient of the constant term + */ +public record SigmoidPolynomial(double c0, double c1, double c2) { + + public double get(double x) { + var p = Math.fma(x, Math.fma(x, c0, c1), c2); + if (!Double.isFinite(p)) return p > 0 ? 1 : 0; + return .5 + x / (p * Math.sqrt(1 + p * p)); + } + + public double max() { + // evaluate at the edges + var result = Math.max(get(Spectrum.LAMBDA_MIN), get(Spectrum.LAMBDA_MAX)); + var lambda = -c1 / (2 * c0); + if (lambda >= 360 && lambda <= 830) { + // evaluate at the vertex + return Math.max(result, get(lambda)); + } else { + return result; + } + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/SpectrumTable.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/SpectrumTable.java new file mode 100644 index 0000000..c7f4def --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/colors/SpectrumTable.java @@ -0,0 +1,91 @@ +package eu.jonahbauer.raytracing.render.spectral.colors; + +import eu.jonahbauer.raytracing.render.texture.Color; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * A table of sigmoid polynomials used to convert between RGB values and spectra. + *

+ * The rgb values are renormalized to xyz coordinates with {@code z} being the largest of the rgb components, and + * {@code x} and {@code y} being the other two rgb components divided by {@code z}. By this construction, {@code x}, + * {@code y} and {@code z} are all in the range [0, 1] which allows for better use of the samples in a fixed grid. + * The {@code z} coordinate is additionally remapped using {@link #zNodes} to improve sampling at both ends of the scale. + *

+ * The coefficients of the sigmoid functions are stored in a five-dimensional array with indices as described in + * {@link #coefficients}. + */ +public final class SpectrumTable { + private static final int RESOLUTION = 64; + + /** + * the remapped {@code z} values + */ + private final double[] zNodes; + + /** + * the stored coefficients, with the following indices + *

    + *
  1. the component index of the biggest rgb component
  2. + *
  3. the {@code z} coordinate
  4. + *
  5. the {@code y} coordinate
  6. + *
  7. the {@code x} coordinate
  8. + *
  9. the coefficient index
  10. + *
+ */ + private final double[][][][][] coefficients; + + public SpectrumTable(double[] zNodes, double[][][][][] coefficients) { + this.zNodes = zNodes; + this.coefficients = coefficients; + } + + public @NotNull SigmoidPolynomial get(@NotNull Color color) { + // handle uniform rgb values + if (color.r() == color.g() && color.g() == color.b()) { + return new SigmoidPolynomial(0, 0, (color.r() - .5) / Math.sqrt(color.r() * (1 - color.r()))); + } + + // find maximum component and compute remapped component values + var max = color.r() > color.g() + ? (color.r() > color.b() ? 0 : 2) + : (color.g() > color.b() ? 1 : 2); + + var z = color.component(max); + var x = color.component((max + 1) % 3) * (RESOLUTION - 1) / z; + var y = color.component((max + 2) % 3) * (RESOLUTION - 1) / z; + + // compute integer indices and offsets for coefficient interpolation + int xi = Math.min((int) x, RESOLUTION - 2); + int yi = Math.min((int) y, RESOLUTION - 2); + int zi = Arrays.binarySearch(zNodes, z); + if (zi < 0) zi = -zi - 1; + zi++; + + var dx = x - xi; + var dy = y -yi; + var dz = (z - zNodes[zi]) / (zNodes[zi + 1] - zNodes[zi]); + + // trilinearly interpolate sigmoid polynomial coefficients + var c = new double[3]; + for (int i = 0; i < 3; i++) { + c[i] = lerp(dz, + lerp(dy, + lerp(dx, coefficients[max][zi + 0][yi + 0][xi + 0][i], coefficients[max][zi + 0][yi + 0][xi + 1][i]), + lerp(dx, coefficients[max][zi + 0][yi + 1][xi + 0][i], coefficients[max][zi + 0][yi + 1][xi + 1][i]) + ), + lerp(dy, + lerp(dx, coefficients[max][zi + 1][yi + 0][xi + 0][i], coefficients[max][zi + 1][yi + 0][xi + 1][i]), + lerp(dx, coefficients[max][zi + 1][yi + 1][xi + 0][i], coefficients[max][zi + 1][yi + 1][xi + 1][i]) + ) + ); + } + + return new SigmoidPolynomial(c[0], c[1], c[2]); + } + + private static double lerp(double t, double a, double b) { + return Math.fma(t, b, Math.fma(-t, a, a)); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/BlackbodySpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/BlackbodySpectrum.java new file mode 100644 index 0000000..4a07f8b --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/BlackbodySpectrum.java @@ -0,0 +1,45 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +public final class BlackbodySpectrum implements Spectrum { + /** + * the speed of light in m/s + */ + private static final double c = 299792458d; + + /** + * the planck constant in m^2*kg/s + */ + private static final double h = 6.62607015E-34; + + /** + * the boltzmann constant in m^2*kg/s^2/K + */ + private static final double k = 1.380649E-23; + + /** + * wien's displacement constant in m*K + */ + private static final double b = 2.897771995E-3; + + private final double T; + private final double factor; + + public BlackbodySpectrum(double T) { + if (T < 0) throw new IllegalArgumentException("T must be non-negative"); + this.T = T; + this.factor = 1 / get(b / T); + } + + @Override + public double max() { + return 1; + } + + @Override + public double get(double lambda) { + lambda *= 1E-9; + var l2 = lambda * lambda; + var x = h * c / (lambda * k * T); + return 2 * h * c * c / (l2 * l2 * lambda) / (Math.exp(x) - 1) * factor; + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/ConstantSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/ConstantSpectrum.java new file mode 100644 index 0000000..e5348da --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/ConstantSpectrum.java @@ -0,0 +1,17 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +/** + * A constant spectrum. + * @param c the constant value + */ +public record ConstantSpectrum(double c) implements Spectrum { + @Override + public double max() { + return c; + } + + @Override + public double get(double lambda) { + return c; + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/DenselySampledSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/DenselySampledSpectrum.java new file mode 100644 index 0000000..9fdb61e --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/DenselySampledSpectrum.java @@ -0,0 +1,51 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * A spectrum sampled in one nanometer intervals. + */ +public final class DenselySampledSpectrum implements Spectrum { + private final double[] samples; + private final int min; + + private final double max; + + public DenselySampledSpectrum(@NotNull Spectrum spectrum) { + this(spectrum, LAMBDA_MIN, LAMBDA_MAX); + } + + public DenselySampledSpectrum(@NotNull Spectrum spectrum, int min, int max) { + if (max - min + 1 <= 0) throw new IllegalArgumentException("samples must not be empty"); + this.samples = new double[max - min + 1]; + var maxValue = 0d; + for (int lambda = min; lambda <= max; lambda++) { + var sample = spectrum.get(lambda); + if (sample > maxValue) maxValue = sample; + this.samples[lambda] = sample; + } + this.min = min; + this.max = maxValue; + } + + public DenselySampledSpectrum(double @NotNull[] samples, int lambdaMin) { + if (samples.length == 0) throw new IllegalArgumentException("samples must not be empty"); + this.samples = Arrays.copyOf(samples, samples.length); + this.min = lambdaMin; + this.max = Arrays.stream(this.samples).max().orElseThrow(); + } + + @Override + public double max() { + return max; + } + + @Override + public double get(double lambda) { + int offset = (int) Math.round(lambda) - min; + if (offset < 0 || offset >= samples.length) return 0; + return samples[offset]; + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/PiecewiseLinearSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/PiecewiseLinearSpectrum.java new file mode 100644 index 0000000..c6c4c3d --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/PiecewiseLinearSpectrum.java @@ -0,0 +1,48 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +import java.util.Arrays; + +public final class PiecewiseLinearSpectrum implements Spectrum { + private final double[] lambdas; + private final double[] values; + private final double max; + + public PiecewiseLinearSpectrum(double[] lambdas, double[] values) { + if (lambdas.length != values.length) { + throw new IllegalArgumentException("lambdas and values must have the same length"); + } + + this.lambdas = Arrays.copyOf(lambdas, lambdas.length); + this.values = Arrays.copyOf(values, values.length); + + var max = 0d; + for (int i = 1; i < this.lambdas.length; i++) { + if (this.lambdas[i] <= this.lambdas[i - 1]) { + throw new IllegalArgumentException("lambdas must be in increasing order"); + } + if (this.values[i] < 0) { + throw new IllegalArgumentException("values must be non-negative"); + } else if (this.values[i] > max) { + max = this.values[i]; + } + } + this.max = max; + } + + @Override + public double max() { + return max; + } + + @Override + public double get(double lambda) { + if (lambdas.length == 0 || lambda < lambdas[0] || lambda > lambdas[lambdas.length - 1]) return 0; + if (lambda == lambdas[lambdas.length - 1]) return values[values.length - 1]; + + var i = Arrays.binarySearch(lambdas, lambda); + if (i < 0) i = -i - 1; + + var t = (lambda - lambdas[i]) / (lambdas[i + 1] - lambdas[i]); + return (1 - t) * values[i] + t * values[i + 1]; + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBAlbedoSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBAlbedoSpectrum.java new file mode 100644 index 0000000..58b9d21 --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBAlbedoSpectrum.java @@ -0,0 +1,27 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +import eu.jonahbauer.raytracing.render.spectral.colors.ColorSpace; +import eu.jonahbauer.raytracing.render.spectral.colors.SigmoidPolynomial; +import eu.jonahbauer.raytracing.render.texture.Color; +import org.jetbrains.annotations.NotNull; + +public final class RGBAlbedoSpectrum implements Spectrum { + private final @NotNull SigmoidPolynomial polynomial; + + public RGBAlbedoSpectrum(@NotNull ColorSpace cs, @NotNull Color rgb) { + 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); + } + + @Override + public double max() { + return polynomial.max(); + } + + @Override + public double get(double lambda) { + return polynomial.get(lambda); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBIlluminantSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBIlluminantSpectrum.java new file mode 100644 index 0000000..a6dbf95 --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBIlluminantSpectrum.java @@ -0,0 +1,32 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +import eu.jonahbauer.raytracing.render.spectral.colors.ColorSpace; +import eu.jonahbauer.raytracing.render.spectral.colors.SigmoidPolynomial; +import eu.jonahbauer.raytracing.render.texture.Color; +import org.jetbrains.annotations.NotNull; + +public final class RGBIlluminantSpectrum implements Spectrum { + private final double scale; + private final @NotNull SigmoidPolynomial polynomial; + private final @NotNull DenselySampledSpectrum illuminant; + + public RGBIlluminantSpectrum(@NotNull ColorSpace cs, @NotNull Color rgb) { + if (rgb.r() < 0 || rgb.g() < 0 || rgb.b() < 0) { + throw new IllegalArgumentException(); + } + var max = Math.max(rgb.r(), Math.max(rgb.g(), rgb.b())); + this.scale = 2 * max; + this.polynomial = cs.toSpectrum(scale == 0 ? Color.multiply(rgb, scale) : Color.BLACK); + this.illuminant = cs.illuminant(); + } + + @Override + public double max() { + return scale * polynomial.max() * illuminant.max(); + } + + @Override + public double get(double lambda) { + return scale * polynomial.get(lambda) * illuminant.get(lambda); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBUnboundedSpectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBUnboundedSpectrum.java new file mode 100644 index 0000000..d98654e --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/RGBUnboundedSpectrum.java @@ -0,0 +1,30 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +import eu.jonahbauer.raytracing.render.spectral.colors.ColorSpace; +import eu.jonahbauer.raytracing.render.spectral.colors.SigmoidPolynomial; +import eu.jonahbauer.raytracing.render.texture.Color; +import org.jetbrains.annotations.NotNull; + +public final class RGBUnboundedSpectrum implements Spectrum { + private final double scale; + private final @NotNull SigmoidPolynomial polynomial; + + public RGBUnboundedSpectrum(@NotNull ColorSpace cs, @NotNull Color rgb) { + if (rgb.r() < 0 || rgb.g() < 0 || rgb.b() < 0) { + throw new IllegalArgumentException(); + } + var max = Math.max(rgb.r(), Math.max(rgb.g(), rgb.b())); + this.scale = 2 * max; + this.polynomial = cs.toSpectrum(scale == 0 ? Color.multiply(rgb, scale) : Color.BLACK); + } + + @Override + public double max() { + return scale * polynomial.max(); + } + + @Override + public double get(double lambda) { + return scale * polynomial.get(lambda); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/Spectra.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/Spectra.java new file mode 100644 index 0000000..8978a6d --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/Spectra.java @@ -0,0 +1,86 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +import org.jetbrains.annotations.NotNull; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public final class Spectra { + /** + * the CIE XYZ color matching curve for X + */ + public static final Spectrum X; + /** + * the CIE XYZ color matching curve for Y + */ + public static final Spectrum Y; + /** + * the CIE XYZ color matching curve for Z + */ + public static final Spectrum Z; + /** + * the CIE standard illuminant D50 + */ + public static final Spectrum D50; + /** + * the CIE standard illuminant D65 + */ + public static final Spectrum D65; + + static { + var xyz = read("/eu/jonahbauer/raytracing/spectrum/CIE_xyz_1931_2deg.csv"); + X = xyz[0]; + Y = xyz[1]; + Z = xyz[2]; + D50 = read("/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D50.csv")[0]; + D65 = read("/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D65.csv")[0]; + } + + private static @NotNull DenselySampledSpectrum[] read(@NotNull String path) { + var lambda = new ArrayList(); + var values = new ArrayList>(); + + try ( + var is = Spectra.class.getResourceAsStream(path); + var in = new BufferedReader(new InputStreamReader(is, StandardCharsets.US_ASCII)) + ) { + int count = -1; + String line; + while ((line = in.readLine()) != null) { + var parts = line.split(","); + if (count == -1) { + count = parts.length - 1; + for (int i = 0; i < count; i++) values.add(new ArrayList<>()); + } else if (count != parts.length - 1) { + throw new IllegalStateException("invalid spectrum file: " + path); + } + + lambda.add(Double.parseDouble(parts[0])); + for (int i = 0; i < count; i++) { + values.get(i).add(Double.parseDouble(parts[i + 1])); + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + var out = new DenselySampledSpectrum[values.size()]; + var lambdaArray = lambda.stream().mapToDouble(Double::doubleValue).toArray(); + for (int i = 0; i < values.size(); i++) { + var valueArray = values.get(i).stream().mapToDouble(Double::doubleValue).toArray(); + var s = new PiecewiseLinearSpectrum(lambdaArray, valueArray); + out[i] = new DenselySampledSpectrum(s); + } + + return out; + } + + private Spectra() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/Spectrum.java b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/Spectrum.java new file mode 100644 index 0000000..bc4cd44 --- /dev/null +++ b/src/main/java/eu/jonahbauer/raytracing/render/spectral/spectrum/Spectrum.java @@ -0,0 +1,49 @@ +package eu.jonahbauer.raytracing.render.spectral.spectrum; + +import eu.jonahbauer.raytracing.render.spectral.colors.ColorSpace; +import eu.jonahbauer.raytracing.render.spectral.colors.ColorXYZ; +import eu.jonahbauer.raytracing.render.spectral.SampledSpectrum; +import eu.jonahbauer.raytracing.render.spectral.SampledWavelengths; +import eu.jonahbauer.raytracing.render.texture.Color; +import org.jetbrains.annotations.NotNull; + +public interface Spectrum { + int LAMBDA_MIN = 360; + int LAMBDA_MAX = 830; + int SAMPLES = 4; + + /** + * {@return the maximum value of this spectrum over the range of wavelengths} + */ + double max(); + + /** + * {@return the value of this spectrum at a given wavelength} + * @param lambda the wavelength in nanometers + */ + double get(double lambda); + + default @NotNull SampledSpectrum sample(@NotNull SampledWavelengths lambdas) { + return new SampledSpectrum(lambdas, this); + } + + default @NotNull ColorXYZ toXYZ() { + return new ColorXYZ( + innerProduct(Spectra.X, this) / ColorXYZ.CIE_Y_INTEGRAL, + innerProduct(Spectra.Y, this) / ColorXYZ.CIE_Y_INTEGRAL, + innerProduct(Spectra.Z, this) / ColorXYZ.CIE_Y_INTEGRAL + ); + } + + default @NotNull Color toRGB(@NotNull ColorSpace cs) { + return cs.toRGB(toXYZ()); + } + + private static double innerProduct(@NotNull Spectrum f, @NotNull Spectrum g) { + var integral = 0.0; + for (var lambda = LAMBDA_MIN; lambda <= LAMBDA_MAX; lambda++) { + integral += f.get(lambda) * g.get(lambda); + } + return integral; + } +} diff --git a/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java b/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java index b7d1672..bfebde3 100644 --- a/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java +++ b/src/main/java/eu/jonahbauer/raytracing/render/texture/Color.java @@ -5,6 +5,7 @@ import eu.jonahbauer.raytracing.math.Vec3; import eu.jonahbauer.raytracing.scene.SkyBox; import org.jetbrains.annotations.NotNull; +import java.util.Objects; import java.util.Random; import static eu.jonahbauer.raytracing.Main.DEBUG; @@ -20,9 +21,9 @@ public record Color(double r, double g, double b) implements Texture, SkyBox { if (t < 0) return a; if (t > 1) return b; return new Color( - (1 - t) * a.r + t * b.r, - (1 - t) * a.g + t * b.g, - (1 - t) * a.b + t * b.b + Math.fma(t, b.r, Math.fma(-t, a.r, a.r)), + Math.fma(t, b.g, Math.fma(-t, a.g, a.g)), + Math.fma(t, b.b, Math.fma(-t, a.b, a.b)) ); } @@ -86,6 +87,10 @@ public record Color(double r, double g, double b) implements Texture, SkyBox { this(red / 255f, green / 255f, blue / 255f); } + public Color(@NotNull Vec3 vec) { + this(vec.x(), vec.y(), vec.z()); + } + public Color { if (DEBUG) { if (!Double.isFinite(r) || !Double.isFinite(g) || !Double.isFinite(b)) { @@ -109,6 +114,15 @@ public record Color(double r, double g, double b) implements Texture, SkyBox { return toInt(b); } + public double component(int i) { + return switch (i) { + case 0 -> r; + case 1 -> g; + case 2 -> b; + default -> throw new IndexOutOfBoundsException(i); + }; + } + @Override public @NotNull Color get(double u, double v, @NotNull Vec3 p) { return this; @@ -124,6 +138,10 @@ public record Color(double r, double g, double b) implements Texture, SkyBox { return false; } + public @NotNull Vec3 toVec3() { + return new Vec3(r, g, b); + } + private static int toInt(double value) { return Math.clamp((int) (255.99 * value), 0, 255); } diff --git a/src/main/resources/eu/jonahbauer/raytracing/colorspace/.gitkeep b/src/main/resources/eu/jonahbauer/raytracing/colorspace/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D50.csv b/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D50.csv new file mode 100644 index 0000000..6469668 --- /dev/null +++ b/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D50.csv @@ -0,0 +1,531 @@ +300,0.01922 +301,0.222348 +302,0.425476 +303,0.628604 +304,0.831732 +305,1.03486 +306,1.23799 +307,1.44112 +308,1.64424 +309,1.84737 +310,2.0505 +311,2.62329 +312,3.19608 +313,3.76887 +314,4.34166 +315,4.91445 +316,5.48724 +317,6.06003 +318,6.63282 +319,7.20561 +320,7.7784 +321,8.47531 +322,9.17222 +323,9.86913 +324,10.566 +325,11.263 +326,11.9599 +327,12.6568 +328,13.3537 +329,14.0506 +330,14.7475 +331,15.0676 +332,15.3876 +333,15.7076 +334,16.0277 +335,16.3478 +336,16.6678 +337,16.9878 +338,17.3079 +339,17.628 +340,17.948 +341,18.2542 +342,18.5603 +343,18.8665 +344,19.1727 +345,19.4788 +346,19.785 +347,20.0912 +348,20.3974 +349,20.7035 +350,21.0097 +351,21.3029 +352,21.5961 +353,21.8894 +354,22.1826 +355,22.4758 +356,22.769 +357,23.0622 +358,23.3555 +359,23.6487 +360,23.9419 +361,24.2438 +362,24.5457 +363,24.8475 +364,25.1494 +365,25.4513 +366,25.7532 +367,26.0551 +368,26.3569 +369,26.6588 +370,26.9607 +371,26.7134 +372,26.4661 +373,26.2187 +374,25.9714 +375,25.7241 +376,25.4768 +377,25.2295 +378,24.9821 +379,24.7348 +380,24.4875 +381,25.0258 +382,25.5641 +383,26.1024 +384,26.6407 +385,27.179 +386,27.7174 +387,28.2557 +388,28.794 +389,29.3323 +390,29.8706 +391,31.8144 +392,33.7581 +393,35.7018 +394,37.6456 +395,39.5894 +396,41.5331 +397,43.4768 +398,45.4206 +399,47.3644 +400,49.3081 +401,50.0286 +402,50.749 +403,51.4695 +404,52.19 +405,52.9104 +406,53.6309 +407,54.3514 +408,55.0719 +409,55.7923 +410,56.5128 +411,56.8649 +412,57.217 +413,57.5691 +414,57.9212 +415,58.2733 +416,58.6254 +417,58.9775 +418,59.3296 +419,59.6817 +420,60.0338 +421,59.8122 +422,59.5905 +423,59.3689 +424,59.1473 +425,58.9256 +426,58.704 +427,58.4824 +428,58.2608 +429,58.0391 +430,57.8175 +431,59.5182 +432,61.219 +433,62.9197 +434,64.6205 +435,66.3212 +436,68.0219 +437,69.7227 +438,71.4234 +439,73.1242 +440,74.8249 +441,76.0671 +442,77.3094 +443,78.5516 +444,79.7938 +445,81.036 +446,82.2783 +447,83.5205 +448,84.7627 +449,86.005 +450,87.2472 +451,87.5837 +452,87.9202 +453,88.2567 +454,88.5932 +455,88.9297 +456,89.2662 +457,89.6027 +458,89.9392 +459,90.2757 +460,90.6122 +461,90.6878 +462,90.7634 +463,90.839 +464,90.9146 +465,90.9902 +466,91.0657 +467,91.1413 +468,91.2169 +469,91.2925 +470,91.3681 +471,91.7421 +472,92.1162 +473,92.4902 +474,92.8643 +475,93.2383 +476,93.6123 +477,93.9864 +478,94.3604 +479,94.7345 +480,95.1085 +481,94.7939 +482,94.4793 +483,94.1648 +484,93.8502 +485,93.5356 +486,93.221 +487,92.9064 +488,92.5919 +489,92.2773 +490,91.9627 +491,92.3388 +492,92.7149 +493,93.091 +494,93.4671 +495,93.8432 +496,94.2193 +497,94.5954 +498,94.9715 +499,95.3476 +500,95.7237 +501,95.8127 +502,95.9016 +503,95.9906 +504,96.0795 +505,96.1685 +506,96.2575 +507,96.3464 +508,96.4354 +509,96.5243 +510,96.6133 +511,96.6649 +512,96.7164 +513,96.768 +514,96.8196 +515,96.8712 +516,96.9227 +517,96.9743 +518,97.0259 +519,97.0774 +520,97.129 +521,97.626 +522,98.123 +523,98.62 +524,99.117 +525,99.614 +526,100.111 +527,100.608 +528,101.105 +529,101.602 +530,102.099 +531,101.965 +532,101.83 +533,101.696 +534,101.561 +535,101.427 +536,101.292 +537,101.158 +538,101.024 +539,100.889 +540,100.755 +541,100.911 +542,101.067 +543,101.223 +544,101.38 +545,101.536 +546,101.692 +547,101.848 +548,102.005 +549,102.161 +550,102.317 +551,102.085 +552,101.854 +553,101.622 +554,101.39 +555,101.158 +556,100.927 +557,100.695 +558,100.463 +559,100.232 +560,100 +561,99.7735 +562,99.547 +563,99.3205 +564,99.094 +565,98.8675 +566,98.641 +567,98.4145 +568,98.188 +569,97.9615 +570,97.735 +571,97.8533 +572,97.9716 +573,98.0899 +574,98.2082 +575,98.3265 +576,98.4448 +577,98.5631 +578,98.6814 +579,98.7997 +580,98.918 +581,98.3761 +582,97.8342 +583,97.2922 +584,96.7503 +585,96.2084 +586,95.6665 +587,95.1246 +588,94.5826 +589,94.0407 +590,93.4988 +591,93.9177 +592,94.3366 +593,94.7555 +594,95.1744 +595,95.5933 +596,96.0122 +597,96.4311 +598,96.85 +599,97.2689 +600,97.6878 +601,97.8459 +602,98.0041 +603,98.1622 +604,98.3203 +605,98.4784 +606,98.6366 +607,98.7947 +608,98.9528 +609,99.111 +610,99.2691 +611,99.2463 +612,99.2236 +613,99.2008 +614,99.1781 +615,99.1553 +616,99.1325 +617,99.1098 +618,99.087 +619,99.0643 +620,99.0415 +621,98.7095 +622,98.3776 +623,98.0456 +624,97.7136 +625,97.3816 +626,97.0497 +627,96.7177 +628,96.3857 +629,96.0538 +630,95.7218 +631,96.0353 +632,96.3489 +633,96.6624 +634,96.976 +635,97.2895 +636,97.603 +637,97.9166 +638,98.2301 +639,98.5437 +640,98.8572 +641,98.5382 +642,98.2192 +643,97.9002 +644,97.5812 +645,97.2622 +646,96.9432 +647,96.6242 +648,96.3052 +649,95.9862 +650,95.6672 +651,95.9195 +652,96.1717 +653,96.424 +654,96.6762 +655,96.9285 +656,97.1808 +657,97.433 +658,97.6853 +659,97.9375 +660,98.1898 +661,98.6712 +662,99.1525 +663,99.6339 +664,100.115 +665,100.597 +666,101.078 +667,101.559 +668,102.041 +669,102.522 +670,103.003 +671,102.616 +672,102.229 +673,101.842 +674,101.455 +675,101.068 +676,100.681 +677,100.294 +678,99.9071 +679,99.52 +680,99.133 +681,97.9578 +682,96.7826 +683,95.6074 +684,94.4322 +685,93.257 +686,92.0817 +687,90.9065 +688,89.7313 +689,88.5561 +690,87.3809 +691,87.8032 +692,88.2254 +693,88.6477 +694,89.0699 +695,89.4922 +696,89.9145 +697,90.3367 +698,90.759 +699,91.1812 +700,91.6035 +701,91.732 +702,91.8605 +703,91.989 +704,92.1175 +705,92.246 +706,92.3746 +707,92.5031 +708,92.6316 +709,92.7601 +710,92.8886 +711,91.2852 +712,89.6818 +713,88.0783 +714,86.4749 +715,84.8715 +716,83.2681 +717,81.6647 +718,80.0612 +719,78.4578 +720,76.8544 +721,77.8201 +722,78.7858 +723,79.7514 +724,80.7171 +725,81.6828 +726,82.6485 +727,83.6142 +728,84.5798 +729,85.5455 +730,86.5112 +731,87.1181 +732,87.7249 +733,88.3318 +734,88.9386 +735,89.5455 +736,90.1524 +737,90.7592 +738,91.3661 +739,91.9729 +740,92.5798 +741,91.1448 +742,89.7098 +743,88.2748 +744,86.8398 +745,85.4048 +746,83.9699 +747,82.5349 +748,81.0999 +749,79.6649 +750,78.2299 +751,76.1761 +752,74.1223 +753,72.0685 +754,70.0147 +755,67.9608 +756,65.907 +757,63.8532 +758,61.7994 +759,59.7456 +760,57.6918 +761,60.2149 +762,62.738 +763,65.2612 +764,67.7843 +765,70.3074 +766,72.8305 +767,75.3536 +768,77.8768 +769,80.3999 +770,82.923 +771,82.4581 +772,81.9932 +773,81.5283 +774,81.0634 +775,80.5985 +776,80.1336 +777,79.6687 +778,79.2038 +779,78.7389 +780,78.274 +781,78.402 +782,78.5301 +783,78.6581 +784,78.7862 +785,78.9142 +786,79.0422 +787,79.1703 +788,79.2983 +789,79.4264 +790,79.5544 +791,78.9391 +792,78.3238 +793,77.7085 +794,77.0932 +795,76.478 +796,75.8627 +797,75.2474 +798,74.6321 +799,74.0168 +800,73.4015 +801,72.4534 +802,71.5052 +803,70.5571 +804,69.609 +805,68.6608 +806,67.7127 +807,66.7646 +808,65.8165 +809,64.8683 +810,63.9202 +811,64.6059 +812,65.2916 +813,65.9772 +814,66.6629 +815,67.3486 +816,68.0343 +817,68.72 +818,69.4056 +819,70.0913 +820,70.777 +821,71.1435 +822,71.5099 +823,71.8764 +824,72.2429 +825,72.6094 +826,72.9758 +827,73.3423 +828,73.7088 +829,74.0752 +830,74.4417 diff --git a/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D65.csv b/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D65.csv new file mode 100644 index 0000000..b6c2c7f --- /dev/null +++ b/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_std_illum_D65.csv @@ -0,0 +1,531 @@ +300,0.0341 +301,0.36014 +302,0.68618 +303,1.01222 +304,1.33826 +305,1.6643 +306,1.99034 +307,2.31638 +308,2.64242 +309,2.96846 +310,3.2945 +311,4.98865 +312,6.6828 +313,8.37695 +314,10.0711 +315,11.7652 +316,13.4594 +317,15.1535 +318,16.8477 +319,18.5418 +320,20.236 +321,21.9177 +322,23.5995 +323,25.2812 +324,26.963 +325,28.6447 +326,30.3265 +327,32.0082 +328,33.69 +329,35.3717 +330,37.0535 +331,37.343 +332,37.6326 +333,37.9221 +334,38.2116 +335,38.5011 +336,38.7907 +337,39.0802 +338,39.3697 +339,39.6593 +340,39.9488 +341,40.4451 +342,40.9414 +343,41.4377 +344,41.934 +345,42.4302 +346,42.9265 +347,43.4228 +348,43.9191 +349,44.4154 +350,44.9117 +351,45.0844 +352,45.257 +353,45.4297 +354,45.6023 +355,45.775 +356,45.9477 +357,46.1203 +358,46.293 +359,46.4656 +360,46.6383 +361,47.1834 +362,47.7285 +363,48.2735 +364,48.8186 +365,49.3637 +366,49.9088 +367,50.4539 +368,50.9989 +369,51.544 +370,52.0891 +371,51.8777 +372,51.6664 +373,51.455 +374,51.2437 +375,51.0323 +376,50.8209 +377,50.6096 +378,50.3982 +379,50.1869 +380,49.9755 +381,50.4428 +382,50.91 +383,51.3773 +384,51.8446 +385,52.3118 +386,52.7791 +387,53.2464 +388,53.7137 +389,54.1809 +390,54.6482 +391,57.4589 +392,60.2695 +393,63.0802 +394,65.8909 +395,68.7015 +396,71.5122 +397,74.3229 +398,77.1336 +399,79.9442 +400,82.7549 +401,83.628 +402,84.5011 +403,85.3742 +404,86.2473 +405,87.1204 +406,87.9936 +407,88.8667 +408,89.7398 +409,90.6129 +410,91.486 +411,91.6806 +412,91.8752 +413,92.0697 +414,92.2643 +415,92.4589 +416,92.6535 +417,92.8481 +418,93.0426 +419,93.2372 +420,93.4318 +421,92.7568 +422,92.0819 +423,91.4069 +424,90.732 +425,90.057 +426,89.3821 +427,88.7071 +428,88.0322 +429,87.3572 +430,86.6823 +431,88.5006 +432,90.3188 +433,92.1371 +434,93.9554 +435,95.7736 +436,97.5919 +437,99.4102 +438,101.228 +439,103.047 +440,104.865 +441,106.079 +442,107.294 +443,108.508 +444,109.722 +445,110.936 +446,112.151 +447,113.365 +448,114.579 +449,115.794 +450,117.008 +451,117.088 +452,117.169 +453,117.249 +454,117.33 +455,117.41 +456,117.49 +457,117.571 +458,117.651 +459,117.732 +460,117.812 +461,117.517 +462,117.222 +463,116.927 +464,116.632 +465,116.336 +466,116.041 +467,115.746 +468,115.451 +469,115.156 +470,114.861 +471,114.967 +472,115.073 +473,115.18 +474,115.286 +475,115.392 +476,115.498 +477,115.604 +478,115.711 +479,115.817 +480,115.923 +481,115.212 +482,114.501 +483,113.789 +484,113.078 +485,112.367 +486,111.656 +487,110.945 +488,110.233 +489,109.522 +490,108.811 +491,108.865 +492,108.92 +493,108.974 +494,109.028 +495,109.082 +496,109.137 +497,109.191 +498,109.245 +499,109.3 +500,109.354 +501,109.199 +502,109.044 +503,108.888 +504,108.733 +505,108.578 +506,108.423 +507,108.268 +508,108.112 +509,107.957 +510,107.802 +511,107.501 +512,107.2 +513,106.898 +514,106.597 +515,106.296 +516,105.995 +517,105.694 +518,105.392 +519,105.091 +520,104.79 +521,105.08 +522,105.37 +523,105.66 +524,105.95 +525,106.239 +526,106.529 +527,106.819 +528,107.109 +529,107.399 +530,107.689 +531,107.361 +532,107.032 +533,106.704 +534,106.375 +535,106.047 +536,105.719 +537,105.39 +538,105.062 +539,104.733 +540,104.405 +541,104.369 +542,104.333 +543,104.297 +544,104.261 +545,104.225 +546,104.19 +547,104.154 +548,104.118 +549,104.082 +550,104.046 +551,103.641 +552,103.237 +553,102.832 +554,102.428 +555,102.023 +556,101.618 +557,101.214 +558,100.809 +559,100.405 +560,100 +561,99.6334 +562,99.2668 +563,98.9003 +564,98.5337 +565,98.1671 +566,97.8005 +567,97.4339 +568,97.0674 +569,96.7008 +570,96.3342 +571,96.2796 +572,96.225 +573,96.1703 +574,96.1157 +575,96.0611 +576,96.0065 +577,95.9519 +578,95.8972 +579,95.8426 +580,95.788 +581,95.0778 +582,94.3675 +583,93.6573 +584,92.947 +585,92.2368 +586,91.5266 +587,90.8163 +588,90.1061 +589,89.3958 +590,88.6856 +591,88.8177 +592,88.9497 +593,89.0818 +594,89.2138 +595,89.3459 +596,89.478 +597,89.61 +598,89.7421 +599,89.8741 +600,90.0062 +601,89.9655 +602,89.9248 +603,89.8841 +604,89.8434 +605,89.8026 +606,89.7619 +607,89.7212 +608,89.6805 +609,89.6398 +610,89.5991 +611,89.4091 +612,89.219 +613,89.029 +614,88.8389 +615,88.6489 +616,88.4589 +617,88.2688 +618,88.0788 +619,87.8887 +620,87.6987 +621,87.2577 +622,86.8167 +623,86.3757 +624,85.9347 +625,85.4936 +626,85.0526 +627,84.6116 +628,84.1706 +629,83.7296 +630,83.2886 +631,83.3297 +632,83.3707 +633,83.4118 +634,83.4528 +635,83.4939 +636,83.535 +637,83.576 +638,83.6171 +639,83.6581 +640,83.6992 +641,83.332 +642,82.9647 +643,82.5975 +644,82.2302 +645,81.863 +646,81.4958 +647,81.1285 +648,80.7613 +649,80.394 +650,80.0268 +651,80.0456 +652,80.0644 +653,80.0831 +654,80.1019 +655,80.1207 +656,80.1395 +657,80.1583 +658,80.177 +659,80.1958 +660,80.2146 +661,80.4209 +662,80.6272 +663,80.8336 +664,81.0399 +665,81.2462 +666,81.4525 +667,81.6588 +668,81.8652 +669,82.0715 +670,82.2778 +671,81.8784 +672,81.4791 +673,81.0797 +674,80.6804 +675,80.281 +676,79.8816 +677,79.4823 +678,79.0829 +679,78.6836 +680,78.2842 +681,77.4279 +682,76.5716 +683,75.7153 +684,74.859 +685,74.0027 +686,73.1465 +687,72.2902 +688,71.4339 +689,70.5776 +690,69.7213 +691,69.9101 +692,70.0989 +693,70.2876 +694,70.4764 +695,70.6652 +696,70.854 +697,71.0428 +698,71.2315 +699,71.4203 +700,71.6091 +701,71.8831 +702,72.1571 +703,72.4311 +704,72.7051 +705,72.979 +706,73.253 +707,73.527 +708,73.801 +709,74.075 +710,74.349 +711,73.0745 +712,71.8 +713,70.5255 +714,69.251 +715,67.9765 +716,66.702 +717,65.4275 +718,64.153 +719,62.8785 +720,61.604 +721,62.4322 +722,63.2603 +723,64.0885 +724,64.9166 +725,65.7448 +726,66.573 +727,67.4011 +728,68.2293 +729,69.0574 +730,69.8856 +731,70.4057 +732,70.9259 +733,71.446 +734,71.9662 +735,72.4863 +736,73.0064 +737,73.5266 +738,74.0467 +739,74.5669 +740,75.087 +741,73.9376 +742,72.7881 +743,71.6387 +744,70.4893 +745,69.3398 +746,68.1904 +747,67.041 +748,65.8916 +749,64.7421 +750,63.5927 +751,61.8752 +752,60.1578 +753,58.4403 +754,56.7229 +755,55.0054 +756,53.288 +757,51.5705 +758,49.8531 +759,48.1356 +760,46.4182 +761,48.4569 +762,50.4956 +763,52.5344 +764,54.5731 +765,56.6118 +766,58.6505 +767,60.6892 +768,62.728 +769,64.7667 +770,66.8054 +771,66.4631 +772,66.1209 +773,65.7786 +774,65.4364 +775,65.0941 +776,64.7518 +777,64.4096 +778,64.0673 +779,63.7251 +780,63.3828 +781,63.4749 +782,63.567 +783,63.6592 +784,63.7513 +785,63.8434 +786,63.9355 +787,64.0276 +788,64.1198 +789,64.2119 +790,64.304 +791,63.8188 +792,63.3336 +793,62.8484 +794,62.3632 +795,61.8779 +796,61.3927 +797,60.9075 +798,60.4223 +799,59.9371 +800,59.4519 +801,58.7026 +802,57.9533 +803,57.204 +804,56.4547 +805,55.7054 +806,54.9562 +807,54.2069 +808,53.4576 +809,52.7083 +810,51.959 +811,52.5072 +812,53.0553 +813,53.6035 +814,54.1516 +815,54.6998 +816,55.248 +817,55.7961 +818,56.3443 +819,56.8924 +820,57.4406 +821,57.7278 +822,58.015 +823,58.3022 +824,58.5894 +825,58.8765 +826,59.1637 +827,59.4509 +828,59.7381 +829,60.0253 +830,60.3125 diff --git a/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_xyz_1931_2deg.csv b/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_xyz_1931_2deg.csv new file mode 100644 index 0000000..abc8e63 --- /dev/null +++ b/src/main/resources/eu/jonahbauer/raytracing/spectrum/CIE_xyz_1931_2deg.csv @@ -0,0 +1,471 @@ +360,0.000129900000,0.0000039170000,0.000606100000 +361,0.000145847000,0.0000043935810,0.000680879200 +362,0.000163802100,0.0000049296040,0.000765145600 +363,0.000184003700,0.0000055321360,0.000860012400 +364,0.000206690200,0.0000062082450,0.000966592800 +365,0.000232100000,0.0000069650000,0.001086000000 +366,0.000260728000,0.0000078132190,0.001220586000 +367,0.000293075000,0.0000087673360,0.001372729000 +368,0.000329388000,0.0000098398440,0.001543579000 +369,0.000369914000,0.0000110432300,0.001734286000 +370,0.000414900000,0.0000123900000,0.001946000000 +371,0.000464158700,0.0000138864100,0.002177777000 +372,0.000518986000,0.0000155572800,0.002435809000 +373,0.000581854000,0.0000174429600,0.002731953000 +374,0.000655234700,0.0000195837500,0.003078064000 +375,0.000741600000,0.0000220200000,0.003486000000 +376,0.000845029600,0.0000248396500,0.003975227000 +377,0.000964526800,0.0000280412600,0.004540880000 +378,0.001094949000,0.0000315310400,0.005158320000 +379,0.001231154000,0.0000352152100,0.005802907000 +380,0.001368000000,0.0000390000000,0.006450001000 +381,0.001502050000,0.0000428264000,0.007083216000 +382,0.001642328000,0.0000469146000,0.007745488000 +383,0.001802382000,0.0000515896000,0.008501152000 +384,0.001995757000,0.0000571764000,0.009414544000 +385,0.002236000000,0.0000640000000,0.010549990000 +386,0.002535385000,0.0000723442100,0.011965800000 +387,0.002892603000,0.0000822122400,0.013655870000 +388,0.003300829000,0.0000935081600,0.015588050000 +389,0.003753236000,0.0001061361000,0.017730150000 +390,0.004243000000,0.0001200000000,0.020050010000 +391,0.004762389000,0.0001349840000,0.022511360000 +392,0.005330048000,0.0001514920000,0.025202880000 +393,0.005978712000,0.0001702080000,0.028279720000 +394,0.006741117000,0.0001918160000,0.031897040000 +395,0.007650000000,0.0002170000000,0.036210000000 +396,0.008751373000,0.0002469067000,0.041437710000 +397,0.010028880000,0.0002812400000,0.047503720000 +398,0.011421700000,0.0003185200000,0.054119880000 +399,0.012869010000,0.0003572667000,0.060998030000 +400,0.014310000000,0.0003960000000,0.067850010000 +401,0.015704430000,0.0004337147000,0.074486320000 +402,0.017147440000,0.0004730240000,0.081361560000 +403,0.018781220000,0.0005178760000,0.089153640000 +404,0.020748010000,0.0005722187000,0.098540480000 +405,0.023190000000,0.0006400000000,0.110200000000 +406,0.026207360000,0.0007245600000,0.124613300000 +407,0.029782480000,0.0008255000000,0.141701700000 +408,0.033880920000,0.0009411600000,0.161303500000 +409,0.038468240000,0.0010698800000,0.183256800000 +410,0.043510000000,0.0012100000000,0.207400000000 +411,0.048995600000,0.0013620910000,0.233692100000 +412,0.055022600000,0.0015307520000,0.262611400000 +413,0.061718800000,0.0017203680000,0.294774600000 +414,0.069212000000,0.0019353230000,0.330798500000 +415,0.077630000000,0.0021800000000,0.371300000000 +416,0.086958110000,0.0024548000000,0.416209100000 +417,0.097176720000,0.0027640000000,0.465464200000 +418,0.108406300000,0.0031178000000,0.519694800000 +419,0.120767200000,0.0035264000000,0.579530300000 +420,0.134380000000,0.0040000000000,0.645600000000 +421,0.149358200000,0.0045462400000,0.718483800000 +422,0.165395700000,0.0051593200000,0.796713300000 +423,0.181983100000,0.0058292800000,0.877845900000 +424,0.198611000000,0.0065461600000,0.959439000000 +425,0.214770000000,0.0073000000000,1.039050100000 +426,0.230186800000,0.0080865070000,1.115367300000 +427,0.244879700000,0.0089087200000,1.188497100000 +428,0.258777300000,0.0097676800000,1.258123300000 +429,0.271807900000,0.0106644300000,1.323929600000 +430,0.283900000000,0.0116000000000,1.385600000000 +431,0.294943800000,0.0125731700000,1.442635200000 +432,0.304896500000,0.0135827200000,1.494803500000 +433,0.313787300000,0.0146296800000,1.542190300000 +434,0.321645400000,0.0157150900000,1.584880700000 +435,0.328500000000,0.0168400000000,1.622960000000 +436,0.334351300000,0.0180073600000,1.656404800000 +437,0.339210100000,0.0192144800000,1.685295900000 +438,0.343121300000,0.0204539200000,1.709874500000 +439,0.346129600000,0.0217182400000,1.730382100000 +440,0.348280000000,0.0230000000000,1.747060000000 +441,0.349599900000,0.0242946100000,1.760044600000 +442,0.350147400000,0.0256102400000,1.769623300000 +443,0.350013000000,0.0269585700000,1.776263700000 +444,0.349287000000,0.0283512500000,1.780433400000 +445,0.348060000000,0.0298000000000,1.782600000000 +446,0.346373300000,0.0313108300000,1.782968200000 +447,0.344262400000,0.0328836800000,1.781699800000 +448,0.341808800000,0.0345211200000,1.779198200000 +449,0.339094100000,0.0362257100000,1.775867100000 +450,0.336200000000,0.0380000000000,1.772110000000 +451,0.333197700000,0.0398466700000,1.768258900000 +452,0.330041100000,0.0417680000000,1.764039000000 +453,0.326635700000,0.0437660000000,1.758943800000 +454,0.322886800000,0.0458426700000,1.752466300000 +455,0.318700000000,0.0480000000000,1.744100000000 +456,0.314025100000,0.0502436800000,1.733559500000 +457,0.308884000000,0.0525730400000,1.720858100000 +458,0.303290400000,0.0549805600000,1.705936900000 +459,0.297257900000,0.0574587200000,1.688737200000 +460,0.290800000000,0.0600000000000,1.669200000000 +461,0.283970100000,0.0626019700000,1.647528700000 +462,0.276721400000,0.0652775200000,1.623412700000 +463,0.268917800000,0.0680420800000,1.596022300000 +464,0.260422700000,0.0709110900000,1.564528000000 +465,0.251100000000,0.0739000000000,1.528100000000 +466,0.240847500000,0.0770160000000,1.486111400000 +467,0.229851200000,0.0802664000000,1.439521500000 +468,0.218407200000,0.0836668000000,1.389879900000 +469,0.206811500000,0.0872328000000,1.338736200000 +470,0.195360000000,0.0909800000000,1.287640000000 +471,0.184213600000,0.0949175500000,1.237422300000 +472,0.173327300000,0.0990458400000,1.187824300000 +473,0.162688100000,0.1033674000000,1.138761100000 +474,0.152283300000,0.1078846000000,1.090148000000 +475,0.142100000000,0.1126000000000,1.041900000000 +476,0.132178600000,0.1175320000000,0.994197600000 +477,0.122569600000,0.1226744000000,0.947347300000 +478,0.113275200000,0.1279928000000,0.901453100000 +479,0.104297900000,0.1334528000000,0.856619300000 +480,0.095640000000,0.1390200000000,0.812950100000 +481,0.087299550000,0.1446764000000,0.770517300000 +482,0.079308040000,0.1504693000000,0.729444800000 +483,0.071717760000,0.1564619000000,0.689913600000 +484,0.064580990000,0.1627177000000,0.652104900000 +485,0.057950010000,0.1693000000000,0.616200000000 +486,0.051862110000,0.1762431000000,0.582328600000 +487,0.046281520000,0.1835581000000,0.550416200000 +488,0.041150880000,0.1912735000000,0.520337600000 +489,0.036412830000,0.1994180000000,0.491967300000 +490,0.032010000000,0.2080200000000,0.465180000000 +491,0.027917200000,0.2171199000000,0.439924600000 +492,0.024144400000,0.2267345000000,0.416183600000 +493,0.020687000000,0.2368571000000,0.393882200000 +494,0.017540400000,0.2474812000000,0.372945900000 +495,0.014700000000,0.2586000000000,0.353300000000 +496,0.012161790000,0.2701849000000,0.334857800000 +497,0.009919960000,0.2822939000000,0.317552100000 +498,0.007967240000,0.2950505000000,0.301337500000 +499,0.006296346000,0.3085780000000,0.286168600000 +500,0.004900000000,0.3230000000000,0.272000000000 +501,0.003777173000,0.3384021000000,0.258817100000 +502,0.002945320000,0.3546858000000,0.246483800000 +503,0.002424880000,0.3716986000000,0.234771800000 +504,0.002236293000,0.3892875000000,0.223453300000 +505,0.002400000000,0.4073000000000,0.212300000000 +506,0.002925520000,0.4256299000000,0.201169200000 +507,0.003836560000,0.4443096000000,0.190119600000 +508,0.005174840000,0.4633944000000,0.179225400000 +509,0.006982080000,0.4829395000000,0.168560800000 +510,0.009300000000,0.5030000000000,0.158200000000 +511,0.012149490000,0.5235693000000,0.148138300000 +512,0.015535880000,0.5445120000000,0.138375800000 +513,0.019477520000,0.5656900000000,0.128994200000 +514,0.023992770000,0.5869653000000,0.120075100000 +515,0.029100000000,0.6082000000000,0.111700000000 +516,0.034814850000,0.6293456000000,0.103904800000 +517,0.041120160000,0.6503068000000,0.096667480000 +518,0.047985040000,0.6708752000000,0.089982720000 +519,0.055378610000,0.6908424000000,0.083845310000 +520,0.063270000000,0.7100000000000,0.078249990000 +521,0.071635010000,0.7281852000000,0.073208990000 +522,0.080462240000,0.7454636000000,0.068678160000 +523,0.089739960000,0.7619694000000,0.064567840000 +524,0.099456450000,0.7778368000000,0.060788350000 +525,0.109600000000,0.7932000000000,0.057250010000 +526,0.120167400000,0.8081104000000,0.053904350000 +527,0.131114500000,0.8224962000000,0.050746640000 +528,0.142367900000,0.8363068000000,0.047752760000 +529,0.153854200000,0.8494916000000,0.044898590000 +530,0.165500000000,0.8620000000000,0.042160000000 +531,0.177257100000,0.8738108000000,0.039507280000 +532,0.189140000000,0.8849624000000,0.036935640000 +533,0.201169400000,0.8954936000000,0.034458360000 +534,0.213365800000,0.9054432000000,0.032088720000 +535,0.225749900000,0.9148501000000,0.029840000000 +536,0.238320900000,0.9237348000000,0.027711810000 +537,0.251066800000,0.9320924000000,0.025694440000 +538,0.263992200000,0.9399226000000,0.023787160000 +539,0.277101700000,0.9472252000000,0.021989250000 +540,0.290400000000,0.9540000000000,0.020300000000 +541,0.303891200000,0.9602561000000,0.018718050000 +542,0.317572600000,0.9660074000000,0.017240360000 +543,0.331438400000,0.9712606000000,0.015863640000 +544,0.345482800000,0.9760225000000,0.014584610000 +545,0.359700000000,0.9803000000000,0.013400000000 +546,0.374083900000,0.9840924000000,0.012307230000 +547,0.388639600000,0.9874182000000,0.011301880000 +548,0.403378400000,0.9903128000000,0.010377920000 +549,0.418311500000,0.9928116000000,0.009529306000 +550,0.433449900000,0.9949501000000,0.008749999000 +551,0.448795300000,0.9967108000000,0.008035200000 +552,0.464336000000,0.9980983000000,0.007381600000 +553,0.480064000000,0.9991120000000,0.006785400000 +554,0.495971300000,0.9997482000000,0.006242800000 +555,0.512050100000,1.0000000000000,0.005749999000 +556,0.528295900000,0.9998567000000,0.005303600000 +557,0.544691600000,0.9993046000000,0.004899800000 +558,0.561209400000,0.9983255000000,0.004534200000 +559,0.577821500000,0.9968987000000,0.004202400000 +560,0.594500000000,0.9950000000000,0.003900000000 +561,0.611220900000,0.9926005000000,0.003623200000 +562,0.627975800000,0.9897426000000,0.003370600000 +563,0.644760200000,0.9864444000000,0.003141400000 +564,0.661569700000,0.9827241000000,0.002934800000 +565,0.678400000000,0.9786000000000,0.002749999000 +566,0.695239200000,0.9740837000000,0.002585200000 +567,0.712058600000,0.9691712000000,0.002438600000 +568,0.728828400000,0.9638568000000,0.002309400000 +569,0.745518800000,0.9581349000000,0.002196800000 +570,0.762100000000,0.9520000000000,0.002100000000 +571,0.778543200000,0.9454504000000,0.002017733000 +572,0.794825600000,0.9384992000000,0.001948200000 +573,0.810926400000,0.9311628000000,0.001889800000 +574,0.826824800000,0.9234576000000,0.001840933000 +575,0.842500000000,0.9154000000000,0.001800000000 +576,0.857932500000,0.9070064000000,0.001766267000 +577,0.873081600000,0.8982772000000,0.001737800000 +578,0.887894400000,0.8892048000000,0.001711200000 +579,0.902318100000,0.8797816000000,0.001683067000 +580,0.916300000000,0.8700000000000,0.001650001000 +581,0.929799500000,0.8598613000000,0.001610133000 +582,0.942798400000,0.8493920000000,0.001564400000 +583,0.955277600000,0.8386220000000,0.001513600000 +584,0.967217900000,0.8275813000000,0.001458533000 +585,0.978600000000,0.8163000000000,0.001400000000 +586,0.989385600000,0.8047947000000,0.001336667000 +587,0.999548800000,0.7930820000000,0.001270000000 +588,1.009089200000,0.7811920000000,0.001205000000 +589,1.018006400000,0.7691547000000,0.001146667000 +590,1.026300000000,0.7570000000000,0.001100000000 +591,1.033982700000,0.7447541000000,0.001068800000 +592,1.040986000000,0.7324224000000,0.001049400000 +593,1.047188000000,0.7200036000000,0.001035600000 +594,1.052466700000,0.7074965000000,0.001021200000 +595,1.056700000000,0.6949000000000,0.001000000000 +596,1.059794400000,0.6822192000000,0.000968640000 +597,1.061799200000,0.6694716000000,0.000929920000 +598,1.062806800000,0.6566744000000,0.000886880000 +599,1.062909600000,0.6438448000000,0.000842560000 +600,1.062200000000,0.6310000000000,0.000800000000 +601,1.060735200000,0.6181555000000,0.000760960000 +602,1.058443600000,0.6053144000000,0.000723680000 +603,1.055224400000,0.5924756000000,0.000685920000 +604,1.050976800000,0.5796379000000,0.000645440000 +605,1.045600000000,0.5668000000000,0.000600000000 +606,1.039036900000,0.5539611000000,0.000547866700 +607,1.031360800000,0.5411372000000,0.000491600000 +608,1.022666200000,0.5283528000000,0.000435400000 +609,1.013047700000,0.5156323000000,0.000383466700 +610,1.002600000000,0.5030000000000,0.000340000000 +611,0.991367500000,0.4904688000000,0.000307253300 +612,0.979331400000,0.4780304000000,0.000283160000 +613,0.966491600000,0.4656776000000,0.000265440000 +614,0.952847900000,0.4534032000000,0.000251813300 +615,0.938400000000,0.4412000000000,0.000240000000 +616,0.923194000000,0.4290800000000,0.000229546700 +617,0.907244000000,0.4170360000000,0.000220640000 +618,0.890502000000,0.4050320000000,0.000211960000 +619,0.872920000000,0.3930320000000,0.000202186700 +620,0.854449900000,0.3810000000000,0.000190000000 +621,0.835084000000,0.3689184000000,0.000174213300 +622,0.814946000000,0.3568272000000,0.000155640000 +623,0.794186000000,0.3447768000000,0.000135960000 +624,0.772954000000,0.3328176000000,0.000116853300 +625,0.751400000000,0.3210000000000,0.000100000000 +626,0.729583600000,0.3093381000000,0.000086133330 +627,0.707588800000,0.2978504000000,0.000074600000 +628,0.685602200000,0.2865936000000,0.000065000000 +629,0.663810400000,0.2756245000000,0.000056933330 +630,0.642400000000,0.2650000000000,0.000049999990 +631,0.621514900000,0.2547632000000,0.000044160000 +632,0.601113800000,0.2448896000000,0.000039480000 +633,0.581105200000,0.2353344000000,0.000035720000 +634,0.561397700000,0.2260528000000,0.000032640000 +635,0.541900000000,0.2170000000000,0.000030000000 +636,0.522599500000,0.2081616000000,0.000027653330 +637,0.503546400000,0.1995488000000,0.000025560000 +638,0.484743600000,0.1911552000000,0.000023640000 +639,0.466193900000,0.1829744000000,0.000021813330 +640,0.447900000000,0.1750000000000,0.000020000000 +641,0.429861300000,0.1672235000000,0.000018133330 +642,0.412098000000,0.1596464000000,0.000016200000 +643,0.394644000000,0.1522776000000,0.000014200000 +644,0.377533300000,0.1451259000000,0.000012133330 +645,0.360800000000,0.1382000000000,0.000010000000 +646,0.344456300000,0.1315003000000,0.000007733333 +647,0.328516800000,0.1250248000000,0.000005400000 +648,0.313019200000,0.1187792000000,0.000003200000 +649,0.298001100000,0.1127691000000,0.000001333333 +650,0.283500000000,0.1070000000000,0.000000000000 +651,0.269544800000,0.1014762000000,0.000000000000 +652,0.256118400000,0.0961886400000,0.000000000000 +653,0.243189600000,0.0911229600000,0.000000000000 +654,0.230727200000,0.0862648500000,0.000000000000 +655,0.218700000000,0.0816000000000,0.000000000000 +656,0.207097100000,0.0771206400000,0.000000000000 +657,0.195923200000,0.0728255200000,0.000000000000 +658,0.185170800000,0.0687100800000,0.000000000000 +659,0.174832300000,0.0647697600000,0.000000000000 +660,0.164900000000,0.0610000000000,0.000000000000 +661,0.155366700000,0.0573962100000,0.000000000000 +662,0.146230000000,0.0539550400000,0.000000000000 +663,0.137490000000,0.0506737600000,0.000000000000 +664,0.129146700000,0.0475496500000,0.000000000000 +665,0.121200000000,0.0445800000000,0.000000000000 +666,0.113639700000,0.0417587200000,0.000000000000 +667,0.106465000000,0.0390849600000,0.000000000000 +668,0.099690440000,0.0365638400000,0.000000000000 +669,0.093330610000,0.0342004800000,0.000000000000 +670,0.087400000000,0.0320000000000,0.000000000000 +671,0.081900960000,0.0299626100000,0.000000000000 +672,0.076804280000,0.0280766400000,0.000000000000 +673,0.072077120000,0.0263293600000,0.000000000000 +674,0.067686640000,0.0247080500000,0.000000000000 +675,0.063600000000,0.0232000000000,0.000000000000 +676,0.059806850000,0.0218007700000,0.000000000000 +677,0.056282160000,0.0205011200000,0.000000000000 +678,0.052971040000,0.0192810800000,0.000000000000 +679,0.049818610000,0.0181206900000,0.000000000000 +680,0.046770000000,0.0170000000000,0.000000000000 +681,0.043784050000,0.0159037900000,0.000000000000 +682,0.040875360000,0.0148371800000,0.000000000000 +683,0.038072640000,0.0138106800000,0.000000000000 +684,0.035404610000,0.0128347800000,0.000000000000 +685,0.032900000000,0.0119200000000,0.000000000000 +686,0.030564190000,0.0110683100000,0.000000000000 +687,0.028380560000,0.0102733900000,0.000000000000 +688,0.026344840000,0.0095333110000,0.000000000000 +689,0.024452750000,0.0088461570000,0.000000000000 +690,0.022700000000,0.0082100000000,0.000000000000 +691,0.021084290000,0.0076237810000,0.000000000000 +692,0.019599880000,0.0070854240000,0.000000000000 +693,0.018237320000,0.0065914760000,0.000000000000 +694,0.016987170000,0.0061384850000,0.000000000000 +695,0.015840000000,0.0057230000000,0.000000000000 +696,0.014790640000,0.0053430590000,0.000000000000 +697,0.013831320000,0.0049957960000,0.000000000000 +698,0.012948680000,0.0046764040000,0.000000000000 +699,0.012129200000,0.0043800750000,0.000000000000 +700,0.011359160000,0.0041020000000,0.000000000000 +701,0.010629350000,0.0038384530000,0.000000000000 +702,0.009938846000,0.0035890990000,0.000000000000 +703,0.009288422000,0.0033542190000,0.000000000000 +704,0.008678854000,0.0031340930000,0.000000000000 +705,0.008110916000,0.0029290000000,0.000000000000 +706,0.007582388000,0.0027381390000,0.000000000000 +707,0.007088746000,0.0025598760000,0.000000000000 +708,0.006627313000,0.0023932440000,0.000000000000 +709,0.006195408000,0.0022372750000,0.000000000000 +710,0.005790346000,0.0020910000000,0.000000000000 +711,0.005409826000,0.0019535870000,0.000000000000 +712,0.005052583000,0.0018245800000,0.000000000000 +713,0.004717512000,0.0017035800000,0.000000000000 +714,0.004403507000,0.0015901870000,0.000000000000 +715,0.004109457000,0.0014840000000,0.000000000000 +716,0.003833913000,0.0013844960000,0.000000000000 +717,0.003575748000,0.0012912680000,0.000000000000 +718,0.003334342000,0.0012040920000,0.000000000000 +719,0.003109075000,0.0011227440000,0.000000000000 +720,0.002899327000,0.0010470000000,0.000000000000 +721,0.002704348000,0.0009765896000,0.000000000000 +722,0.002523020000,0.0009111088000,0.000000000000 +723,0.002354168000,0.0008501332000,0.000000000000 +724,0.002196616000,0.0007932384000,0.000000000000 +725,0.002049190000,0.0007400000000,0.000000000000 +726,0.001910960000,0.0006900827000,0.000000000000 +727,0.001781438000,0.0006433100000,0.000000000000 +728,0.001660110000,0.0005994960000,0.000000000000 +729,0.001546459000,0.0005584547000,0.000000000000 +730,0.001439971000,0.0005200000000,0.000000000000 +731,0.001340042000,0.0004839136000,0.000000000000 +732,0.001246275000,0.0004500528000,0.000000000000 +733,0.001158471000,0.0004183452000,0.000000000000 +734,0.001076430000,0.0003887184000,0.000000000000 +735,0.000999949300,0.0003611000000,0.000000000000 +736,0.000928735800,0.0003353835000,0.000000000000 +737,0.000862433200,0.0003114404000,0.000000000000 +738,0.000800750300,0.0002891656000,0.000000000000 +739,0.000743396000,0.0002684539000,0.000000000000 +740,0.000690078600,0.0002492000000,0.000000000000 +741,0.000640515600,0.0002313019000,0.000000000000 +742,0.000594502100,0.0002146856000,0.000000000000 +743,0.000551864600,0.0001992884000,0.000000000000 +744,0.000512429000,0.0001850475000,0.000000000000 +745,0.000476021300,0.0001719000000,0.000000000000 +746,0.000442453600,0.0001597781000,0.000000000000 +747,0.000411511700,0.0001486044000,0.000000000000 +748,0.000382981400,0.0001383016000,0.000000000000 +749,0.000356649100,0.0001287925000,0.000000000000 +750,0.000332301100,0.0001200000000,0.000000000000 +751,0.000309758600,0.0001118595000,0.000000000000 +752,0.000288887100,0.0001043224000,0.000000000000 +753,0.000269539400,0.0000973356000,0.000000000000 +754,0.000251568200,0.0000908458700,0.000000000000 +755,0.000234826100,0.0000848000000,0.000000000000 +756,0.000219171000,0.0000791466700,0.000000000000 +757,0.000204525800,0.0000738580000,0.000000000000 +758,0.000190840500,0.0000689160000,0.000000000000 +759,0.000178065400,0.0000643026700,0.000000000000 +760,0.000166150500,0.0000600000000,0.000000000000 +761,0.000155023600,0.0000559818700,0.000000000000 +762,0.000144621900,0.0000522256000,0.000000000000 +763,0.000134909800,0.0000487184000,0.000000000000 +764,0.000125852000,0.0000454474700,0.000000000000 +765,0.000117413000,0.0000424000000,0.000000000000 +766,0.000109551500,0.0000395610400,0.000000000000 +767,0.000102224500,0.0000369151200,0.000000000000 +768,0.000095394450,0.0000344486800,0.000000000000 +769,0.000089023900,0.0000321481600,0.000000000000 +770,0.000083075270,0.0000300000000,0.000000000000 +771,0.000077512690,0.0000279912500,0.000000000000 +772,0.000072313040,0.0000261135600,0.000000000000 +773,0.000067457780,0.0000243602400,0.000000000000 +774,0.000062928440,0.0000227246100,0.000000000000 +775,0.000058706520,0.0000212000000,0.000000000000 +776,0.000054770280,0.0000197785500,0.000000000000 +777,0.000051099180,0.0000184528500,0.000000000000 +778,0.000047676540,0.0000172168700,0.000000000000 +779,0.000044485670,0.0000160645900,0.000000000000 +780,0.000041509940,0.0000149900000,0.000000000000 +781,0.000038733240,0.0000139872800,0.000000000000 +782,0.000036142030,0.0000130515500,0.000000000000 +783,0.000033723520,0.0000121781800,0.000000000000 +784,0.000031464870,0.0000113625400,0.000000000000 +785,0.000029353260,0.0000106000000,0.000000000000 +786,0.000027375730,0.0000098858770,0.000000000000 +787,0.000025524330,0.0000092173040,0.000000000000 +788,0.000023793760,0.0000085923620,0.000000000000 +789,0.000022178700,0.0000080091330,0.000000000000 +790,0.000020673830,0.0000074657000,0.000000000000 +791,0.000019272260,0.0000069595670,0.000000000000 +792,0.000017966400,0.0000064879950,0.000000000000 +793,0.000016749910,0.0000060486990,0.000000000000 +794,0.000015616480,0.0000056393960,0.000000000000 +795,0.000014559770,0.0000052578000,0.000000000000 +796,0.000013573870,0.0000049017710,0.000000000000 +797,0.000012654360,0.0000045697200,0.000000000000 +798,0.000011797230,0.0000042601940,0.000000000000 +799,0.000010998440,0.0000039717390,0.000000000000 +800,0.000010253980,0.0000037029000,0.000000000000 +801,0.000009559646,0.0000034521630,0.000000000000 +802,0.000008912044,0.0000032183020,0.000000000000 +803,0.000008308358,0.0000030003000,0.000000000000 +804,0.000007745769,0.0000027971390,0.000000000000 +805,0.000007221456,0.0000026078000,0.000000000000 +806,0.000006732475,0.0000024312200,0.000000000000 +807,0.000006276423,0.0000022665310,0.000000000000 +808,0.000005851304,0.0000021130130,0.000000000000 +809,0.000005455118,0.0000019699430,0.000000000000 +810,0.000005085868,0.0000018366000,0.000000000000 +811,0.000004741466,0.0000017122300,0.000000000000 +812,0.000004420236,0.0000015962280,0.000000000000 +813,0.000004120783,0.0000014880900,0.000000000000 +814,0.000003841716,0.0000013873140,0.000000000000 +815,0.000003581652,0.0000012934000,0.000000000000 +816,0.000003339127,0.0000012058200,0.000000000000 +817,0.000003112949,0.0000011241430,0.000000000000 +818,0.000002902121,0.0000010480090,0.000000000000 +819,0.000002705645,0.0000009770578,0.000000000000 +820,0.000002522525,0.0000009109300,0.000000000000 +821,0.000002351726,0.0000008492513,0.000000000000 +822,0.000002192415,0.0000007917212,0.000000000000 +823,0.000002043902,0.0000007380904,0.000000000000 +824,0.000001905497,0.0000006881098,0.000000000000 +825,0.000001776509,0.0000006415300,0.000000000000 +826,0.000001656215,0.0000005980895,0.000000000000 +827,0.000001544022,0.0000005575746,0.000000000000 +828,0.000001439440,0.0000005198080,0.000000000000 +829,0.000001341977,0.0000004846123,0.000000000000 +830,0.000001251141,0.0000004518100,0.000000000000 diff --git a/src/main/resources/earthmap.jpg b/src/main/resources/eu/jonahbauer/raytracing/textures/earthmap.jpg similarity index 100% rename from src/main/resources/earthmap.jpg rename to src/main/resources/eu/jonahbauer/raytracing/textures/earthmap.jpg