From 5e56c197f244e52fa9ad3958d8cfa4cec201d43f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marko=20Savi=C4=87?=
<4282607+marsavic@users.noreply.github.com>
Date: Mon, 21 Nov 2022 23:51:12 +0100
Subject: [PATCH] HalfSpace, Group, Material, uv mapping, Light, Scene, diffuse
lighting
---
.idea/scopes/Raytracing.xml | 3 ++
.idea/vcs.xml | 6 +++
src/xyz/marsavic/gfxlab/graphics3d/Hit.java | 10 ++++-
src/xyz/marsavic/gfxlab/graphics3d/Light.java | 20 +++++++++
.../marsavic/gfxlab/graphics3d/Material.java | 16 +++++++
src/xyz/marsavic/gfxlab/graphics3d/Scene.java | 44 +++++++++++++++++++
.../graphics3d/raytracers/RayTracer.java | 29 ++++++++++++
.../raytracers/RayTracerSimple.java | 44 +++++++++++++++++++
.../graphics3d/raytracers/RayTracingTest.java | 30 -------------
.../gfxlab/graphics3d/scene/SceneTest1.java | 34 ++++++++++++++
.../gfxlab/graphics3d/solids/Ball.java | 25 +++++++++--
.../gfxlab/graphics3d/solids/Group.java | 42 ++++++++++++++++++
.../gfxlab/graphics3d/solids/HalfSpace.java | 42 +++++++++++++-----
src/xyz/marsavic/gfxlab/gui/UtilsGL.java | 17 ++++---
.../marsavic/gfxlab/playground/GfxLab.java | 13 +++---
15 files changed, 314 insertions(+), 61 deletions(-)
create mode 100644 .idea/scopes/Raytracing.xml
create mode 100644 .idea/vcs.xml
create mode 100644 src/xyz/marsavic/gfxlab/graphics3d/Light.java
create mode 100644 src/xyz/marsavic/gfxlab/graphics3d/Material.java
create mode 100644 src/xyz/marsavic/gfxlab/graphics3d/Scene.java
create mode 100644 src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java
create mode 100644 src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracerSimple.java
delete mode 100644 src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java
create mode 100644 src/xyz/marsavic/gfxlab/graphics3d/scene/SceneTest1.java
create mode 100644 src/xyz/marsavic/gfxlab/graphics3d/solids/Group.java
diff --git a/.idea/scopes/Raytracing.xml b/.idea/scopes/Raytracing.xml
new file mode 100644
index 0000000..614dd5d
--- /dev/null
+++ b/.idea/scopes/Raytracing.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/Hit.java b/src/xyz/marsavic/gfxlab/graphics3d/Hit.java
index c46ab54..ad35754 100644
--- a/src/xyz/marsavic/gfxlab/graphics3d/Hit.java
+++ b/src/xyz/marsavic/gfxlab/graphics3d/Hit.java
@@ -7,12 +7,18 @@ import xyz.marsavic.gfxlab.Vec3;
/** Interaction of a ray with a solid.*/
public interface Hit {
- /** The time of the hit */
+ /** The time of the hit. */
double t();
- /** The normal at the point of the hit */
+ /** The normal at the hit point. */
Vec3 n();
+ /** Surface material at the hit point. */
+ Material material();
+
+ /** 2D coordinates in the internal coordinate system of the surface. */
+ Vector uv();
+
/** The normalized normal at the point of the hit */
default Vec3 n_() {
return n().normalized_();
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/Light.java b/src/xyz/marsavic/gfxlab/graphics3d/Light.java
new file mode 100644
index 0000000..ee5d95d
--- /dev/null
+++ b/src/xyz/marsavic/gfxlab/graphics3d/Light.java
@@ -0,0 +1,20 @@
+package xyz.marsavic.gfxlab.graphics3d;
+
+import xyz.marsavic.gfxlab.Color;
+import xyz.marsavic.gfxlab.Vec3;
+
+/** Point light. */
+public record Light(
+ Vec3 p,
+ Color c
+) {
+
+ public static Light pc(Vec3 p, Color c) {
+ return new Light(p, c);
+ }
+
+ public static Light p(Vec3 p) {
+ return pc(p, Color.WHITE);
+ }
+
+}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/Material.java b/src/xyz/marsavic/gfxlab/graphics3d/Material.java
new file mode 100644
index 0000000..ed3adb1
--- /dev/null
+++ b/src/xyz/marsavic/gfxlab/graphics3d/Material.java
@@ -0,0 +1,16 @@
+package xyz.marsavic.gfxlab.graphics3d;
+
+import xyz.marsavic.gfxlab.Color;
+
+public record Material(
+ Color diffuse
+) {
+ public Material diffuse(Color diffuse) { return new Material(diffuse); }
+
+ public static final Material BLACK = new Material(Color.BLACK);
+
+ 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();
+}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/Scene.java b/src/xyz/marsavic/gfxlab/graphics3d/Scene.java
new file mode 100644
index 0000000..154b7e6
--- /dev/null
+++ b/src/xyz/marsavic/gfxlab/graphics3d/Scene.java
@@ -0,0 +1,44 @@
+package xyz.marsavic.gfxlab.graphics3d;
+
+import xyz.marsavic.gfxlab.Color;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public interface Scene {
+ Solid solid();
+
+ Collection lights();
+
+ default Color colorBackground() {
+ return Color.BLACK;
+ }
+
+
+ class Base implements Scene {
+
+ protected Solid solid;
+ protected final List lights = new ArrayList<>();
+ protected final Color colorBackground = Color.BLACK;
+
+ @Override
+ public Solid solid() {
+ return solid;
+ }
+
+ @Override
+ public Collection lights() {
+ return lights;
+ }
+
+ @Override
+ public Color colorBackground() {
+ return colorBackground;
+ }
+
+ }
+
+
+}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java
new file mode 100644
index 0000000..d853a83
--- /dev/null
+++ b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java
@@ -0,0 +1,29 @@
+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.Ray;
+import xyz.marsavic.gfxlab.graphics3d.Scene;
+
+
+public abstract class RayTracer implements ColorFunctionT {
+
+ protected final Scene scene;
+
+
+ public RayTracer(Scene scene) {
+ this.scene = scene;
+ }
+
+
+ protected abstract Color sample(Ray r);
+
+ @Override
+ public Color at(double t, Vector p) {
+ Ray ray = Ray.pd(Vec3.xyz(0, 0, -2.6), Vec3.zp(1.6, p));
+ return sample(ray);
+ }
+
+}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracerSimple.java b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracerSimple.java
new file mode 100644
index 0000000..9e65de6
--- /dev/null
+++ b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracerSimple.java
@@ -0,0 +1,44 @@
+package xyz.marsavic.gfxlab.graphics3d.raytracers;
+
+import xyz.marsavic.gfxlab.Color;
+import xyz.marsavic.gfxlab.Vec3;
+import xyz.marsavic.gfxlab.graphics3d.*;
+
+
+public class RayTracerSimple extends RayTracer {
+
+ public RayTracerSimple(Scene scene) {
+ super(scene);
+ }
+
+ @Override
+ protected Color sample(Ray r) {
+ Hit hit = scene.solid().firstHit(r);
+ 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
+
+ Color lightDiffuse = Color.BLACK; // The sum of diffuse contributions from all the lights
+
+ 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_
+
+ 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);
+ }
+ }
+
+ return hit.material().diffuse().mul(lightDiffuse);
+ }
+
+}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java
deleted file mode 100644
index ede21f2..0000000
--- a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-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.Hit;
-import xyz.marsavic.gfxlab.graphics3d.Ray;
-import xyz.marsavic.gfxlab.graphics3d.solids.Ball;
-import xyz.marsavic.gfxlab.graphics3d.solids.HalfSpace;
-
-
-public class RayTracingTest implements ColorFunctionT {
-
- Ball ball = Ball.cr(Vec3.xyz(0, 0, 2), 1);
- HalfSpace halfSpace = HalfSpace.pn(Vec3.xyz(0, -1, 0), Vec3.xyz(0, 1, 0));
-
- @Override
- public Color at(double t, Vector p) {
- Ray ray = Ray.pq(Vec3.ZERO, Vec3.zp(1, p));
-
- Hit hit1 = ball.firstHit(ray);
- Hit hit2 = halfSpace.firstHit(ray);
-
- double tMin = Math.min(Hit.t(hit1), Hit.t(hit2));
-
- return Color.gray(1.0 / (1.0 + tMin));
- }
-
-}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/scene/SceneTest1.java b/src/xyz/marsavic/gfxlab/graphics3d/scene/SceneTest1.java
new file mode 100644
index 0000000..deb6e3c
--- /dev/null
+++ b/src/xyz/marsavic/gfxlab/graphics3d/scene/SceneTest1.java
@@ -0,0 +1,34 @@
+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.solids.Ball;
+import xyz.marsavic.gfxlab.graphics3d.solids.Group;
+import xyz.marsavic.gfxlab.graphics3d.solids.HalfSpace;
+
+import java.util.Collections;
+
+
+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()))
+ ),
+ HalfSpace.pn(Vec3.xyz(0, -1, 0), Vec3.xyz(0, 1, 0),
+ uv -> new Material(Color.hsb(uv.x(), 0.8, 0.8))
+ )
+ );
+
+ Collections.addAll(lights,
+ 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( 0, 0, -2), Color.gray(0.1))
+ );
+ }
+
+}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/solids/Ball.java b/src/xyz/marsavic/gfxlab/graphics3d/solids/Ball.java
index 789588b..408b5ac 100644
--- a/src/xyz/marsavic/gfxlab/graphics3d/solids/Ball.java
+++ b/src/xyz/marsavic/gfxlab/graphics3d/solids/Ball.java
@@ -1,8 +1,10 @@
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;
@@ -12,21 +14,22 @@ public class Ball implements Solid {
private final Vec3 c;
private final double r;
+ private final F1 mapMaterial;
// transient
private final double rSqr;
-
- private Ball(Vec3 c, double r) {
+ private Ball(Vec3 c, double r, F1 mapMaterial) {
this.c = c;
this.r = r;
rSqr = r * r;
+ this.mapMaterial = mapMaterial;
}
- public static Ball cr(Vec3 c, double r) {
- return new Ball(c, r);
+ public static Ball cr(Vec3 c, double r, F1 mapMaterial) {
+ return new Ball(c, r, mapMaterial);
}
@@ -69,6 +72,20 @@ public class Ball implements Solid {
return ray().at(t()).sub(c());
}
+ @Override
+ public Material material() {
+ return Ball.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);
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/solids/Group.java b/src/xyz/marsavic/gfxlab/graphics3d/solids/Group.java
new file mode 100644
index 0000000..72361db
--- /dev/null
+++ b/src/xyz/marsavic/gfxlab/graphics3d/solids/Group.java
@@ -0,0 +1,42 @@
+package xyz.marsavic.gfxlab.graphics3d.solids;
+
+import xyz.marsavic.gfxlab.graphics3d.Hit;
+import xyz.marsavic.gfxlab.graphics3d.Ray;
+import xyz.marsavic.gfxlab.graphics3d.Solid;
+
+import java.util.Collection;
+
+public class Group implements Solid {
+
+ private final Solid[] solids;
+
+
+ private Group(Solid... solids) {
+ this.solids = solids.clone();
+ }
+
+ public static Group of(Solid... solids) {
+ return new Group(solids);
+ }
+
+ public static Group of(Collection solids) {
+ return new Group(solids.toArray(Solid[]::new));
+ }
+
+ @Override
+ public Hit firstHit(Ray ray, double afterTime) {
+ double minT = Double.POSITIVE_INFINITY;
+ Hit minHit = null;
+
+ for (Solid s : solids) {
+ Hit hit = s.firstHit(ray, afterTime);
+ double t = Hit.t(hit);
+ if (t < minT) {
+ minT = t;
+ minHit = hit;
+ }
+ }
+
+ return minHit;
+ }
+}
diff --git a/src/xyz/marsavic/gfxlab/graphics3d/solids/HalfSpace.java b/src/xyz/marsavic/gfxlab/graphics3d/solids/HalfSpace.java
index 1c18214..e5e0d4a 100644
--- a/src/xyz/marsavic/gfxlab/graphics3d/solids/HalfSpace.java
+++ b/src/xyz/marsavic/gfxlab/graphics3d/solids/HalfSpace.java
@@ -1,10 +1,9 @@
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.GeometryUtils;
-import xyz.marsavic.gfxlab.graphics3d.Hit;
-import xyz.marsavic.gfxlab.graphics3d.Ray;
-import xyz.marsavic.gfxlab.graphics3d.Solid;
+import xyz.marsavic.gfxlab.graphics3d.*;
public class HalfSpace implements Solid {
@@ -12,6 +11,7 @@ public class HalfSpace implements Solid {
private final Vec3 p; // A point on the boundary plane
private final Vec3 e; // A vector parallel to the boundary plane.
private final Vec3 f; // A vector parallel to the boundary plane, not parallel to e.
+ private final F1 mapMaterial;
// transient
private final Vec3 n; // A normal vector to the boundary plane
@@ -20,10 +20,11 @@ public class HalfSpace implements Solid {
- private HalfSpace(Vec3 p, Vec3 e, Vec3 f) {
+ private HalfSpace(Vec3 p, Vec3 e, Vec3 f, F1 mapMaterial) {
this.p = p;
this.e = e;
this.f = f;
+ this.mapMaterial = mapMaterial;
this.n = e.cross(f);
n_ = n.normalized_();
@@ -37,21 +38,21 @@ public class HalfSpace implements Solid {
}
- public static HalfSpace pef(Vec3 p, Vec3 e, Vec3 f) {
- return new HalfSpace(p, e, f);
+ public static HalfSpace pef(Vec3 p, Vec3 e, Vec3 f, F1 mapMaterial) {
+ return new HalfSpace(p, e, f, mapMaterial);
}
- public static HalfSpace pqr(Vec3 p, Vec3 q, Vec3 r) {
- return pef(p, q.sub(p), r.sub(p));
+ public static HalfSpace pqr(Vec3 p, Vec3 q, Vec3 r, F1 mapMaterial) {
+ return pef(p, q.sub(p), r.sub(p), mapMaterial);
}
- public static HalfSpace pn(Vec3 p, Vec3 n) {
+ public static HalfSpace pn(Vec3 p, Vec3 n, F1 mapMaterial) {
double nl = n.length();
Vec3 e = GeometryUtils.normal(n).normalizedTo(nl);
Vec3 f = n.cross(e).normalizedTo(nl);
- return new HalfSpace(p, e, f);
+ return new HalfSpace(p, e, f, mapMaterial);
}
@@ -113,11 +114,30 @@ public class HalfSpace implements Solid {
return n;
}
+ @Override
+ public Material material() {
+ return HalfSpace.this.mapMaterial.at(uv());
+ }
+
@Override
public Vec3 n_() {
return n_;
}
+ @Override
+ public Vector uv() {
+ Vec3 b = ray().at(t()).sub(p);
+
+ double b_e = b.dot(e) / eLSqr;
+ double b_f = b.dot(f) / fLSqr;
+
+ return Vector.xy(
+ (b_e - b_f * f_e) / sinSqr,
+ (b_f - b_e * e_f) / sinSqr
+ );
+ }
}
+
}
+
diff --git a/src/xyz/marsavic/gfxlab/gui/UtilsGL.java b/src/xyz/marsavic/gfxlab/gui/UtilsGL.java
index 0f886e7..d1fa55d 100644
--- a/src/xyz/marsavic/gfxlab/gui/UtilsGL.java
+++ b/src/xyz/marsavic/gfxlab/gui/UtilsGL.java
@@ -15,10 +15,9 @@ import xyz.marsavic.gfxlab.Color;
import xyz.marsavic.gfxlab.Matrix;
import xyz.marsavic.gfxlab.MatrixData;
import xyz.marsavic.gfxlab.MatrixInts;
-import xyz.marsavic.resources.ResourceManagerMap;
import xyz.marsavic.random.RNG;
+import xyz.marsavic.resources.ResourceManagerMap;
import xyz.marsavic.time.Profiler;
-import xyz.marsavic.utils.Utils;
import javax.imageio.ImageIO;
import java.io.File;
@@ -139,13 +138,13 @@ public class UtilsGL {
static {
int p = ForkJoinPool.getCommonPoolParallelism();
try {
- boolean obsRunning = false;
- obsRunning |= ProcessHandle.allProcesses().anyMatch(ph -> ph.info().command().orElse("").contains("obs64")); // Windows
- obsRunning |= !Utils.runCommand("top -b -n 1 | grep \" obs\"").isEmpty(); // Linux
- obsRunning |= true;
- if (obsRunning) {
- p -= 3;
- }
+// boolean obsRunning = false;
+// obsRunning |= ProcessHandle.allProcesses().anyMatch(ph -> ph.info().command().orElse("").contains("obs64")); // Windows
+// obsRunning |= !Utils.runCommand("top -b -n 1 | grep \" obs\"").isEmpty(); // Linux
+// obsRunning |= true;
+// if (obsRunning) {
+ p = 1 + p/2;
+// }
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/src/xyz/marsavic/gfxlab/playground/GfxLab.java b/src/xyz/marsavic/gfxlab/playground/GfxLab.java
index 1cffe32..ec749b4 100644
--- a/src/xyz/marsavic/gfxlab/playground/GfxLab.java
+++ b/src/xyz/marsavic/gfxlab/playground/GfxLab.java
@@ -4,11 +4,12 @@ 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.raytracers.RayTracingTest;
+import xyz.marsavic.gfxlab.graphics3d.raytracers.RayTracerSimple;
+import xyz.marsavic.gfxlab.graphics3d.scene.SceneTest1;
import xyz.marsavic.gfxlab.gui.UtilsGL;
import xyz.marsavic.gfxlab.tonemapping.ColorTransform;
import xyz.marsavic.gfxlab.tonemapping.ToneMapping;
-import xyz.marsavic.gfxlab.tonemapping.colortransforms.Identity;
+import xyz.marsavic.gfxlab.tonemapping.colortransforms.Multiply;
import static xyz.marsavic.gfxlab.elements.ElementF.e;
import static xyz.marsavic.gfxlab.elements.Output.val;
@@ -28,13 +29,15 @@ public class GfxLab {
e(Fs::aFillFrameColor,
e(Fs::transformedColorFunction,
// e(Blobs::new, val(5), val(0.1), val(0.2)),
- e(RayTracingTest::new),
+ e(RayTracerSimple::new,
+ e(SceneTest1::new)
+ ),
e(TransformationsFromSize.toGeometric, eSize)
)
),
e(Fs::toneMapping,
e(ColorTransform::asColorTransformFromMatrixColor,
- e(Identity::new)
+ e(Multiply::new, val(1.0))
)
)
)
@@ -70,7 +73,7 @@ class Fs {
public static ToneMapping toneMapping(F1> f_ColorTransform_MatrixColor) {
return (input, output) -> {
ColorTransform f = f_ColorTransform_MatrixColor.at(input);
- output.fill(p -> f.at(input.get(p)).code());
+ output.fill(p -> f.at(input.get(p)).codeClamp());
};
}