Compare commits

..

No commits in common. "master" and "kapri-ortho-refraction" have entirely different histories.

18 changed files with 107 additions and 1906 deletions

View file

@ -2,13 +2,13 @@
<library name="google.guava" type="repository"> <library name="google.guava" type="repository">
<properties maven-id="com.google.guava:guava:RELEASE" /> <properties maven-id="com.google.guava:guava:RELEASE" />
<CLASSES> <CLASSES>
<root url="jar://$PROJECT_DIR$/lib/guava-32.1.2-jre.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/guava-31.1-jre.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/failureaccess-1.0.1.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/failureaccess-1.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/jsr305-3.0.2.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/jsr305-3.0.2.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/checker-qual-3.33.0.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/checker-qual-3.12.0.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/error_prone_annotations-2.18.0.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/error_prone_annotations-2.11.0.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/j2objc-annotations-2.8.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/j2objc-annotations-1.3.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_20" default="true" project-jdk-name="liberica-20" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="liberica-19" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View file

@ -56,7 +56,7 @@ public class Color {
default -> null; default -> null;
}; };
} }
public static Color hsb(Vec3 v) { public static Color hsb(Vec3 v) {
return hsb(v.x(), v.y(), v.z()); return hsb(v.x(), v.y(), v.z());
@ -75,7 +75,7 @@ public class Color {
double cr = 4.0767245293f * cl - 3.3072168827f * cm + 0.2307590544f * cs; double cr = 4.0767245293f * cl - 3.3072168827f * cm + 0.2307590544f * cs;
double cg = -1.2681437731f * cl + 2.6093323231f * cm - 0.3411344290f * cs; double cg = -1.2681437731f * cl + 2.6093323231f * cm - 0.3411344290f * cs;
double cb = -0.0041119885f * cl - 0.7034763098f * cm + 1.7068625689f * cs; double cb = -0.0041119885f * cl - 0.7034763098f * cm + 1.7068625689f * cs;
return return
( (
cr < 0 || cr > 1 || cr < 0 || cr > 1 ||
@ -103,24 +103,7 @@ public class Color {
public static Color oklabPolar(Vec3 v) { public static Color oklabPolar(Vec3 v) {
return oklabPolar(v.x(), v.y(), v.z()); return oklabPolar(v.x(), v.y(), v.z());
} }
static double clipDoubleXyz(double x) {
if (x < 0.0)
return 0.0;
return x;
}
public static Color xyz(double x, double y, double z) {
double r = 3.2404542 * x - 1.5371385 * y - 0.4985314 * z;
double g = -0.9692660 * x + 1.8760108 * y + 0.0415560 * z;
double b = 0.0556434 * x - 0.2040259 * y + 1.0572252 * z;
r = clipDoubleXyz(r);
g = clipDoubleXyz(g);
b = clipDoubleXyz(b);
return Color.rgb(r,g,b);
}
public static Color code(int code) { public static Color code(int code) {
return rgb( return rgb(

View file

@ -1,14 +0,0 @@
package xyz.marsavic.gfxlab;
import javafx.util.Pair;
import java.util.Arrays;
import java.util.Comparator;
@FunctionalInterface
public interface Spectrum {
public double at(double wavelength);
public final Spectrum WHITE = w -> 1.0;
public final Spectrum BLACK = w -> 0.0;
}

View file

@ -1,85 +0,0 @@
package xyz.marsavic.gfxlab;
import javafx.util.Pair;
import java.util.Arrays;
import java.util.Comparator;
public class SplineSpectrum implements Spectrum {
Pair<Double, Double>[] samples;
double[] m;
public SplineSpectrum(Pair<Double, Double>[] samples) {
if (samples == null) {
throw new NullPointerException();
}
this.samples = samples;
int n = samples.length;
double[] d = new double[n - 1];
m = new double[n];
for (int i = 1; i < samples.length; i++) {
double h = samples[i].getKey() - samples[i - 1].getKey();
if (h <= 0.0)
throw new IllegalArgumentException("Samples must have strictly increasing x coordinates.");
d[i - 1] = (samples[i].getValue() - samples[i - 1].getValue());
}
m[0] = d[0];
for (int i = 1; i < n - 1; i++) {
if (d[i] == 0.0) {
m[i] = 0.0;
m[i + 1] = 0.0;
} else {
double a = m[i] / d[i];
double b = m[i + 1] / d[i];
double h = a*a+b*b;
if (h > 9.0) {
double t = 3.0 / h;
m[i] = t * a * d[i];
m[i + 1] = t * b * d[i];
}
}
}
}
@Override
public double at(double wavelength) {
final int n = samples.length;
if (wavelength <= samples[0].getKey()) {
return samples[0].getValue();
}
if (wavelength >= samples[n-1].getKey()) {
return samples[n-1].getValue();
}
int i = Arrays.binarySearch(samples,
new Pair<Double, Double>(Double.valueOf(wavelength), null),
new DoublePairKeyComparator());
if (i >= 0) {
return samples[i].getValue();
}
i = -(i+2); // Invert negative result and get index of previous element
double h = samples[i+1].getKey() - samples[i].getKey();
double t = (wavelength - samples[i].getKey()) / h;
return (samples[i].getValue() * (1 + 2*t) + h*m[i]*t) * (1 - t) * (1 - t)
+ (samples[i+1].getValue() * (3 - 2*t) + h * m[i+1] * (t - 1)) * t * t;
}
}
class DoublePairKeyComparator implements Comparator<Pair<Double, Double>> {
@Override
public int compare(Pair<Double, Double> o1, Pair<Double, Double> o2) {
double k1 = o1.getKey(), k2 = o2.getKey();
if (k1 > k2)
return 1;
else if (k1 < k2) {
return -1;
} else {
return 0;
}
}
}

View file

@ -1,20 +1,20 @@
package xyz.marsavic.gfxlab.graphics3d; package xyz.marsavic.gfxlab.graphics3d;
import xyz.marsavic.gfxlab.Spectrum; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Vec3; import xyz.marsavic.gfxlab.Vec3;
/** Point light. */ /** Point light. */
public record Light( public record Light(
Vec3 p, Vec3 p,
Spectrum s Color c
) { ) {
public static Light ps(Vec3 p, Spectrum s) { public static Light pc(Vec3 p, Color c) {
return new Light(p, s); return new Light(p, c);
} }
public static Light p(Vec3 p) { public static Light p(Vec3 p) {
return ps(p, wavelength -> 1.0); return pc(p, Color.WHITE);
} }
} }

View file

@ -1,46 +1,30 @@
package xyz.marsavic.gfxlab.graphics3d; package xyz.marsavic.gfxlab.graphics3d;
import javafx.util.Pair;
import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Spectrum;
import xyz.marsavic.gfxlab.SplineSpectrum;
public record Material( public record Material(
Spectrum diffuse, Color diffuse,
Spectrum specular, Color specular,
Spectrum emissive,
double shininess, double shininess,
Spectrum reflective, Color reflective,
Spectrum refractive, Color refractive,
Spectrum refractiveIndex double refractiveIndex
) { ) {
public Material diffuse (Spectrum diffuse ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); } public Material diffuse (Color diffuse ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
public Material specular (Spectrum specular ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); } public Material specular (Color specular ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
public Material emissive (Spectrum emissive ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); } public Material shininess (double shininess ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
public Material shininess (double shininess ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); } public Material reflective (Color reflective ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
public Material reflective (Spectrum reflective ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); } public Material refractive (Color refractive ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
public Material refractive (Spectrum refractive ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); } public Material refractiveIndex(double refractiveIndex) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
public Material refractiveIndex(Spectrum refractiveIndex) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); }
// Since refractive index is a function from wavelength to a real number, it can be viewed as a spectrum
public static final Material BLACK = new Material(w -> 0, w -> 0, w -> 0, 32, w -> 0, w -> 0, w -> 1.5);
public static Material matte (Spectrum s) { return BLACK.diffuse(s); } public static final Material BLACK = new Material(Color.BLACK, Color.BLACK, 32, Color.BLACK, Color.BLACK, 1.5);
public static Material matte (double k) { return matte(w -> k); }
public static Material matte ( ) { return matte(w -> 1.0); } // TODO: potentially have to replace with D65 public static Material matte (Color c) { return BLACK.diffuse(c); }
public static Material matte (double k) { return matte(Color.gray(k)); }
public static Material matte ( ) { return matte(Color.WHITE); }
public static final Material MATTE = matte(); public static final Material MATTE = matte();
public static final Material MIRROR = BLACK.reflective(new SplineSpectrum(new Pair[]{ public static final Material MIRROR = BLACK.reflective(Color.WHITE);
new Pair<Double, Double>(248.0, 0.926), public static final Material GLASS = BLACK.refractive(Color.WHITE).refractiveIndex(1.5);
new Pair<Double, Double>(400.0, 0.920),
new Pair<Double, Double>(532.0, 0.916),
new Pair<Double, Double>(633.0, 0.907),
new Pair<Double, Double>(800.0, 0.868)
}));
public static final Material GLASS = BLACK.refractive(w -> 1.0)
.refractiveIndex(w -> 1.6 + (w-400)/(800-400) * (1.55 - 1.6)); /* Made to roughly resemble refractive index
of BaK4 crown glass*/
public static Material light (Spectrum s) { return BLACK.emissive(s); }
} }

View file

@ -1,7 +1,6 @@
package xyz.marsavic.gfxlab.graphics3d; package xyz.marsavic.gfxlab.graphics3d;
import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Spectrum;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -13,13 +12,16 @@ public interface Scene {
Collection<Light> lights(); Collection<Light> lights();
Spectrum backgroundSpectrum = wavelength -> 0; default Color colorBackground() {
return Color.BLACK;
}
class Base implements Scene { class Base implements Scene {
protected Solid solid; protected Solid solid;
protected final List<Light> lights = new ArrayList<>(); protected final List<Light> lights = new ArrayList<>();
protected final Color colorBackground = Color.BLACK;
@Override @Override
public Solid solid() { public Solid solid() {
@ -31,7 +33,10 @@ public interface Scene {
return lights; return lights;
} }
public final Spectrum backgroundSpectrum = wavelength -> 0; @Override
public Color colorBackground() {
return colorBackground;
}
} }

View file

@ -1,100 +1,84 @@
package xyz.marsavic.gfxlab.graphics3d.raytracers; package xyz.marsavic.gfxlab.graphics3d.raytracers;
import xyz.marsavic.geometry.Vec;
import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Vec3; import xyz.marsavic.gfxlab.Vec3;
import xyz.marsavic.gfxlab.graphics3d.*; import xyz.marsavic.gfxlab.graphics3d.*;
import xyz.marsavic.random.RNG;
import xyz.marsavic.utils.Numeric;
public class RayTracerSimple extends RayTracer { public class RayTracerSimple extends RayTracer {
private static final int spectrumSamples = 20;
private static final double minWavelength = 380;
private static final double maxWavelength = 780;
private static final double EPSILON = 1e-9; private static final double EPSILON = 1e-9;
private static final int sampleNumber = 4;
private static final double stopProbability = 1.0;
public RayTracerSimple(Scene scene, Camera camera) { public RayTracerSimple(Scene scene, Camera camera) {
super(scene, camera); super(scene, camera);
} }
public static RNG rng = new RNG();
@Override @Override
protected Color sample(Ray ray) { protected Color sample(Ray ray) {
Color result = Color.BLACK; return sample(ray, 64);
for (int i = 0; i < sampleNumber; i++) {
double x = 0.0, y = 0.0, z = 0.0;
for (int j = 0; j < spectrumSamples; j++) {
double wavelength = minWavelength + (((double) j + rng.nextDouble()) / spectrumSamples) * (maxWavelength - minWavelength);
double intensity = sample(ray, wavelength, 7);
x += intensity * Xyz.x[(int) wavelength];
y += intensity * Xyz.y[(int) wavelength];
z += intensity * Xyz.z[(int) wavelength];
}
result = result.add(Color.xyz(x, y, z));
}
return result.div(sampleNumber);
} }
protected double sample(Ray ray, double wavelength, int depthRemaining) { protected Color sample(Ray ray, int depthRemaining) {
double returnFactor = 1.0; if (depthRemaining == 0) {
if (depthRemaining <= 0) { return Color.BLACK;
if (rng.nextDouble(1.0) <= stopProbability) {
return 0.0;
} else {
returnFactor = 1/(1-stopProbability);
}
} }
Hit hit = scene.solid().firstHit(ray, EPSILON); Hit hit = scene.solid().firstHit(ray, EPSILON);
if (hit == null) { if (hit == null) {
return scene.backgroundSpectrum.at(wavelength); return scene.colorBackground();
} }
Vec3 p = ray.at(hit.t()); // The hit point Vec3 p = ray.at(hit.t()); // The hit point
Vec3 n_ = hit.n_(); // Normalized normal to the body surface at the hit point Vec3 n_ = hit.n_(); // Normalized normal to the body surface at the hit point
Vec3 i = ray.d().inverse(); // Incoming direction Vec3 i = ray.d().inverse(); // Incoming direction
double lI = i.length(); double lI = i.length();
Vec3 r = GeometryUtils.reflectedN(n_, i); // Reflected ray (i reflected over n) Vec3 r = GeometryUtils.reflectedN(n_, i); // Reflected ray (i reflected over n)
Vec3 r_ = r.div(lI); // Reflected ray (i reflected over n) Vec3 r_ = r.div(lI); // Reflected ray (i reflected over n)
Color lightDiffuse = Color.BLACK; // The sum of diffuse contributions from all the lights
Color lightSpecular = Color.BLACK; // The sum of specular contributions from all the lights
Material material = hit.material(); Material material = hit.material();
double lightDiffuse = 0.0; // The diffuse contribution of the generated path for (Light light : scene.lights()) {
double lightSpecular = 0.0; // The specular contribution of the generated path Vec3 l = light.p().sub(p); // Vector from p to the light;
double lightReflected = 0.0; // The reflective contribution of the generated path
double lightRefracted = 0.0; // The refractive contribution of the generated path Ray rayToLight = Ray.pd(p, l);
double lightEmissive = material.emissive().at(wavelength); // The contribution of the light surface itself if (scene.solid().hitBetween(rayToLight, EPSILON, 1)) continue;
double result = lightEmissive; double lLSqr = l.lengthSquared(); // Distance from p to the light squared
double lL = Math.sqrt(lLSqr); // Distance from p to the light
double diffuse = material.diffuse().at(wavelength); double cosLN = n_.dot(l) / lL; // Cosine of the angle between l and n_
if (diffuse != 0.0) {
double r1 = rng.nextDouble(1.0); // Angle of projected random vector in the plain normal to n_ if (cosLN > 0) { // If the light is above the surface
double r2 = rng.nextDouble(0.25); // Angle of vector compared to n_ Color irradiance = light.c().mul(cosLN / lLSqr);
Vec3 u_ = GeometryUtils.normal(n_).normalized_(); // One of the normalized vectors normal to n // The irradiance represents how much light is received by a unit area of the surface. It is
Vec3 v_ = n_.cross(u_); // Doesn't need to be normalized because n_ and u_ are normalized and normal // proportional to the cosine of the incoming angle and inversely proportional to the distance squared
Vec3 o = u_.mul(Numeric.sinT(r1)).add(v_.mul(Numeric.cosT(r1))) // (inverse-square law).
.mul(Numeric.cosT(r2)).add(n_.mul(Numeric.sinT(r2))); // Outgoing sample vector lightDiffuse = lightDiffuse.add(irradiance);
lightDiffuse = diffuse * sample(Ray.pd(p, o), wavelength, depthRemaining - 1);
double cosLR = l.dot(r_);
if (cosLR > 0) { // If the angle between l and r is acute
cosLR /= lL;
lightSpecular = lightSpecular.add(irradiance.mul(Math.pow(cosLR, material.shininess())));
}
}
}
Color result = Color.BLACK;
result = result.add(material.diffuse ().mul(lightDiffuse ));
result = result.add(material.specular().mul(lightSpecular));
if (material.reflective().notZero()) {
// When material has reflective properties we recursively find the color visible along the ray (p, r).
Color lightReflected = sample(Ray.pd(p, r), depthRemaining - 1);
result = result.add(material.reflective().mul(lightReflected));
} }
result += lightDiffuse;
double reflective = material.reflective().at(wavelength);
if (reflective != 0.0) {
lightReflected = sample(Ray.pd(p, r), wavelength, depthRemaining - 1);
result += reflective * lightReflected;
}
double refractive = material.refractive().at(wavelength); if (material.refractive().notZero()) {
if (refractive != 0.0) {
Vec3 b; // refracted light vector Vec3 b; // refracted light vector
double rInd = 1/material.refractiveIndex().at(wavelength); double rInd = 1/material.refractiveIndex();
double iCosN = i.dot(n_); double iCosN = i.dot(n_);
if (iCosN < 0) { if (iCosN < 0) {
@ -114,10 +98,11 @@ public class RayTracerSimple extends RayTracer {
} }
b = bRejection.add(bProjection); b = bRejection.add(bProjection);
} }
lightRefracted = sample(Ray.pd(p, b), wavelength, depthRemaining - 1); Color lightRefracted = sample(Ray.pd(p, b), depthRemaining - 1);
result += refractive * lightRefracted; result = result.add(material.refractive().mul(lightRefracted));
} }
return returnFactor * result; return result;
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,5 @@
/*
package xyz.marsavic.gfxlab.graphics3d.scene; package xyz.marsavic.gfxlab.graphics3d.scene;
import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Vec3; import xyz.marsavic.gfxlab.Vec3;
import xyz.marsavic.gfxlab.graphics3d.Light; import xyz.marsavic.gfxlab.graphics3d.Light;
@ -58,4 +56,3 @@ public class DiscoRoom extends Scene.Base {
} }
} }
*/

View file

@ -1,4 +1,3 @@
/*
package xyz.marsavic.gfxlab.graphics3d.scene; package xyz.marsavic.gfxlab.graphics3d.scene;
import xyz.marsavic.geometry.Vector; import xyz.marsavic.geometry.Vector;
@ -51,4 +50,3 @@ public class Mirrors extends Scene.Base {
} }
} }
*/

View file

@ -1,7 +1,5 @@
/*
package xyz.marsavic.gfxlab.graphics3d.scene; package xyz.marsavic.gfxlab.graphics3d.scene;
import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Vec3; import xyz.marsavic.gfxlab.Vec3;
import xyz.marsavic.gfxlab.graphics3d.Light; import xyz.marsavic.gfxlab.graphics3d.Light;
@ -50,4 +48,3 @@ public class RefractionTest extends Scene.Base {
} }
} }
*/

View file

@ -1,4 +1,4 @@
/* package xyz.marsavic.gfxlab.graphics3d.scene; package xyz.marsavic.gfxlab.graphics3d.scene;
import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Vec3; import xyz.marsavic.gfxlab.Vec3;
@ -32,4 +32,3 @@ public class SceneTest1 extends Scene.Base{
} }
} }
*/

View file

@ -1,75 +0,0 @@
package xyz.marsavic.gfxlab.graphics3d.scene;
import xyz.marsavic.functions.interfaces.F1;
import xyz.marsavic.geometry.Vector;
import xyz.marsavic.gfxlab.SplineSpectrum;
import xyz.marsavic.gfxlab.Vec3;
import xyz.marsavic.gfxlab.graphics3d.*;
import xyz.marsavic.gfxlab.graphics3d.solids.Ball;
import xyz.marsavic.gfxlab.graphics3d.solids.Group;
import xyz.marsavic.gfxlab.graphics3d.solids.HalfSpace;
import xyz.marsavic.gfxlab.graphics3d.solids.Parallelepiped;
import xyz.marsavic.gfxlab.graphics3d.textures.Grid;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class SpectrumTest extends Scene.Base {
public SpectrumTest() {
var materialUVWalls = (F1<Material, Vector>) (uv -> Material.matte(1.0));
var materialBlocks = (F1<Material, Vector>) (uv -> Material.matte(0.0));
var materialUVWallsL = Grid.standard(w -> 1.0);
var materialUVWallsB = Grid.standard(w -> 1.0);
var materialCoverBlock = Grid.standard(w -> 0.0);
var materialUVWallsR = Grid.standard(w -> 1.0);
var materialGlass = (F1<Material, Vector>) (uv -> Material.GLASS
.refractiveIndex(w -> 5.6 + (w-400)/(800-400) * (1.55 - 5.6)));
var materialMirror = (F1<Material, Vector>) (uv -> Material.MIRROR);
var materialLight = (F1<Material, Vector>) (uv -> Material.light(w -> 1.0));
Collection<Solid> solids = new ArrayList<>();
Collections.addAll(solids,
HalfSpace.pn(Vec3.xyz(-1, 0, 0), Vec3.xyz( 1, 0, 0), materialUVWallsL),
HalfSpace.pn(Vec3.xyz( 1, 0, 0), Vec3.xyz(-1, 0, 0), materialUVWallsR),
HalfSpace.pn(Vec3.xyz( 0, -1, 0), Vec3.xyz( 0, 1, 0), materialUVWalls),
// HalfSpace.pn(Vec3.xyz( 0, 1, 0), Vec3.xyz( 0, -1, 0), materialUVWalls),
HalfSpace.pn(Vec3.xyz( 0, 0, 1), Vec3.xyz( 0, 0, -1), materialUVWallsB),
HalfSpace.pn(Vec3.xyz( 0, 0, -6), Vec3.xyz( 0, 0, 1), materialUVWallsB),
Ball.cr(Vec3.xyz(0, 6, 0), 0.8, materialLight),
Parallelepiped.pabc(Vec3.xyz(-0.25, 0, 0.25),
Vec3.xyz(0.6, 0.8, 0),
Vec3.xyz(-0.2, -0.6, 0),
Vec3.xyz(0, 0, -0.5),
materialGlass),
Parallelepiped.pabc(Vec3.xyz(-1, 1, 1),
Vec3.xyz(0.75, 0, 0),
Vec3.xyz(0, 0.4, 0),
Vec3.xyz(0, 0, -6),
materialCoverBlock),
Parallelepiped.pabc(Vec3.xyz(0.25, 1, 1),
Vec3.xyz(2, 0, 0),
Vec3.xyz(0, 0.4, 0),
Vec3.xyz(0, 0, -6),
materialCoverBlock),
Parallelepiped.pabc(Vec3.xyz(-0.25, 1, 1),
Vec3.xyz(0.5, 0, 0),
Vec3.xyz(0, 0.4, 0),
Vec3.xyz(0, 0, -0.75),
materialCoverBlock),
Parallelepiped.pabc(Vec3.xyz(-0.25, 1, -0.25),
Vec3.xyz(0.5, 0, 0),
Vec3.xyz(0, 0.4, 0),
Vec3.xyz(0, 0, -6),
materialCoverBlock)
);
solid = Group.of(solids);
}
}

View file

@ -1,108 +0,0 @@
package xyz.marsavic.gfxlab.graphics3d.solids;
import xyz.marsavic.functions.interfaces.F1;
import xyz.marsavic.geometry.Vector;
import xyz.marsavic.gfxlab.Vec3;
import xyz.marsavic.gfxlab.graphics3d.Hit;
import xyz.marsavic.gfxlab.graphics3d.Material;
import xyz.marsavic.gfxlab.graphics3d.Ray;
import xyz.marsavic.gfxlab.graphics3d.Solid;
public class Parallelepiped implements Solid {
private final Vec3 p; // starting vertex
private final Vec3[][][] vertices;
HalfSpace [] sides;
private final Vec3 a, b, c;
private Parallelepiped(Vec3 point, Vec3 aEdge, Vec3 bEdge, Vec3 cEdge, F1<Material, Vector> mapMaterial) {
this.p = point;
this.a = aEdge;
this.b = bEdge;
this.c = cEdge;
vertices = new Vec3[][][]
{{{p, p.add(c)}, {p.add(b), p.add(b).add(c)}},
{{p.add(a), p.add(a).add(c)}, {p.add(a).add(b), p.add(a).add(b).add(c)}}};
sides = new HalfSpace[6];
sides[0] = HalfSpace.pef(p, b, a, mapMaterial);
sides[1] = HalfSpace.pef(p.add(c), a, b, mapMaterial);
sides[2] = HalfSpace.pef(p, a, c, mapMaterial);
sides[3] = HalfSpace.pef(p.add(b), c, a, mapMaterial);
sides[4] = HalfSpace.pef(p, c, b, mapMaterial);
sides[5] = HalfSpace.pef(p.add(a), b, c, mapMaterial);
}
public static Parallelepiped pabc(Vec3 p, Vec3 a, Vec3 b, Vec3 c, F1<Material, Vector> mapMaterial) {
return new Parallelepiped(p, a, b, c, mapMaterial);
}
public Vec3 p() {
return p;
}
public Vec3 a() {
return a;
}
public Vec3 b() {
return b;
}
public Vec3 c() {
return c;
}
public Vec3[][][] vertices() {
return vertices.clone();
}
private static boolean pointOnParallelogram(Vec3 p, Vec3 e, Vec3 f) {
// we solve p as a linear combination of a*e+b*f, then check if this combination is in
// 0<=a<=1 and 0<=b<=1
double D = e.lengthSquared() * f.lengthSquared() - e.dot(f)*e.dot(f);
if (D == 0)
return false;
// System determinant
double Da = p.dot(e)*f.lengthSquared() - p.dot(f)*e.dot(f);
// a's determinant
double Db = e.lengthSquared()*p.dot(f) - e.dot(f)*p.dot(e);
double a = Da/D;
// a's determinant
double b = Db/D;
// b's determinant
return a >= 0 && a <= 1 && b >= 0 && b <= 1;
}
@Override
public Hit firstHit(Ray ray, double afterTime) {
Hit[] planeHits = new Hit[6];
for (int i = 0; i < 6; i++) {
planeHits[i] = sides[i].firstHit(ray, afterTime);
if (planeHits[i] == null) {
continue;
}
Vec3 rayPlaneIntersect = ray.at(planeHits[i].t());
if (!pointOnParallelogram(rayPlaneIntersect.sub(sides[i].p()), sides[i].e(), sides[i].f())) {
planeHits[i] = null;
}
}
double minT = Hit.t(null); // Positive infinity
int minI = 0;
for (int i = 0; i < 6; i++) {
if (Hit.t(planeHits[i]) < minT) {
minT = Hit.t(planeHits[i]);
minI = i;
}
}
return planeHits[minI];
}
}

View file

@ -4,7 +4,6 @@ package xyz.marsavic.gfxlab.graphics3d.textures;
import xyz.marsavic.functions.interfaces.F1; import xyz.marsavic.functions.interfaces.F1;
import xyz.marsavic.geometry.Vector; import xyz.marsavic.geometry.Vector;
import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Spectrum;
import xyz.marsavic.gfxlab.graphics3d.Material; import xyz.marsavic.gfxlab.graphics3d.Material;
@ -34,22 +33,22 @@ public class Grid implements F1<Material, Vector> {
} }
public static Grid standard(Spectrum spectrum) { public static Grid standard(Color color) {
return new Grid( return new Grid(
Vector.xy(0.25, 0.25), Vector.xy(0.25, 0.25),
Vector.xy(0.01, 0.01), Vector.xy(0.01, 0.01),
Material.matte(spectrum), Material.matte(color),
Material.matte(w -> spectrum.at(w) * 0.75) Material.matte(color.mul(0.75))
); );
} }
public static Grid standardUnit(Spectrum spectrum) { public static Grid standardUnit(Color color) {
return new Grid( return new Grid(
Vector.UNIT_DIAGONAL, Vector.UNIT_DIAGONAL,
Vector.xy(1.0/64), Vector.xy(1.0/64),
Material.matte(spectrum), Material.matte(color),
Material.matte(w -> spectrum.at(w) * 0.75) Material.matte(color.mul(0.75))
); );
} }
} }

View file

@ -8,7 +8,7 @@ import xyz.marsavic.gfxlab.graphics3d.Affine;
import xyz.marsavic.gfxlab.graphics3d.cameras.Perspective; import xyz.marsavic.gfxlab.graphics3d.cameras.Perspective;
import xyz.marsavic.gfxlab.graphics3d.cameras.TransformedCamera; import xyz.marsavic.gfxlab.graphics3d.cameras.TransformedCamera;
import xyz.marsavic.gfxlab.graphics3d.raytracers.RayTracerSimple; import xyz.marsavic.gfxlab.graphics3d.raytracers.RayTracerSimple;
import xyz.marsavic.gfxlab.graphics3d.scene.SpectrumTest; import xyz.marsavic.gfxlab.graphics3d.scene.RefractionTest;
import xyz.marsavic.gfxlab.gui.UtilsGL; import xyz.marsavic.gfxlab.gui.UtilsGL;
import xyz.marsavic.gfxlab.tonemapping.ColorTransform; import xyz.marsavic.gfxlab.tonemapping.ColorTransform;
import xyz.marsavic.gfxlab.tonemapping.ToneMapping; import xyz.marsavic.gfxlab.tonemapping.ToneMapping;
@ -35,13 +35,14 @@ public class GfxLab {
e(RayTracerSimple::new, e(RayTracerSimple::new,
// e(RefractionTest::new), // e(RefractionTest::new),
// e(DiscoRoom::new, val(16), val(16), val(0x3361EB272FEA4C62L)), // e(DiscoRoom::new, val(16), val(16), val(0x3361EB272FEA4C62L)),
e(SpectrumTest::new), e(RefractionTest::new),
// e(Mirrors::new, val(3)), // e(Mirrors::new, val(3)),
e(TransformedCamera::new, e(TransformedCamera::new,
e(Perspective::new, val(1.0/3)), e(Perspective::new, val(1.0/3)),
// e(Orthographic::new), // e(Orthographic::new),
e(Affine.IDENTITY e(Affine.IDENTITY
.then(Affine.translation(Vec3.xyz(0, 0, -4))) .then(Affine.translation(Vec3.xyz(0, 0, -4)))
// .then(Affine.rotationAboutY(0.03))
) )
) )
), ),