Compare commits
5 commits
master
...
kapri-scen
Author | SHA1 | Date | |
---|---|---|---|
![]() |
53958e9b97 | ||
![]() |
96fd7e4339 | ||
![]() |
110e85827e | ||
![]() |
edf8d251ed | ||
![]() |
b3f073e2be |
|
@ -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 />
|
||||||
|
|
|
@ -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>
|
|
@ -9,7 +9,6 @@
|
||||||
- Ako koristite IntelliJ, ovo je lako namestiti: File > Project Structure... > Project > SDK > Add SDK > Download JDK... > Vendor: BellSoft Liberica JDK 19.0.1.
|
- Ako koristite IntelliJ, ovo je lako namestiti: File > Project Structure... > Project > SDK > Add SDK > Download JDK... > Vendor: BellSoft Liberica JDK 19.0.1.
|
||||||
- Alternativno, sami preuzmite JDK sa [https://bell-sw.com/pages/downloads/](https://bell-sw.com/pages/downloads/#/java-19-current). Izaberite vaš OS, poslednju verziju, i Full JDK (jedino Full JDK uključuje JavaFX). Kada instalirate/raspakujete JDK, namestite u IDE-u da projekat koristi baš taj JDK.
|
- Alternativno, sami preuzmite JDK sa [https://bell-sw.com/pages/downloads/](https://bell-sw.com/pages/downloads/#/java-19-current). Izaberite vaš OS, poslednju verziju, i Full JDK (jedino Full JDK uključuje JavaFX). Kada instalirate/raspakujete JDK, namestite u IDE-u da projekat koristi baš taj JDK.
|
||||||
- Ako nećete da koristite BellSoft Liberica JDK, snađite se da preuzmete odgovarajuće biblioteke na neki način (direktni download svih potrebnih jar-fajlova, Maven, ...). Potrebni su vam javafx-base, javafx-controls, javafx-graphics, i javafx-swing.
|
- Ako nećete da koristite BellSoft Liberica JDK, snađite se da preuzmete odgovarajuće biblioteke na neki način (direktni download svih potrebnih jar-fajlova, Maven, ...). Potrebni su vam javafx-base, javafx-controls, javafx-graphics, i javafx-swing.
|
||||||
- U nekim slučajevima JavaFX neće koristiti GPU za iscrtavanje interfejsa i sve će biti pomalo laggy (meni se to dešava uz Linux i integrisani GPU). U tom slučaju (a ni inače verovatno ne može da škodi), dodajte system property `prism.forceGPU = true`, npr. kroz VM argument `-Dprism.forceGPU=true`.
|
|
||||||
|
|
||||||
|
|
||||||
## Šta-gde
|
## Šta-gde
|
||||||
|
|
BIN
resources/obomba.jpg
Normal file
BIN
resources/obomba.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
|
@ -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(
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package xyz.marsavic.gfxlab.graphics3d;
|
|
||||||
|
|
||||||
import xyz.marsavic.geometry.Vector;
|
|
||||||
|
|
||||||
|
|
||||||
public interface Camera {
|
|
||||||
Ray exitingRay(Vector sensorPosition);
|
|
||||||
}
|
|
|
@ -2,6 +2,8 @@ package xyz.marsavic.gfxlab.graphics3d;
|
||||||
|
|
||||||
|
|
||||||
import xyz.marsavic.gfxlab.Vec3;
|
import xyz.marsavic.gfxlab.Vec3;
|
||||||
|
import xyz.marsavic.random.sampling.Sampler;
|
||||||
|
import xyz.marsavic.utils.Numeric;
|
||||||
|
|
||||||
public class GeometryUtils {
|
public class GeometryUtils {
|
||||||
|
|
||||||
|
@ -24,12 +26,4 @@ public class GeometryUtils {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Vec3 reflected(Vec3 n, Vec3 d) {
|
|
||||||
return n.mul(2 * d.dot(n) / n.lengthSquared()).sub(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 reflectedN(Vec3 n_, Vec3 d) {
|
|
||||||
return n_.mul(2 * d.dot(n_)).sub(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,32 @@
|
||||||
package xyz.marsavic.gfxlab.graphics3d;
|
package xyz.marsavic.gfxlab.graphics3d;
|
||||||
|
|
||||||
import javafx.util.Pair;
|
import xyz.marsavic.geometry.Vector;
|
||||||
import xyz.marsavic.gfxlab.Color;
|
import xyz.marsavic.gfxlab.Color;
|
||||||
import xyz.marsavic.gfxlab.Spectrum;
|
|
||||||
import xyz.marsavic.gfxlab.SplineSpectrum;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
public record Material(
|
public record Material(
|
||||||
Spectrum diffuse,
|
Color diffuse
|
||||||
Spectrum specular,
|
|
||||||
Spectrum emissive,
|
|
||||||
double shininess,
|
|
||||||
Spectrum reflective,
|
|
||||||
Spectrum refractive,
|
|
||||||
Spectrum refractiveIndex
|
|
||||||
|
|
||||||
) {
|
) {
|
||||||
public Material diffuse (Spectrum diffuse ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); }
|
public static Material diffuseImage(BufferedImage img, Vector uv) {
|
||||||
public Material specular (Spectrum specular ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); }
|
int x = (int) (uv.x()*img.getWidth()) % img.getWidth();
|
||||||
public Material emissive (Spectrum emissive ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); }
|
if (x < 0) {
|
||||||
public Material shininess (double shininess ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); }
|
x += img.getWidth(); // adding in case of negative modulo
|
||||||
public Material reflective (Spectrum reflective ) { return new Material(diffuse, specular, emissive, shininess, reflective, refractive, refractiveIndex); }
|
}
|
||||||
public Material refractive (Spectrum refractive ) { return new Material(diffuse, specular, emissive, 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);
|
int y = (int) (uv.y()*img.getWidth()) % img.getWidth();
|
||||||
|
if (y < 0) {
|
||||||
|
y += img.getHeight();
|
||||||
|
}
|
||||||
|
y = img.getHeight()-y-1; // inverting y, BufferedImage is encoded from top to bottom, and uv mapping is bottom to top
|
||||||
|
return new Material(Color.code(img.getRGB(x, y)));
|
||||||
|
}
|
||||||
|
public Material diffuse(Color diffuse) { return new Material(diffuse); }
|
||||||
|
|
||||||
public static Material matte (Spectrum s) { return BLACK.diffuse(s); }
|
public static final Material BLACK = new Material(Color.BLACK);
|
||||||
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[]{
|
|
||||||
new Pair<Double, Double>(248.0, 0.926),
|
|
||||||
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); }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package xyz.marsavic.gfxlab.graphics3d;
|
package xyz.marsavic.gfxlab.graphics3d;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public interface Solid {
|
public interface Solid {
|
||||||
|
|
||||||
|
@ -16,12 +19,4 @@ public interface Solid {
|
||||||
return firstHit(ray, 0);
|
return firstHit(ray, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
default boolean hitBetween(Ray ray, double afterTime, double beforeTime) {
|
|
||||||
Hit hit = firstHit(ray);
|
|
||||||
if (hit == null) return false;
|
|
||||||
double t = hit.t();
|
|
||||||
return (afterTime < t) && (t < beforeTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
package xyz.marsavic.gfxlab.graphics3d.cameras;
|
|
||||||
|
|
||||||
import xyz.marsavic.geometry.Vector;
|
|
||||||
import xyz.marsavic.gfxlab.Vec3;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Camera;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Ray;
|
|
||||||
|
|
||||||
public class Orthographic implements Camera {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Ray exitingRay(Vector p) {
|
|
||||||
return Ray.pd(Vec3.zp(0, p), Vec3.xyz(0, 0, 1));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package xyz.marsavic.gfxlab.graphics3d.cameras;
|
|
||||||
|
|
||||||
import xyz.marsavic.geometry.Vector;
|
|
||||||
import xyz.marsavic.gfxlab.Vec3;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Camera;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Ray;
|
|
||||||
import xyz.marsavic.utils.Numeric;
|
|
||||||
|
|
||||||
|
|
||||||
public record Perspective(
|
|
||||||
double k
|
|
||||||
) implements Camera {
|
|
||||||
|
|
||||||
public static Perspective fov(double angle) {
|
|
||||||
return new Perspective(Numeric.tanT(angle / 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Ray exitingRay(Vector p) {
|
|
||||||
return Ray.pd(Vec3.ZERO, Vec3.zp(1/k, p));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package xyz.marsavic.gfxlab.graphics3d.cameras;
|
|
||||||
|
|
||||||
import xyz.marsavic.geometry.Vector;
|
|
||||||
import xyz.marsavic.gfxlab.Transformation;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Camera;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Ray;
|
|
||||||
|
|
||||||
|
|
||||||
public record TransformedCamera (
|
|
||||||
Camera source,
|
|
||||||
Transformation transformation
|
|
||||||
) implements Camera {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Ray exitingRay(Vector sensorPosition) {
|
|
||||||
Ray ray = source.exitingRay(sensorPosition);
|
|
||||||
return transformation.at(ray);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ package xyz.marsavic.gfxlab.graphics3d.raytracers;
|
||||||
import xyz.marsavic.geometry.Vector;
|
import xyz.marsavic.geometry.Vector;
|
||||||
import xyz.marsavic.gfxlab.Color;
|
import xyz.marsavic.gfxlab.Color;
|
||||||
import xyz.marsavic.gfxlab.ColorFunctionT;
|
import xyz.marsavic.gfxlab.ColorFunctionT;
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Camera;
|
import xyz.marsavic.gfxlab.Vec3;
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Ray;
|
import xyz.marsavic.gfxlab.graphics3d.Ray;
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Scene;
|
import xyz.marsavic.gfxlab.graphics3d.Scene;
|
||||||
|
|
||||||
|
@ -11,12 +11,10 @@ import xyz.marsavic.gfxlab.graphics3d.Scene;
|
||||||
public abstract class RayTracer implements ColorFunctionT {
|
public abstract class RayTracer implements ColorFunctionT {
|
||||||
|
|
||||||
protected final Scene scene;
|
protected final Scene scene;
|
||||||
protected final Camera camera;
|
|
||||||
|
|
||||||
|
|
||||||
public RayTracer(Scene scene, Camera camera) {
|
public RayTracer(Scene scene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.camera = camera;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,8 +22,12 @@ public abstract class RayTracer implements ColorFunctionT {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Color at(double t, Vector p) {
|
public Color at(double t, Vector p) {
|
||||||
Ray ray = camera.exitingRay(p);
|
Ray ray = Ray.pd(Vec3.xyz(0, 0, -15), Vec3.zp(1.6, p));
|
||||||
return sample(ray);
|
return sample(ray);
|
||||||
}
|
}
|
||||||
|
// @Override
|
||||||
|
// public Color at(double t, Vector p) {
|
||||||
|
// Ray ray = Ray.pd(Vec3.xyz(0, 20, -20), Vec3.xyz(0, -1, 1).add(Vec3.xyz(p.x(), p.y(), p.y())));
|
||||||
|
// return sample(ray);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,123 +1,49 @@
|
||||||
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;
|
public RayTracerSimple(Scene scene) {
|
||||||
private static final double minWavelength = 380;
|
super(scene);
|
||||||
private static final double maxWavelength = 780;
|
|
||||||
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) {
|
|
||||||
super(scene, camera);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RNG rng = new RNG();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Color sample(Ray ray) {
|
protected Color sample(Ray r) {
|
||||||
Color result = Color.BLACK;
|
Hit hit = scene.solid().firstHit(r);
|
||||||
for (int i = 0; i < sampleNumber; i++) {
|
if (hit == null) {
|
||||||
double x = 0.0, y = 0.0, z = 0.0;
|
return scene.colorBackground();
|
||||||
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);
|
|
||||||
}
|
Vec3 p = r.at(hit.t()); // The hit point
|
||||||
|
Vec3 n_ = hit.n_(); // Normalized normal to the body surface at the hit point
|
||||||
protected double sample(Ray ray, double wavelength, int depthRemaining) {
|
|
||||||
double returnFactor = 1.0;
|
Color lightDiffuse = Color.BLACK; // The sum of diffuse contributions from all the lights
|
||||||
if (depthRemaining <= 0) {
|
|
||||||
if (rng.nextDouble(1.0) <= stopProbability) {
|
for (Light light : scene.lights()) {
|
||||||
return 0.0;
|
Vec3 l = light.p().sub(p); // Vector from p to the light;
|
||||||
} else {
|
Ray lRay = new Ray(light.p(), l.inverse()); // Project a Ray from light source to object
|
||||||
returnFactor = 1/(1-stopProbability);
|
Hit lHit = scene.solid().firstHit(lRay);
|
||||||
|
double epsilon = 0.000001;
|
||||||
|
if (lRay.at(Hit.t(lHit)).sub(p).lengthSquared() >= epsilon)
|
||||||
|
continue; // if it strikes an object before our point, a shadow is cast, no light is added
|
||||||
|
double lLSqr = l.lengthSquared(); // Distance from p to the light squared
|
||||||
|
double lL = Math.sqrt(lLSqr); // Distance from p to the light
|
||||||
|
double cosLN = n_.dot(l) / lL; // Cosine of the angle between l and n_
|
||||||
|
|
||||||
|
if (cosLN > 0) { // If the light is above the surface
|
||||||
|
Color irradiance = light.c().mul(cosLN / lLSqr);
|
||||||
|
// The irradiance represents how much light is received by a unit area of the surface. It is
|
||||||
|
// proportional to the cosine of the incoming angle and inversely proportional to the distance squared
|
||||||
|
// (inverse-square law).
|
||||||
|
lightDiffuse = lightDiffuse.add(irradiance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Hit hit = scene.solid().firstHit(ray, EPSILON);
|
return hit.material().diffuse().mul(lightDiffuse);
|
||||||
if (hit == null) {
|
|
||||||
return scene.backgroundSpectrum.at(wavelength);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 p = ray.at(hit.t()); // The hit point
|
|
||||||
Vec3 n_ = hit.n_(); // Normalized normal to the body surface at the hit point
|
|
||||||
Vec3 i = ray.d().inverse(); // Incoming direction
|
|
||||||
double lI = i.length();
|
|
||||||
Vec3 r = GeometryUtils.reflectedN(n_, i); // Reflected ray (i reflected over n)
|
|
||||||
Vec3 r_ = r.div(lI); // Reflected ray (i reflected over n)
|
|
||||||
|
|
||||||
Material material = hit.material();
|
|
||||||
|
|
||||||
double lightDiffuse = 0.0; // The diffuse contribution of the generated path
|
|
||||||
double lightSpecular = 0.0; // The specular contribution of the generated path
|
|
||||||
double lightReflected = 0.0; // The reflective contribution of the generated path
|
|
||||||
double lightRefracted = 0.0; // The refractive contribution of the generated path
|
|
||||||
double lightEmissive = material.emissive().at(wavelength); // The contribution of the light surface itself
|
|
||||||
|
|
||||||
double result = lightEmissive;
|
|
||||||
|
|
||||||
double diffuse = material.diffuse().at(wavelength);
|
|
||||||
if (diffuse != 0.0) {
|
|
||||||
double r1 = rng.nextDouble(1.0); // Angle of projected random vector in the plain normal to n_
|
|
||||||
double r2 = rng.nextDouble(0.25); // Angle of vector compared to n_
|
|
||||||
Vec3 u_ = GeometryUtils.normal(n_).normalized_(); // One of the normalized vectors normal to n
|
|
||||||
Vec3 v_ = n_.cross(u_); // Doesn't need to be normalized because n_ and u_ are normalized and normal
|
|
||||||
Vec3 o = u_.mul(Numeric.sinT(r1)).add(v_.mul(Numeric.cosT(r1)))
|
|
||||||
.mul(Numeric.cosT(r2)).add(n_.mul(Numeric.sinT(r2))); // Outgoing sample vector
|
|
||||||
lightDiffuse = diffuse * sample(Ray.pd(p, o), wavelength, depthRemaining - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (refractive != 0.0) {
|
|
||||||
Vec3 b; // refracted light vector
|
|
||||||
double rInd = 1/material.refractiveIndex().at(wavelength);
|
|
||||||
|
|
||||||
double iCosN = i.dot(n_);
|
|
||||||
if (iCosN < 0) {
|
|
||||||
rInd = 1/rInd;
|
|
||||||
}
|
|
||||||
Vec3 iProjection = n_.mul(iCosN);
|
|
||||||
Vec3 iRejection = i.sub(iProjection);
|
|
||||||
double iSinSqr = iRejection.lengthSquared()/i.lengthSquared();
|
|
||||||
double bSinSqr = iSinSqr*rInd*rInd;
|
|
||||||
if (bSinSqr > 1) {
|
|
||||||
b = r;
|
|
||||||
} else {
|
|
||||||
Vec3 bRejection = iRejection.inverse();
|
|
||||||
Vec3 bProjection = n_.mul(Math.sqrt(bRejection.lengthSquared()*(1-bSinSqr)/bSinSqr));
|
|
||||||
if (iCosN > 0) {
|
|
||||||
bProjection = bProjection.inverse();
|
|
||||||
}
|
|
||||||
b = bRejection.add(bProjection);
|
|
||||||
}
|
|
||||||
lightRefracted = sample(Ray.pd(p, b), wavelength, depthRemaining - 1);
|
|
||||||
result += refractive * lightRefracted;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnFactor * result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
package xyz.marsavic.gfxlab.graphics3d.scene;
|
|
||||||
|
|
||||||
|
|
||||||
import xyz.marsavic.gfxlab.Color;
|
|
||||||
import xyz.marsavic.gfxlab.Vec3;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Light;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Material;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Scene;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Solid;
|
|
||||||
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.textures.Grid;
|
|
||||||
import xyz.marsavic.random.RNG;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
|
|
||||||
public class DiscoRoom extends Scene.Base {
|
|
||||||
|
|
||||||
public DiscoRoom(int nBalls, int nLights, long seed) {
|
|
||||||
RNG rngBalls = new RNG(2*seed);
|
|
||||||
|
|
||||||
var materialUVWalls = Grid.standard(Color.WHITE);
|
|
||||||
|
|
||||||
Collection<Solid> solids = new ArrayList<>();
|
|
||||||
Collections.addAll(solids,
|
|
||||||
HalfSpace.pn(Vec3.xyz(-1, 0, 0), Vec3.xyz( 1, 0, 0), materialUVWalls),
|
|
||||||
HalfSpace.pn(Vec3.xyz( 1, 0, 0), Vec3.xyz(-1, 0, 0), materialUVWalls),
|
|
||||||
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), materialUVWalls)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < nBalls; i++) {
|
|
||||||
double hue = rngBalls.nextDouble();
|
|
||||||
Material material = rngBalls.nextDouble() < 0.8 ?
|
|
||||||
Material.matte(Color.hsb(hue, 0.9, 0.9)).specular(Color.WHITE).shininess(16) :
|
|
||||||
Material.MIRROR;
|
|
||||||
|
|
||||||
solids.add(Ball.cr(Vec3.random(rngBalls).ZOtoMP(), 0.2, uv -> material));
|
|
||||||
}
|
|
||||||
|
|
||||||
solid = Group.of(solids);
|
|
||||||
|
|
||||||
|
|
||||||
RNG rngLights = new RNG(2*seed + 1);
|
|
||||||
|
|
||||||
for (int i = 0; i < nLights; i++) {
|
|
||||||
lights.add(Light.pc(
|
|
||||||
Vec3.random(rngLights).ZOtoMP(),
|
|
||||||
Color.hsb(rngLights.nextDouble(), 0.75, 1))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
package xyz.marsavic.gfxlab.graphics3d.scene;
|
|
||||||
|
|
||||||
import xyz.marsavic.geometry.Vector;
|
|
||||||
import xyz.marsavic.gfxlab.Color;
|
|
||||||
import xyz.marsavic.gfxlab.Vec3;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Light;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Material;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Scene;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Solid;
|
|
||||||
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.textures.Grid;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
|
|
||||||
public class Mirrors extends Scene.Base {
|
|
||||||
|
|
||||||
public Mirrors(int nBalls) {
|
|
||||||
var materialUVWalls = Grid.standard(Color.WHITE);
|
|
||||||
var materialUVWallsL = Grid.standard(Color.hsb(0.00, 0.5, 1.0));
|
|
||||||
var materialUVWallsR = Grid.standard(Color.hsb(0.33, 0.5, 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), materialUVWalls)
|
|
||||||
);
|
|
||||||
|
|
||||||
Collections.addAll(lights,
|
|
||||||
Light.pc(Vec3.xyz(-0.8, 0.8, -0.8), Color.WHITE),
|
|
||||||
Light.pc(Vec3.xyz(-0.8, 0.8, 0.8), Color.WHITE),
|
|
||||||
Light.pc(Vec3.xyz( 0.8, 0.8, -0.8), Color.WHITE),
|
|
||||||
Light.pc(Vec3.xyz( 0.8, 0.8, 0.8), Color.WHITE)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < nBalls; i++) {
|
|
||||||
Vector c = Vector.polar(0.5, 1.0 * i / nBalls);
|
|
||||||
Ball ball = Ball.cr(Vec3.zp(0, c), 0.4, uv -> Material.MIRROR);
|
|
||||||
solids.add(ball);
|
|
||||||
}
|
|
||||||
|
|
||||||
solid = Group.of(solids);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
101
src/xyz/marsavic/gfxlab/graphics3d/scene/Obamaborea.java
Normal file
101
src/xyz/marsavic/gfxlab/graphics3d/scene/Obamaborea.java
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package xyz.marsavic.gfxlab.graphics3d.scene;
|
||||||
|
|
||||||
|
import xyz.marsavic.gfxlab.Color;
|
||||||
|
import xyz.marsavic.gfxlab.Vec3;
|
||||||
|
import xyz.marsavic.gfxlab.graphics3d.Light;
|
||||||
|
import xyz.marsavic.gfxlab.graphics3d.Material;
|
||||||
|
import xyz.marsavic.gfxlab.graphics3d.Scene;
|
||||||
|
import xyz.marsavic.gfxlab.graphics3d.Solid;
|
||||||
|
import xyz.marsavic.gfxlab.graphics3d.solids.Group;
|
||||||
|
import xyz.marsavic.gfxlab.graphics3d.solids.HalfSpace;
|
||||||
|
import xyz.marsavic.gfxlab.graphics3d.solids.Parallelepiped;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class Obamaborea extends Scene.Base {
|
||||||
|
BufferedImage obomba;
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
obomba = ImageIO.read(new File("resources/obomba.jpg"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Couldn't load Obomba, exiting");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Obamaborea(int width, int floors) {
|
||||||
|
double pillarHeight = 5;
|
||||||
|
double pillarSpace = 5;
|
||||||
|
Solid floor = HalfSpace.pn(Vec3.xyz(0, -1, 0), Vec3.xyz(0, 0.1, 0),
|
||||||
|
uv -> Material.diffuseImage(obomba, uv)
|
||||||
|
);
|
||||||
|
Parallelepiped[][][] pillars = new Parallelepiped[floors][width][width];
|
||||||
|
|
||||||
|
for (int i = 0; i < floors; i++) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
for (int k = 0; k < width; k++) {
|
||||||
|
pillars[i][j][k] =
|
||||||
|
Parallelepiped.cxyz(
|
||||||
|
Vec3.xyz((k+0.5-width/2.0)*pillarSpace,
|
||||||
|
(i*1.5)*pillarHeight,
|
||||||
|
(j+0.5-width/2.0)*pillarSpace),
|
||||||
|
1, pillarHeight, 1,
|
||||||
|
uv -> Material.diffuseImage(obomba, uv));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Solid> objects = Arrays.stream(pillars).flatMap(Arrays::stream).flatMap(Arrays::stream)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
objects.add(floor);
|
||||||
|
solid = Group.of(objects);
|
||||||
|
|
||||||
|
// Light[][][] ls = new Light[floors+1][width+1][width+1];
|
||||||
|
//
|
||||||
|
// for (int i = 0; i < floors+1; i++) {
|
||||||
|
// for (int j = 0; j < width+1; j++) {
|
||||||
|
// for (int k = 0; k < width+1; k++) {
|
||||||
|
// ls[i][j][k] = Light.pc(Vec3.xyz(((double) k - width / 2.0) * pillarSpace,
|
||||||
|
// (i + 0.5) * pillarHeight,
|
||||||
|
// ((double) j - width / 2.0) * pillarSpace), Color.gray(10));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Light [] lsFlat = Arrays.stream(ls).flatMap(Arrays::stream).flatMap(Arrays::stream).collect(Collectors.toList()).toArray(new Light[0]);
|
||||||
|
Collections.addAll(lights, Light.pc(Vec3.xyz((-width/2.0) * pillarSpace,
|
||||||
|
0.5*pillarHeight,
|
||||||
|
(-width/2.0) * pillarSpace), Color.gray(30)),
|
||||||
|
Light.pc(Vec3.xyz((width/2.0) * pillarSpace,
|
||||||
|
0.5*pillarHeight,
|
||||||
|
(-width/2.0) * pillarSpace), Color.gray(30)),
|
||||||
|
Light.pc(Vec3.xyz((-width/2.0) * pillarSpace,
|
||||||
|
0.5*pillarHeight,
|
||||||
|
(width/2.0) * pillarSpace), Color.gray(30)),
|
||||||
|
Light.pc(Vec3.xyz((width/2.0) * pillarSpace,
|
||||||
|
0.5*pillarHeight,
|
||||||
|
(width/2.0) * pillarSpace), Color.gray(30)),
|
||||||
|
Light.pc(Vec3.xyz((-width/2.0) * pillarSpace,
|
||||||
|
(width+0.5)*pillarHeight,
|
||||||
|
(-width/2.0) * pillarSpace), Color.gray(30)),
|
||||||
|
Light.pc(Vec3.xyz((width/2.0) * pillarSpace,
|
||||||
|
(width+0.5)*pillarHeight,
|
||||||
|
(-width/2.0) * pillarSpace), Color.gray(30)),
|
||||||
|
Light.pc(Vec3.xyz((-width/2.0) * pillarSpace,
|
||||||
|
(width+0.5)*pillarHeight,
|
||||||
|
(width/2.0) * pillarSpace), Color.gray(30)),
|
||||||
|
Light.pc(Vec3.xyz((width/2.0) * pillarSpace,
|
||||||
|
(width+0.5)*pillarHeight,
|
||||||
|
(width/2.0) * pillarSpace), Color.gray(30))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
package xyz.marsavic.gfxlab.graphics3d.scene;
|
|
||||||
|
|
||||||
|
|
||||||
import xyz.marsavic.gfxlab.Color;
|
|
||||||
import xyz.marsavic.gfxlab.Vec3;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Light;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Material;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Scene;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Solid;
|
|
||||||
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.textures.Grid;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
|
|
||||||
public class RefractionTest extends Scene.Base {
|
|
||||||
|
|
||||||
public RefractionTest() {
|
|
||||||
var materialUVWalls = Grid.standard(Color.WHITE);
|
|
||||||
var materialUVWallsL = Grid.standard(Color.hsb(0.00, 0.5, 1.0));
|
|
||||||
var materialUVWallsR = Grid.standard(Color.hsb(0.33, 0.5, 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), materialUVWalls),
|
|
||||||
|
|
||||||
Ball.cr(Vec3.xyz(-0.3, 0.3, 0.0), 0.4, uv -> Material.GLASS.refractive(Color.hsb(0.7, 0.2, 1.0))),
|
|
||||||
Ball.cr(Vec3.xyz( 0.4, -0.4, 0.0), 0.4, uv -> Material.GLASS),
|
|
||||||
Ball.cr(Vec3.xyz(-0.3, -0.4, -0.6), 0.4, uv -> Material.GLASS.refractiveIndex(2.5)),
|
|
||||||
Ball.cr(Vec3.xyz( 0.4, 0.3, 0.6), 0.4, uv -> Material.GLASS.refractiveIndex(0.6))
|
|
||||||
);
|
|
||||||
|
|
||||||
Collections.addAll(lights,
|
|
||||||
Light.pc(Vec3.xyz(-0.7, 0.7, -0.7), Color.WHITE),
|
|
||||||
Light.pc(Vec3.xyz(-0.7, 0.7, 0.7), Color.WHITE),
|
|
||||||
Light.pc(Vec3.xyz( 0.7, 0.7, -0.7), Color.WHITE),
|
|
||||||
Light.pc(Vec3.xyz( 0.7, 0.7, 0.7), Color.WHITE)
|
|
||||||
);
|
|
||||||
|
|
||||||
solid = Group.of(solids);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -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;
|
||||||
|
@ -9,21 +9,33 @@ import xyz.marsavic.gfxlab.graphics3d.solids.Ball;
|
||||||
import xyz.marsavic.gfxlab.graphics3d.solids.Group;
|
import xyz.marsavic.gfxlab.graphics3d.solids.Group;
|
||||||
import xyz.marsavic.gfxlab.graphics3d.solids.HalfSpace;
|
import xyz.marsavic.gfxlab.graphics3d.solids.HalfSpace;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
|
||||||
public class SceneTest1 extends Scene.Base{
|
public class SceneTest1 extends Scene.Base{
|
||||||
|
BufferedImage obomba;
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
obomba = ImageIO.read(new File("resources/obomba.jpg"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Couldn't load Obomba, exiting");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SceneTest1() {
|
public SceneTest1() {
|
||||||
solid = Group.of(
|
solid = Group.of(
|
||||||
Ball.cr(Vec3.xyz(0, 0, 0), 1,
|
Ball.cr(Vec3.xyz(0, 0, 0), 1,
|
||||||
uv -> Material.matte(Color.hsb(uv.x() * 6, 0.8, uv.y()))
|
uv -> Material.diffuseImage(obomba, uv)
|
||||||
),
|
),
|
||||||
HalfSpace.pn(Vec3.xyz(0, -1, 0), Vec3.xyz(0, 1, 0),
|
HalfSpace.pn(Vec3.xyz(0, -1, 0), Vec3.xyz(0, 1, 0),
|
||||||
uv -> Material.matte(Color.hsb(uv.x(), 0.8, 0.8))
|
uv -> Material.diffuseImage(obomba, uv)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Collections.addAll(lights,
|
Collections.addAll(lights,
|
||||||
Light.pc(Vec3.xyz(-1, 1, -1), Color.hsb(0.0, 1.0, 0.6)),
|
Light.pc(Vec3.xyz(-1, 1, -1), Color.hsb(0.0, 1.0, 0.6)),
|
||||||
Light.pc(Vec3.xyz( 2, 0, 0), Color.gray(0.6)),
|
Light.pc(Vec3.xyz( 2, 0, 0), Color.gray(0.6)),
|
||||||
|
@ -32,4 +44,3 @@ public class SceneTest1 extends Scene.Base{
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
*/
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
107
src/xyz/marsavic/gfxlab/graphics3d/solids/Cylinder.java
Normal file
107
src/xyz/marsavic/gfxlab/graphics3d/solids/Cylinder.java
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
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;
|
||||||
|
import xyz.marsavic.utils.Numeric;
|
||||||
|
|
||||||
|
public class Cylinder implements Solid {
|
||||||
|
|
||||||
|
private final Vec3 p;
|
||||||
|
private final double r;
|
||||||
|
private final Vec3 d; // directional vector, for a finite cylinder it also represents the height
|
||||||
|
private final F1<Material, Vector> mapMaterial;
|
||||||
|
|
||||||
|
// transient
|
||||||
|
private final double rSqr;
|
||||||
|
private final boolean finite;
|
||||||
|
|
||||||
|
|
||||||
|
private Cylinder(Vec3 p, double r, Vec3 d, F1<Material, Vector> mapMaterial, boolean finite) {
|
||||||
|
this.p = p;
|
||||||
|
this.r = r;
|
||||||
|
this.d = d;
|
||||||
|
rSqr = r * r;
|
||||||
|
this.mapMaterial = mapMaterial;
|
||||||
|
this.finite = finite;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Cylinder prdi(Vec3 p, double r, Vec3 d, F1<Material, Vector> mapMaterial) {
|
||||||
|
return new Cylinder(p, r, d, mapMaterial, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cylinder prd(Vec3 p, double r, Vec3 d, F1<Material, Vector> mapMaterial) {
|
||||||
|
return new Cylinder(p, r, d, mapMaterial, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cylinder crd(Vec3 c, double r, Vec3 d, F1<Material, Vector> mapMaterial) {
|
||||||
|
return new Cylinder(c.sub(d.div(2)), r, d, mapMaterial, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 c() {
|
||||||
|
return p.add(d.div(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 p() { return p; }
|
||||||
|
public double r() {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
public Vec3 d() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cylinder.HitCylinder firstHit(Ray ray, double afterTime) {
|
||||||
|
Vec3 e = c().sub(ray.p()); // Vector from the ray origin to the Cylinder start point
|
||||||
|
|
||||||
|
double dSqr = ray.d().lengthSquared();
|
||||||
|
double l = e.dot(ray.d()) / dSqr;
|
||||||
|
double mSqr = l * l - (e.lengthSquared() - rSqr) / dSqr;
|
||||||
|
|
||||||
|
if (mSqr > 0) {
|
||||||
|
double m = Math.sqrt(mSqr);
|
||||||
|
if (l - m > afterTime) return new Cylinder.HitCylinder(ray, l - m);
|
||||||
|
if (l + m > afterTime) return new Cylinder.HitCylinder(ray, l + m);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class HitCylinder extends Hit.RayT {
|
||||||
|
|
||||||
|
protected HitCylinder(Ray ray, double t) {
|
||||||
|
super(ray, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec3 n() {
|
||||||
|
return ray().at(t()).sub(c());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material material() {
|
||||||
|
return Cylinder.this.mapMaterial.at(uv());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector uv() {
|
||||||
|
Vec3 n = n();
|
||||||
|
return Vector.xy(
|
||||||
|
Numeric.atan2T(n.z(), n.x()),
|
||||||
|
-2 * Numeric.asinT(n.y() / r) + 0.5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec3 n_() {
|
||||||
|
return n().div(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,15 +39,4 @@ public class Group implements Solid {
|
||||||
|
|
||||||
return minHit;
|
return minHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hitBetween(Ray ray, double afterTime, double beforeTime) {
|
|
||||||
for (Solid s : solids) {
|
|
||||||
Hit hit = s.firstHit(ray, afterTime);
|
|
||||||
if ((hit != null) && (hit.t() < beforeTime)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,15 @@ import xyz.marsavic.gfxlab.graphics3d.Solid;
|
||||||
public class Parallelepiped implements Solid {
|
public class Parallelepiped implements Solid {
|
||||||
|
|
||||||
private final Vec3 p; // starting vertex
|
private final Vec3 p; // starting vertex
|
||||||
|
|
||||||
private final Vec3[][][] vertices;
|
private final Vec3[][][] vertices;
|
||||||
HalfSpace [] sides;
|
HalfSpace [] sides;
|
||||||
|
private final F1<Material, Vector> mapMaterial;
|
||||||
|
|
||||||
private final Vec3 a, b, c;
|
private final Vec3 a, b, c;
|
||||||
|
|
||||||
private Parallelepiped(Vec3 point, Vec3 aEdge, Vec3 bEdge, Vec3 cEdge, F1<Material, Vector> mapMaterial) {
|
private Parallelepiped(Vec3 point, Vec3 aEdge, Vec3 bEdge, Vec3 cEdge, F1<Material, Vector> mapMaterial) {
|
||||||
|
this.mapMaterial = mapMaterial;
|
||||||
|
|
||||||
this.p = point;
|
this.p = point;
|
||||||
this.a = aEdge;
|
this.a = aEdge;
|
||||||
this.b = bEdge;
|
this.b = bEdge;
|
||||||
|
@ -25,7 +27,7 @@ public class Parallelepiped implements Solid {
|
||||||
|
|
||||||
vertices = new Vec3[][][]
|
vertices = new Vec3[][][]
|
||||||
{{{p, p.add(c)}, {p.add(b), p.add(b).add(c)}},
|
{{{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)}}};
|
{{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 = new HalfSpace[6];
|
||||||
sides[0] = HalfSpace.pef(p, b, a, mapMaterial);
|
sides[0] = HalfSpace.pef(p, b, a, mapMaterial);
|
||||||
sides[1] = HalfSpace.pef(p.add(c), a, b, mapMaterial);
|
sides[1] = HalfSpace.pef(p.add(c), a, b, mapMaterial);
|
||||||
|
@ -40,10 +42,29 @@ public class Parallelepiped implements Solid {
|
||||||
return new Parallelepiped(p, a, b, c, mapMaterial);
|
return new Parallelepiped(p, a, b, c, mapMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Parallelepiped cabc(Vec3 center, Vec3 a, Vec3 b, Vec3 c, F1<Material, Vector> mapMaterial) {
|
||||||
|
return new Parallelepiped(center.sub(a.div(2)).sub(b.div(2)).sub(c.div(2)),
|
||||||
|
a, b, c, mapMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parallelepiped pxyz(Vec3 p, double x, double y, double z, F1<Material, Vector> mapMaterial) {
|
||||||
|
return new Parallelepiped(p,
|
||||||
|
Vec3.xyz(x, 0, 0), Vec3.xyz(0, y, 0), Vec3.xyz(0, 0, z),
|
||||||
|
mapMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parallelepiped cxyz(Vec3 center, double x, double y, double z, F1<Material, Vector> mapMaterial) {
|
||||||
|
return new Parallelepiped(center.sub(Vec3.xyz(x/2, y/2, z/2)),
|
||||||
|
Vec3.xyz(x, 0, 0), Vec3.xyz(0, y, 0), Vec3.xyz(0, 0, z),
|
||||||
|
mapMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
public Vec3 p() {
|
public Vec3 p() {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vec3 center() { return p.add(a.div(2)).add(b.div(2)).add(c.div(2)); }
|
||||||
|
|
||||||
public Vec3 a() {
|
public Vec3 a() {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
package xyz.marsavic.gfxlab.graphics3d.textures;
|
|
||||||
|
|
||||||
|
|
||||||
import xyz.marsavic.functions.interfaces.F1;
|
|
||||||
import xyz.marsavic.geometry.Vector;
|
|
||||||
import xyz.marsavic.gfxlab.Color;
|
|
||||||
import xyz.marsavic.gfxlab.Spectrum;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Material;
|
|
||||||
|
|
||||||
|
|
||||||
public class Grid implements F1<Material, Vector> {
|
|
||||||
|
|
||||||
private final Vector size, sizeLine;
|
|
||||||
private final Material material, materialLine;
|
|
||||||
|
|
||||||
// transient
|
|
||||||
private final Vector sizeLineHalf;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public Grid(Vector size, Vector sizeLine, Material material, Material materialLine) {
|
|
||||||
this.size = size;
|
|
||||||
this.sizeLine = sizeLine;
|
|
||||||
this.material = material;
|
|
||||||
this.materialLine = materialLine;
|
|
||||||
sizeLineHalf = sizeLine.div(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material at(Vector uv) {
|
|
||||||
Vector p = uv.add(sizeLineHalf).mod(size);
|
|
||||||
return (p.x() < sizeLine.x()) || (p.y() < sizeLine.y()) ? materialLine : material;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Grid standard(Spectrum spectrum) {
|
|
||||||
return new Grid(
|
|
||||||
Vector.xy(0.25, 0.25),
|
|
||||||
Vector.xy(0.01, 0.01),
|
|
||||||
Material.matte(spectrum),
|
|
||||||
Material.matte(w -> spectrum.at(w) * 0.75)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Grid standardUnit(Spectrum spectrum) {
|
|
||||||
return new Grid(
|
|
||||||
Vector.UNIT_DIAGONAL,
|
|
||||||
Vector.xy(1.0/64),
|
|
||||||
Material.matte(spectrum),
|
|
||||||
Material.matte(w -> spectrum.at(w) * 0.75)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,15 +4,12 @@ import xyz.marsavic.functions.interfaces.A2;
|
||||||
import xyz.marsavic.functions.interfaces.F1;
|
import xyz.marsavic.functions.interfaces.F1;
|
||||||
import xyz.marsavic.gfxlab.*;
|
import xyz.marsavic.gfxlab.*;
|
||||||
import xyz.marsavic.gfxlab.elements.Output;
|
import xyz.marsavic.gfxlab.elements.Output;
|
||||||
import xyz.marsavic.gfxlab.graphics3d.Affine;
|
|
||||||
import xyz.marsavic.gfxlab.graphics3d.cameras.Perspective;
|
|
||||||
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.Obamaborea;
|
||||||
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;
|
||||||
import xyz.marsavic.gfxlab.tonemapping.matrixcolor_to_colortransforms.AutoSoft;
|
import xyz.marsavic.gfxlab.tonemapping.colortransforms.Multiply;
|
||||||
|
|
||||||
import static xyz.marsavic.gfxlab.elements.ElementF.e;
|
import static xyz.marsavic.gfxlab.elements.ElementF.e;
|
||||||
import static xyz.marsavic.gfxlab.elements.Output.val;
|
import static xyz.marsavic.gfxlab.elements.Output.val;
|
||||||
|
@ -33,32 +30,22 @@ public class GfxLab {
|
||||||
e(Fs::transformedColorFunction,
|
e(Fs::transformedColorFunction,
|
||||||
// e(Blobs::new, val(5), val(0.1), val(0.2)),
|
// e(Blobs::new, val(5), val(0.1), val(0.2)),
|
||||||
e(RayTracerSimple::new,
|
e(RayTracerSimple::new,
|
||||||
// e(RefractionTest::new),
|
e(Obamaborea::new, val(3), val(3))
|
||||||
// e(DiscoRoom::new, val(16), val(16), val(0x3361EB272FEA4C62L)),
|
|
||||||
e(SpectrumTest::new),
|
|
||||||
// e(Mirrors::new, val(3)),
|
|
||||||
e(TransformedCamera::new,
|
|
||||||
e(Perspective::new, val(1.0/3)),
|
|
||||||
// e(Orthographic::new),
|
|
||||||
e(Affine.IDENTITY
|
|
||||||
.then(Affine.translation(Vec3.xyz(0, 0, -4)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
e(TransformationsFromSize.toGeometric, eSize)
|
e(TransformationsFromSize.toGeometric, eSize)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
e(Fs::toneMapping,
|
e(Fs::toneMapping,
|
||||||
// e(ColorTransform::asColorTransformFromMatrixColor,
|
e(ColorTransform::asColorTransformFromMatrixColor,
|
||||||
// e(Multiply::new, val(0.05))
|
e(Multiply::new, val(1.0))
|
||||||
// )
|
)
|
||||||
e(AutoSoft::new, e(0x1p-5), e(1.0))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
outRenderer = eRenderer.out();
|
outRenderer = eRenderer.out();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,6 +76,5 @@ class Fs {
|
||||||
output.fill(p -> f.at(input.get(p)).codeClamp());
|
output.fill(p -> f.at(input.get(p)).codeClamp());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
package xyz.marsavic.gfxlab.tonemapping.matrixcolor_to_colortransforms;
|
|
||||||
|
|
||||||
import xyz.marsavic.functions.interfaces.F1;
|
|
||||||
import xyz.marsavic.geometry.Vector;
|
|
||||||
import xyz.marsavic.gfxlab.Color;
|
|
||||||
import xyz.marsavic.gfxlab.Matrix;
|
|
||||||
import xyz.marsavic.gfxlab.gui.UtilsGL;
|
|
||||||
import xyz.marsavic.gfxlab.tonemapping.ColorTransform;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
public class AutoSoft implements F1<ColorTransform, Matrix<Color>> {
|
|
||||||
|
|
||||||
private final double preFactor;
|
|
||||||
private final double power;
|
|
||||||
private final double postFactor = 1.0;
|
|
||||||
private final boolean autoPostFactor = true;
|
|
||||||
|
|
||||||
|
|
||||||
public AutoSoft(double preFactor, double power) {
|
|
||||||
this.preFactor = preFactor;
|
|
||||||
this.power = power;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private double lFactor(double lSrc) {
|
|
||||||
double lPre = lSrc * preFactor;
|
|
||||||
double lDst = 1 - 1 / (1 + Math.pow(lPre, power));
|
|
||||||
|
|
||||||
double f = lDst / lSrc;
|
|
||||||
if (Double.isNaN(f)) {
|
|
||||||
f = 0;
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ColorTransform at(Matrix<Color> colorMatrix) {
|
|
||||||
Vector size = colorMatrix.size();
|
|
||||||
|
|
||||||
double postFactor_;
|
|
||||||
|
|
||||||
if (autoPostFactor) {
|
|
||||||
double[] maxY = new double[size.xInt()];
|
|
||||||
|
|
||||||
UtilsGL.parallelY(size, y -> {
|
|
||||||
maxY[y] = Double.NEGATIVE_INFINITY;
|
|
||||||
for (int x = 0; x < size.xInt(); x++) {
|
|
||||||
Color c = colorMatrix.get(x, y);
|
|
||||||
Color result = c.mul(lFactor(c.luminance()));
|
|
||||||
maxY[y] = Math.max(maxY[y], result.max());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO Replace with fork-join task.
|
|
||||||
|
|
||||||
double max = Double.NEGATIVE_INFINITY;
|
|
||||||
for (int y = 0; y < size.yInt(); y++) {
|
|
||||||
max = Math.max(max, maxY[y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
postFactor_ = 1 / max;
|
|
||||||
} else {
|
|
||||||
postFactor_ = postFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return color -> color.mul(lFactor(color.luminance()) * postFactor_);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue