Shadows, Reflections, Camera, Grid, AutoSoft, ...
This commit is contained in:
parent
c3d9698ede
commit
98320a6901
|
@ -9,6 +9,7 @@
|
|||
- 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.
|
||||
- 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
|
||||
|
|
8
src/xyz/marsavic/gfxlab/graphics3d/Camera.java
Normal file
8
src/xyz/marsavic/gfxlab/graphics3d/Camera.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package xyz.marsavic.gfxlab.graphics3d;
|
||||
|
||||
import xyz.marsavic.geometry.Vector;
|
||||
|
||||
|
||||
public interface Camera {
|
||||
Ray exitingRay(Vector sensorPosition);
|
||||
}
|
|
@ -2,8 +2,6 @@ package xyz.marsavic.gfxlab.graphics3d;
|
|||
|
||||
|
||||
import xyz.marsavic.gfxlab.Vec3;
|
||||
import xyz.marsavic.random.sampling.Sampler;
|
||||
import xyz.marsavic.utils.Numeric;
|
||||
|
||||
public class GeometryUtils {
|
||||
|
||||
|
@ -26,4 +24,12 @@ 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,14 +3,28 @@ package xyz.marsavic.gfxlab.graphics3d;
|
|||
import xyz.marsavic.gfxlab.Color;
|
||||
|
||||
public record Material(
|
||||
Color diffuse
|
||||
) {
|
||||
public Material diffuse(Color diffuse) { return new Material(diffuse); }
|
||||
Color diffuse,
|
||||
Color specular,
|
||||
double shininess,
|
||||
Color reflective,
|
||||
Color refractive,
|
||||
double refractiveIndex
|
||||
|
||||
public static final Material BLACK = new Material(Color.BLACK);
|
||||
) {
|
||||
public Material diffuse (Color diffuse ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
|
||||
public Material specular (Color specular ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
|
||||
public Material shininess (double shininess ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
|
||||
public Material reflective (Color reflective ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
|
||||
public Material refractive (Color refractive ) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
|
||||
public Material refractiveIndex(double refractiveIndex) { return new Material(diffuse, specular, shininess, reflective, refractive, refractiveIndex); }
|
||||
|
||||
public static final Material BLACK = new Material(Color.BLACK, Color.BLACK, 32, Color.BLACK, Color.BLACK, 1.5);
|
||||
|
||||
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 MIRROR = BLACK.reflective(Color.WHITE);
|
||||
public static final Material GLASS = BLACK.refractive(Color.WHITE).refractiveIndex(1.5);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package xyz.marsavic.gfxlab.graphics3d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface Solid {
|
||||
|
||||
|
@ -19,4 +16,12 @@ public interface Solid {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
23
src/xyz/marsavic/gfxlab/graphics3d/cameras/Perspective.java
Normal file
23
src/xyz/marsavic/gfxlab/graphics3d/cameras/Perspective.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
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.gfxlab.Color;
|
||||
import xyz.marsavic.gfxlab.ColorFunctionT;
|
||||
import xyz.marsavic.gfxlab.Vec3;
|
||||
import xyz.marsavic.gfxlab.graphics3d.Camera;
|
||||
import xyz.marsavic.gfxlab.graphics3d.Ray;
|
||||
import xyz.marsavic.gfxlab.graphics3d.Scene;
|
||||
|
||||
|
@ -11,10 +11,12 @@ import xyz.marsavic.gfxlab.graphics3d.Scene;
|
|||
public abstract class RayTracer implements ColorFunctionT {
|
||||
|
||||
protected final Scene scene;
|
||||
protected final Camera camera;
|
||||
|
||||
|
||||
public RayTracer(Scene scene) {
|
||||
public RayTracer(Scene scene, Camera camera) {
|
||||
this.scene = scene;
|
||||
this.camera = camera;
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +24,7 @@ public abstract class RayTracer implements ColorFunctionT {
|
|||
|
||||
@Override
|
||||
public Color at(double t, Vector p) {
|
||||
Ray ray = Ray.pd(Vec3.xyz(0, 0, -2.6), Vec3.zp(1.6, p));
|
||||
Ray ray = camera.exitingRay(p);
|
||||
return sample(ray);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,38 +7,75 @@ import xyz.marsavic.gfxlab.graphics3d.*;
|
|||
|
||||
public class RayTracerSimple extends RayTracer {
|
||||
|
||||
public RayTracerSimple(Scene scene) {
|
||||
super(scene);
|
||||
private static final double EPSILON = 1e-9;
|
||||
|
||||
public RayTracerSimple(Scene scene, Camera camera) {
|
||||
super(scene, camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color sample(Ray r) {
|
||||
Hit hit = scene.solid().firstHit(r);
|
||||
protected Color sample(Ray ray) {
|
||||
return sample(ray, 64);
|
||||
}
|
||||
|
||||
protected Color sample(Ray ray, int depthRemaining) {
|
||||
if (depthRemaining == 0) {
|
||||
return Color.BLACK;
|
||||
}
|
||||
|
||||
Hit hit = scene.solid().firstHit(ray, EPSILON);
|
||||
if (hit == null) {
|
||||
return scene.colorBackground();
|
||||
}
|
||||
|
||||
Vec3 p = r.at(hit.t()); // The hit point
|
||||
Vec3 n_ = hit.n_(); // Normalized normal to the body surface at 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 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)
|
||||
|
||||
Color lightDiffuse = Color.BLACK; // The sum of diffuse contributions from all the lights
|
||||
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();
|
||||
|
||||
for (Light light : scene.lights()) {
|
||||
Vec3 l = light.p().sub(p); // Vector from p to the light;
|
||||
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_
|
||||
Vec3 l = light.p().sub(p); // Vector from p to the light;
|
||||
|
||||
if (cosLN > 0) { // If the light is above the surface
|
||||
Ray rayToLight = Ray.pd(p, l);
|
||||
if (scene.solid().hitBetween(rayToLight, EPSILON, 1)) continue;
|
||||
|
||||
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);
|
||||
|
||||
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())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hit.material().diffuse().mul(lightDiffuse);
|
||||
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));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
58
src/xyz/marsavic/gfxlab/graphics3d/scene/DiscoRoom.java
Normal file
58
src/xyz/marsavic/gfxlab/graphics3d/scene/DiscoRoom.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
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))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
52
src/xyz/marsavic/gfxlab/graphics3d/scene/Mirrors.java
Normal file
52
src/xyz/marsavic/gfxlab/graphics3d/scene/Mirrors.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
50
src/xyz/marsavic/gfxlab/graphics3d/scene/RefractionTest.java
Normal file
50
src/xyz/marsavic/gfxlab/graphics3d/scene/RefractionTest.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -17,10 +17,10 @@ public class SceneTest1 extends Scene.Base{
|
|||
public SceneTest1() {
|
||||
solid = Group.of(
|
||||
Ball.cr(Vec3.xyz(0, 0, 0), 1,
|
||||
uv -> new Material(Color.hsb(uv.x() * 6, 0.8, uv.y()))
|
||||
uv -> Material.matte(Color.hsb(uv.x() * 6, 0.8, uv.y()))
|
||||
),
|
||||
HalfSpace.pn(Vec3.xyz(0, -1, 0), Vec3.xyz(0, 1, 0),
|
||||
uv -> new Material(Color.hsb(uv.x(), 0.8, 0.8))
|
||||
uv -> Material.matte(Color.hsb(uv.x(), 0.8, 0.8))
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -39,4 +39,15 @@ public class Group implements Solid {
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
54
src/xyz/marsavic/gfxlab/graphics3d/textures/Grid.java
Normal file
54
src/xyz/marsavic/gfxlab/graphics3d/textures/Grid.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
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.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(Color color) {
|
||||
return new Grid(
|
||||
Vector.xy(0.25, 0.25),
|
||||
Vector.xy(0.01, 0.01),
|
||||
Material.matte(color),
|
||||
Material.matte(color.mul(0.75))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static Grid standardUnit(Color color) {
|
||||
return new Grid(
|
||||
Vector.UNIT_DIAGONAL,
|
||||
Vector.xy(1.0/64),
|
||||
Material.matte(color),
|
||||
Material.matte(color.mul(0.75))
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,12 +4,15 @@ import xyz.marsavic.functions.interfaces.A2;
|
|||
import xyz.marsavic.functions.interfaces.F1;
|
||||
import xyz.marsavic.gfxlab.*;
|
||||
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.scene.SceneTest1;
|
||||
import xyz.marsavic.gfxlab.graphics3d.scene.DiscoRoom;
|
||||
import xyz.marsavic.gfxlab.gui.UtilsGL;
|
||||
import xyz.marsavic.gfxlab.tonemapping.ColorTransform;
|
||||
import xyz.marsavic.gfxlab.tonemapping.ToneMapping;
|
||||
import xyz.marsavic.gfxlab.tonemapping.colortransforms.Multiply;
|
||||
import xyz.marsavic.gfxlab.tonemapping.matrixcolor_to_colortransforms.AutoSoft;
|
||||
|
||||
import static xyz.marsavic.gfxlab.elements.ElementF.e;
|
||||
import static xyz.marsavic.gfxlab.elements.Output.val;
|
||||
|
@ -30,22 +33,31 @@ public class GfxLab {
|
|||
e(Fs::transformedColorFunction,
|
||||
// e(Blobs::new, val(5), val(0.1), val(0.2)),
|
||||
e(RayTracerSimple::new,
|
||||
e(SceneTest1::new)
|
||||
// e(RefractionTest::new),
|
||||
e(DiscoRoom::new, val(16), val(16), val(0x3361EB272FEA4C62L)),
|
||||
// e(Mirrors::new, val(3)),
|
||||
e(TransformedCamera::new,
|
||||
e(Perspective::new, val(1.0/3)),
|
||||
e(Affine.IDENTITY
|
||||
.then(Affine.translation(Vec3.xyz(0, 0, -4)))
|
||||
// .then(Affine.rotationAboutY(0.03))
|
||||
)
|
||||
)
|
||||
),
|
||||
e(TransformationsFromSize.toGeometric, eSize)
|
||||
)
|
||||
),
|
||||
e(Fs::toneMapping,
|
||||
e(ColorTransform::asColorTransformFromMatrixColor,
|
||||
e(Multiply::new, val(1.0))
|
||||
)
|
||||
// e(ColorTransform::asColorTransformFromMatrixColor,
|
||||
// e(Multiply::new, val(0.05))
|
||||
// )
|
||||
e(AutoSoft::new, e(0x1p-5), e(1.0))
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
outRenderer = eRenderer.out();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,4 +89,5 @@ class Fs {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
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