From 2ce55fbb5028edf5bafbc5922dba62c38a83a884 Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Sat, 15 Jul 2023 13:25:20 -0500 Subject: [PATCH 01/38] some experimentation --- chunky/src/java/se/llbit/math/Ray.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index 064efb6ed2..405dd72c61 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -269,6 +269,8 @@ public float[] getBiomeWaterColor(Scene scene) { * Set this ray to a random diffuse reflection of the input ray. */ public final void diffuseReflection(Ray ray, Random random) { + boolean SUN_SAMPLING_TEST = true; + set(ray); // get random point on unit disk @@ -277,6 +279,10 @@ public final void diffuseReflection(Ray ray, Random random) { double r = FastMath.sqrt(x1); double theta = 2 * Math.PI * x2; + if(SUN_SAMPLING_TEST) { + + } + // project to point on hemisphere in tangent space double tx = r * FastMath.cos(theta); double ty = r * FastMath.sin(theta); @@ -314,6 +320,11 @@ public final void diffuseReflection(Ray ray, Random random) { d.x = ux * tx + vx * ty + n.x * tz; d.y = uy * tx + vy * ty + n.y * tz; d.z = uz * tx + vz * ty + n.z * tz; +// if(random.nextFloat() < 0.5) { +// d.x = -0.5; +// d.y = 0.7071; +// d.z = 0.5; +// } o.scaleAdd(Ray.OFFSET, d); currentMaterial = prevMaterial; From a06fe8e39b193294fe8330a53e3af00d3fe58144 Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Sat, 15 Jul 2023 13:42:32 -0500 Subject: [PATCH 02/38] added some incorrect math --- chunky/src/java/se/llbit/math/Ray.java | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index 405dd72c61..0a7c81100d 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -279,15 +279,32 @@ public final void diffuseReflection(Ray ray, Random random) { double r = FastMath.sqrt(x1); double theta = 2 * Math.PI * x2; - if(SUN_SAMPLING_TEST) { - - } - // project to point on hemisphere in tangent space double tx = r * FastMath.cos(theta); double ty = r * FastMath.sin(theta); double tz = FastMath.sqrt(1 - x1); + if(SUN_SAMPLING_TEST) { + double DESIRED_DX = -0.5; + double DESIRED_DY = FastMath.sqrt(0.5); + double DESIRED_DZ = 0.5; + double desired_tx, desired_ty, desired_tz; + if(QuickMath.abs(n.x) > .1) { + desired_tx = DESIRED_DX*n.z*(n.y*n.y - n.x*n.x - n.z*n.z) + DESIRED_DZ*n.x*(n.x*n.x - n.y*n.y + n.z*n.z); + desired_ty = DESIRED_DX*n.x*n.y - DESIRED_DY*(n.x*n.x + n.z*n.z) + DESIRED_DZ*(n.y*n.z); + desired_tz = -DESIRED_DX*n.x + DESIRED_DY*n.y - DESIRED_DZ*n.z; + double sqrtxz = FastMath.sqrt(n.x*n.x+n.z*n.z); + desired_tx /= sqrtxz; + desired_ty /= sqrtxz; + if(desired_tz > 0) { + tx = desired_tx; + ty = desired_ty; + tz = desired_tz; + } + } + + } + // transform from tangent space to world space double xx, xy, xz; double ux, uy, uz; From af86166715ef19982fb3c1c6d0ad0de85b449ea5 Mon Sep 17 00:00:00 2001 From: Justin Barker Date: Sun, 16 Jul 2023 17:15:03 -0500 Subject: [PATCH 03/38] fix math --- chunky/src/java/se/llbit/math/Ray.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index 0a7c81100d..2935bf21df 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -285,14 +285,14 @@ public final void diffuseReflection(Ray ray, Random random) { double tz = FastMath.sqrt(1 - x1); if(SUN_SAMPLING_TEST) { - double DESIRED_DX = -0.5; - double DESIRED_DY = FastMath.sqrt(0.5); + double DESIRED_DX = 0.5; double DESIRED_DZ = 0.5; + double DESIRED_DY = FastMath.sqrt(1 - DESIRED_DX*DESIRED_DX - DESIRED_DZ*DESIRED_DZ); double desired_tx, desired_ty, desired_tz; if(QuickMath.abs(n.x) > .1) { - desired_tx = DESIRED_DX*n.z*(n.y*n.y - n.x*n.x - n.z*n.z) + DESIRED_DZ*n.x*(n.x*n.x - n.y*n.y + n.z*n.z); + desired_tx = DESIRED_DX*n.z - DESIRED_DZ*n.x; desired_ty = DESIRED_DX*n.x*n.y - DESIRED_DY*(n.x*n.x + n.z*n.z) + DESIRED_DZ*(n.y*n.z); - desired_tz = -DESIRED_DX*n.x + DESIRED_DY*n.y - DESIRED_DZ*n.z; + desired_tz = DESIRED_DX*n.x + DESIRED_DY*n.y + DESIRED_DZ*n.z; double sqrtxz = FastMath.sqrt(n.x*n.x+n.z*n.z); desired_tx /= sqrtxz; desired_ty /= sqrtxz; @@ -337,11 +337,6 @@ public final void diffuseReflection(Ray ray, Random random) { d.x = ux * tx + vx * ty + n.x * tz; d.y = uy * tx + vy * ty + n.y * tz; d.z = uz * tx + vz * ty + n.z * tz; -// if(random.nextFloat() < 0.5) { -// d.x = -0.5; -// d.y = 0.7071; -// d.z = 0.5; -// } o.scaleAdd(Ray.OFFSET, d); currentMaterial = prevMaterial; From fcfbc591c5b9b48e6c338cfdcf1d05362c22eb01 Mon Sep 17 00:00:00 2001 From: Justin Barker Date: Sun, 16 Jul 2023 17:58:10 -0500 Subject: [PATCH 04/38] add math for when |n.x| <= 0.1 --- chunky/src/java/se/llbit/math/Ray.java | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index 2935bf21df..e18e6eb168 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -289,20 +289,25 @@ public final void diffuseReflection(Ray ray, Random random) { double DESIRED_DZ = 0.5; double DESIRED_DY = FastMath.sqrt(1 - DESIRED_DX*DESIRED_DX - DESIRED_DZ*DESIRED_DZ); double desired_tx, desired_ty, desired_tz; + desired_tz = DESIRED_DX*n.x + DESIRED_DY*n.y + DESIRED_DZ*n.z; if(QuickMath.abs(n.x) > .1) { desired_tx = DESIRED_DX*n.z - DESIRED_DZ*n.x; - desired_ty = DESIRED_DX*n.x*n.y - DESIRED_DY*(n.x*n.x + n.z*n.z) + DESIRED_DZ*(n.y*n.z); - desired_tz = DESIRED_DX*n.x + DESIRED_DY*n.y + DESIRED_DZ*n.z; + desired_ty = DESIRED_DX*n.x*n.y - DESIRED_DY*(n.x*n.x + n.z*n.z) + DESIRED_DZ*n.y*n.z; double sqrtxz = FastMath.sqrt(n.x*n.x+n.z*n.z); desired_tx /= sqrtxz; desired_ty /= sqrtxz; - if(desired_tz > 0) { - tx = desired_tx; - ty = desired_ty; - tz = desired_tz; - } + } else { + desired_tx = DESIRED_DZ*n.y - DESIRED_DY*n.z; + desired_ty = DESIRED_DY*n.x*n.y - DESIRED_DX*(n.y*n.y + n.z*n.z) + DESIRED_DZ*n.x*n.z; + double sqrtyz = FastMath.sqrt(n.y*n.y+n.z*n.z); + desired_tx /= sqrtyz; + desired_ty /= sqrtyz; + } + if(desired_tz > 0) { + tx = desired_tx; + ty = desired_ty; + tz = desired_tz; } - } // transform from tangent space to world space From f435a53cebcfebf9965a095e8c5dbb619060b340 Mon Sep 17 00:00:00 2001 From: Justin Barker Date: Sun, 16 Jul 2023 20:17:34 -0500 Subject: [PATCH 05/38] first decently-working implementation --- .../chunky/renderer/scene/PathTracer.java | 4 +- chunky/src/java/se/llbit/math/Ray.java | 70 +++++++++++++------ 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java index a373d6e7b6..c88e15f442 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java @@ -232,7 +232,7 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add } } - reflected.diffuseReflection(ray, random); + reflected.diffuseReflection(ray, random, scene); hit = pathTrace(scene, reflected, state, 0, false) || hit; if (hit) { ray.color.x = ray.color.x * (emittance + directLightR * scene.sun.emittance.x + ( @@ -249,7 +249,7 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add } } else { - reflected.diffuseReflection(ray, random); + reflected.diffuseReflection(ray, random, scene); hit = pathTrace(scene, reflected, state, 0, false) || hit; if (hit) { diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index e18e6eb168..03be5c2ff2 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -268,8 +268,13 @@ public float[] getBiomeWaterColor(Scene scene) { /** * Set this ray to a random diffuse reflection of the input ray. */ - public final void diffuseReflection(Ray ray, Random random) { + public final void diffuseReflection(Ray ray, Random random, Scene scene) { + + //TODO: Make these configurable boolean SUN_SAMPLING_TEST = true; + double DEFAULT_CIRCLE_RADIUS = scene.sun().getSunRadius() * 1.2; + double MIN_CIRCLE_RADIUS = DEFAULT_CIRCLE_RADIUS / 10; + double SUN_SAMPLE_CHANCE = 0.25; set(ray); @@ -282,34 +287,55 @@ public final void diffuseReflection(Ray ray, Random random) { // project to point on hemisphere in tangent space double tx = r * FastMath.cos(theta); double ty = r * FastMath.sin(theta); - double tz = FastMath.sqrt(1 - x1); if(SUN_SAMPLING_TEST) { - double DESIRED_DX = 0.5; - double DESIRED_DZ = 0.5; - double DESIRED_DY = FastMath.sqrt(1 - DESIRED_DX*DESIRED_DX - DESIRED_DZ*DESIRED_DZ); + double sun_az = scene.sun().getAzimuth(); + double sun_alt = scene.sun().getAltitude(); + double desired_dx = FastMath.cos(sun_az)*FastMath.cos(sun_alt); + double desired_dz = FastMath.sin(sun_az)*FastMath.cos(sun_alt); + double desired_dy = FastMath.sin(sun_alt); double desired_tx, desired_ty, desired_tz; - desired_tz = DESIRED_DX*n.x + DESIRED_DY*n.y + DESIRED_DZ*n.z; - if(QuickMath.abs(n.x) > .1) { - desired_tx = DESIRED_DX*n.z - DESIRED_DZ*n.x; - desired_ty = DESIRED_DX*n.x*n.y - DESIRED_DY*(n.x*n.x + n.z*n.z) + DESIRED_DZ*n.y*n.z; - double sqrtxz = FastMath.sqrt(n.x*n.x+n.z*n.z); - desired_tx /= sqrtxz; - desired_ty /= sqrtxz; - } else { - desired_tx = DESIRED_DZ*n.y - DESIRED_DY*n.z; - desired_ty = DESIRED_DY*n.x*n.y - DESIRED_DX*(n.y*n.y + n.z*n.z) + DESIRED_DZ*n.x*n.z; - double sqrtyz = FastMath.sqrt(n.y*n.y+n.z*n.z); - desired_tx /= sqrtyz; - desired_ty /= sqrtyz; - } + desired_tz = desired_dx*n.x + desired_dy*n.y + desired_dz*n.z; if(desired_tz > 0) { - tx = desired_tx; - ty = desired_ty; - tz = desired_tz; + if(QuickMath.abs(n.x) > .1) { + desired_tx = desired_dx * n.z - desired_dz * n.x; + desired_ty = desired_dx * n.x * n.y - desired_dy * (n.x * n.x + n.z * n.z) + desired_dz * n.y * n.z; + double sqrtxz = FastMath.hypot(n.x, n.z); + desired_tx /= sqrtxz; + desired_ty /= sqrtxz; + } else { + desired_tx = desired_dz * n.y - desired_dy * n.z; + desired_ty = desired_dy * n.x * n.y - desired_dx * (n.y * n.y + n.z * n.z) + desired_dz * n.x * n.z; + double sqrtzy = FastMath.hypot(n.z, n.y); + desired_tx /= sqrtzy; + desired_ty /= sqrtzy; + } + double circle_radius = FastMath.min(DEFAULT_CIRCLE_RADIUS, 1 - FastMath.hypot(desired_tx, desired_ty) - Ray.EPSILON); + double sample_chance = SUN_SAMPLE_CHANCE * circle_radius * circle_radius / (DEFAULT_CIRCLE_RADIUS * DEFAULT_CIRCLE_RADIUS); + if(circle_radius >= MIN_CIRCLE_RADIUS) { + if(random.nextDouble() < sample_chance) { + tx = desired_tx + tx * circle_radius; + ty = desired_ty + ty * circle_radius; + ray.color.scale(circle_radius * circle_radius / sample_chance); + } else { + while(FastMath.hypot(tx - desired_tx, ty - desired_ty) < circle_radius) { + tx -= desired_tx; + ty -= desired_ty; + // Avoid very unlikely infinite loop + if(tx == 0 && ty == 0) { + break; + } + tx /= circle_radius; + ty /= circle_radius; + } + ray.color.scale((1 - circle_radius * circle_radius) / (1 - sample_chance)); + } + } } } + double tz = FastMath.sqrt(1 - tx*tx - ty*ty); + // transform from tangent space to world space double xx, xy, xz; double ux, uy, uz; From 7b69564cf7419f3005a89717793bd4ed133126ff Mon Sep 17 00:00:00 2001 From: Justin Barker Date: Mon, 17 Jul 2023 11:07:58 -0500 Subject: [PATCH 06/38] add to sun sampling strategy enum (and GUI dropdown) --- .../chunky/renderer/SunSamplingStrategy.java | 15 ++++++++++----- chunky/src/java/se/llbit/math/Ray.java | 5 ++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/chunky/src/java/se/llbit/chunky/renderer/SunSamplingStrategy.java b/chunky/src/java/se/llbit/chunky/renderer/SunSamplingStrategy.java index 48773593df..6e280a1bc1 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/SunSamplingStrategy.java +++ b/chunky/src/java/se/llbit/chunky/renderer/SunSamplingStrategy.java @@ -19,10 +19,11 @@ import se.llbit.util.Registerable; public enum SunSamplingStrategy implements Registerable { - OFF("Off", "Sun is not sampled with next event estimation.", false, true, false, true), - NON_LUMINOUS("Non-Luminous", "Sun is drawn on the skybox but it does not contribute to the lighting of the scene.", false, false, false, false), - FAST("Fast", "Fast sun sampling algorithm. Lower noise but does not correctly model some visual effects.", true, false, false, false), - HIGH_QUALITY("High Quality", "High quality sun sampling. More noise but correctly models visual effects such as caustics.", true, true, true, true); + OFF("Off", "Sun is not sampled with next event estimation.", false, true, false, true, false), + NON_LUMINOUS("Non-Luminous", "Sun is drawn on the skybox but it does not contribute to the lighting of the scene.", false, false, false, false, false), + FAST("Fast", "Fast sun sampling algorithm. Lower noise but does not correctly model some visual effects.", true, false, false, false, false), + HIGH_QUALITY("High Quality", "High quality sun sampling. More noise but correctly models visual effects such as caustics.", true, true, true, true, false), + DIFFUSE("Diffuse", "Sun is sampled on a certain percentage of diffuse reflections. Correctly models visual effects while reducing noise for direct and diffuse illumination.", false, true, false, true, true); private final String displayName; private final String description; @@ -31,8 +32,9 @@ public enum SunSamplingStrategy implements Registerable { private final boolean diffuseSun; private final boolean strictDirectLight; private final boolean sunLuminosity; + private final boolean diffuseSampling; - SunSamplingStrategy(String displayName, String description, boolean sunSampling, boolean diffuseSun, boolean strictDirectLight, boolean sunLuminosity) { + SunSamplingStrategy(String displayName, String description, boolean sunSampling, boolean diffuseSun, boolean strictDirectLight, boolean sunLuminosity, boolean diffuseSampling) { this.displayName = displayName; this.description = description; @@ -40,6 +42,7 @@ public enum SunSamplingStrategy implements Registerable { this.diffuseSun = diffuseSun; this.strictDirectLight = strictDirectLight; this.sunLuminosity = sunLuminosity; + this.diffuseSampling = diffuseSampling; } @Override @@ -72,4 +75,6 @@ public boolean isStrictDirectLight() { public boolean isSunLuminosity() { return sunLuminosity; } + + public boolean isDiffuseSampling() { return diffuseSampling; } } diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index 03be5c2ff2..ea0c89717c 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -271,10 +271,9 @@ public float[] getBiomeWaterColor(Scene scene) { public final void diffuseReflection(Ray ray, Random random, Scene scene) { //TODO: Make these configurable - boolean SUN_SAMPLING_TEST = true; double DEFAULT_CIRCLE_RADIUS = scene.sun().getSunRadius() * 1.2; double MIN_CIRCLE_RADIUS = DEFAULT_CIRCLE_RADIUS / 10; - double SUN_SAMPLE_CHANCE = 0.25; + double SUN_SAMPLE_CHANCE = 0.1; set(ray); @@ -288,7 +287,7 @@ public final void diffuseReflection(Ray ray, Random random, Scene scene) { double tx = r * FastMath.cos(theta); double ty = r * FastMath.sin(theta); - if(SUN_SAMPLING_TEST) { + if(scene.getSunSamplingStrategy().isDiffuseSampling()) { double sun_az = scene.sun().getAzimuth(); double sun_alt = scene.sun().getAltitude(); double desired_dx = FastMath.cos(sun_az)*FastMath.cos(sun_alt); From f64b971ffb9c27efbae33b134be69603b184055f Mon Sep 17 00:00:00 2001 From: Justin Barker Date: Mon, 17 Jul 2023 14:55:59 -0500 Subject: [PATCH 07/38] Add more GUI controls --- .../se/llbit/chunky/renderer/scene/Sun.java | 53 +++++++++++++++++++ .../chunky/ui/render/tabs/LightingTab.java | 31 ++++++++++- chunky/src/java/se/llbit/math/Ray.java | 5 +- .../chunky/ui/render/tabs/LightingTab.fxml | 10 ++++ 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/chunky/src/java/se/llbit/chunky/renderer/scene/Sun.java b/chunky/src/java/se/llbit/chunky/renderer/scene/Sun.java index a368620aa4..153ea0b84f 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/Sun.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/Sun.java @@ -61,6 +61,36 @@ public class Sun implements JsonSerializable { */ public static final double MAX_APPARENT_BRIGHTNESS = 50; + /** + * Default probability for diffuse sun sampling + */ + public static final double DEFAULT_DIFFUSE_SAMPLE_CHANCE = 0.1; + + /** + * Minimum probability for diffuse sun sampling + */ + public static final double MIN_DIFFUSE_SAMPLE_CHANCE = 0.001; + + /** + * Maximum probability for diffuse sun sampling + */ + public static final double MAX_DIFFUSE_SAMPLE_CHANCE = 0.9; + + /** + * Default radius (relative to sun) for diffuse sun sampling + */ + public static final double DEFAULT_DIFFUSE_SAMPLE_RADIUS = 1.2; + + /** + * Minimum radius (relative to sun) for diffuse sun sampling + */ + public static final double MIN_DIFFUSE_SAMPLE_RADIUS = 0.1; + + /** + * Maximum radius (relative to sun) for diffuse sun sampling + */ + public static final double MAX_DIFFUSE_SAMPLE_RADIUS = 5; + private static final double xZenithChroma[][] = {{0.00166, -0.00375, 0.00209, 0}, {-0.02903, 0.06377, -0.03203, 0.00394}, {0.11693, -0.21196, 0.06052, 0.25886},}; @@ -137,6 +167,9 @@ public class Sun implements JsonSerializable { private Vector3 apparentTextureBrightness = new Vector3(1, 1, 1); private boolean enableTextureModification = false; + private double diffuseSampleChance = DEFAULT_DIFFUSE_SAMPLE_CHANCE; + private double diffuseSampleRadius = DEFAULT_DIFFUSE_SAMPLE_RADIUS; + private double azimuth = Math.PI / 2.5; private double altitude = Math.PI / 3; @@ -202,6 +235,8 @@ public void set(Sun other) { radius = other.radius; enableTextureModification = other.enableTextureModification; luminosityPdf = other.luminosityPdf; + diffuseSampleRadius = other.diffuseSampleRadius; + diffuseSampleChance = other.diffuseSampleChance; initSun(); } @@ -475,6 +510,10 @@ public void getRandomSunDirection(Ray reflected, Random random) { apparentColorObj.add("green", apparentColor.y); apparentColorObj.add("blue", apparentColor.z); sun.add("apparentColor", apparentColorObj); + JsonObject diffuseSamplingObj = new JsonObject(); + diffuseSamplingObj.add("chance", diffuseSampleChance); + diffuseSamplingObj.add("radius", diffuseSampleRadius); + sun.add("diffuseSampling", diffuseSamplingObj); sun.add("drawTexture", drawTexture); return sun; } @@ -502,6 +541,12 @@ public void importFromJson(JsonObject json) { apparentColor.z = apparentColorObj.get("blue").doubleValue(1); } + if(json.get("diffuseSampling").isObject()) { + JsonObject diffuseSamplingObj = json.get("diffuseSampling").object(); + diffuseSampleChance = diffuseSamplingObj.get("chance").doubleValue(DEFAULT_DIFFUSE_SAMPLE_CHANCE); + diffuseSampleRadius = diffuseSamplingObj.get("radius").doubleValue(DEFAULT_DIFFUSE_SAMPLE_RADIUS); + } + drawTexture = json.get("drawTexture").boolValue(drawTexture); initSun(); @@ -528,4 +573,12 @@ public void setDrawTexture(boolean value) { public boolean drawTexture() { return drawTexture; } + + public double getDiffuseSampleChance() { return diffuseSampleChance; } + + public void setDiffuseSampleChance(double d) { diffuseSampleChance = d; } + + public double getDiffuseSampleRadius() { return diffuseSampleRadius; } + + public void setDiffuseSampleRadius(double d) { diffuseSampleRadius = d; } } diff --git a/chunky/src/java/se/llbit/chunky/ui/render/tabs/LightingTab.java b/chunky/src/java/se/llbit/chunky/ui/render/tabs/LightingTab.java index bedf302107..fad34d5742 100644 --- a/chunky/src/java/se/llbit/chunky/ui/render/tabs/LightingTab.java +++ b/chunky/src/java/se/llbit/chunky/ui/render/tabs/LightingTab.java @@ -55,6 +55,9 @@ public class LightingTab extends ScrollPane implements RenderControlsTab, Initia @FXML private DoubleAdjuster sunIntensity; @FXML private CheckBox drawSun; @FXML private ComboBox sunSamplingStrategy; + @FXML private TitledPane diffuseSamplingDetailsPane; + @FXML private DoubleAdjuster diffuseSampleChance; + @FXML private DoubleAdjuster diffuseSampleRadius; @FXML private DoubleAdjuster sunLuminosity; @FXML private DoubleAdjuster apparentSunBrightness; @FXML private DoubleAdjuster sunRadius; @@ -134,9 +137,33 @@ public LightingTab() throws IOException { sunSamplingStrategy.getItems().addAll(SunSamplingStrategy.values()); sunSamplingStrategy.getSelectionModel().selectedItemProperty().addListener( - (observable, oldValue, newValue) -> scene.setSunSamplingStrategy(newValue)); + (observable, oldValue, newValue) -> { + scene.setSunSamplingStrategy(newValue); + + boolean visible = scene != null && scene.getSunSamplingStrategy().isDiffuseSampling(); + diffuseSamplingDetailsPane.setVisible(visible); + diffuseSamplingDetailsPane.setExpanded(visible); + diffuseSamplingDetailsPane.setManaged(visible); + }); sunSamplingStrategy.setTooltip(new Tooltip("Determines how the sun is sampled at each bounce.")); + boolean visible = scene != null && scene.getSunSamplingStrategy().isDiffuseSampling(); + diffuseSamplingDetailsPane.setVisible(visible); + diffuseSamplingDetailsPane.setExpanded(visible); + diffuseSamplingDetailsPane.setManaged(visible); + + diffuseSampleChance.setName("Diffuse sample chance"); + diffuseSampleChance.setTooltip("Probability of sampling the sun on each diffuse bounce"); + diffuseSampleChance.setRange(Sun.MIN_DIFFUSE_SAMPLE_CHANCE, Sun.MAX_DIFFUSE_SAMPLE_CHANCE); + diffuseSampleChance.clampBoth(); + diffuseSampleChance.onValueChange(value -> scene.sun().setDiffuseSampleChance(value)); + + diffuseSampleRadius.setName("Diffuse sample radius"); + diffuseSampleRadius.setTooltip("Radius of possible sun sampling bounces (relative to the sun's radius)"); + diffuseSampleRadius.setRange(Sun.MIN_DIFFUSE_SAMPLE_RADIUS, Sun.MAX_DIFFUSE_SAMPLE_RADIUS); + diffuseSampleRadius.clampMin(); + diffuseSampleRadius.onValueChange(value -> scene.sun().setDiffuseSampleRadius(value)); + sunIntensity.setName("Sunlight intensity"); sunIntensity.setTooltip("Changes the intensity of sunlight. Only used when Sun Sampling Strategy is set to FAST or HIGH_QUALITY."); sunIntensity.setRange(Sun.MIN_INTENSITY, Sun.MAX_INTENSITY); @@ -203,6 +230,8 @@ public void setController(RenderControlsFxController controller) { sunAltitude.set(QuickMath.radToDeg(scene.sun().getAltitude())); enableEmitters.setSelected(scene.getEmittersEnabled()); sunSamplingStrategy.getSelectionModel().select(scene.getSunSamplingStrategy()); + diffuseSampleChance.set(scene.sun().getDiffuseSampleChance()); + diffuseSampleRadius.set(scene.sun().getDiffuseSampleRadius()); drawSun.setSelected(scene.sun().drawTexture()); sunColor.colorProperty().removeListener(sunColorListener); sunColor.setColor(ColorUtil.toFx(scene.sun().getColor())); diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index ea0c89717c..de0228b6d4 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -270,10 +270,9 @@ public float[] getBiomeWaterColor(Scene scene) { */ public final void diffuseReflection(Ray ray, Random random, Scene scene) { - //TODO: Make these configurable - double DEFAULT_CIRCLE_RADIUS = scene.sun().getSunRadius() * 1.2; + double DEFAULT_CIRCLE_RADIUS = scene.sun().getSunRadius() * scene.sun().getDiffuseSampleRadius(); double MIN_CIRCLE_RADIUS = DEFAULT_CIRCLE_RADIUS / 10; - double SUN_SAMPLE_CHANCE = 0.1; + double SUN_SAMPLE_CHANCE = scene.sun().getDiffuseSampleChance(); set(ray); diff --git a/chunky/src/res/se/llbit/chunky/ui/render/tabs/LightingTab.fxml b/chunky/src/res/se/llbit/chunky/ui/render/tabs/LightingTab.fxml index 63708d2812..9487e5c5a3 100644 --- a/chunky/src/res/se/llbit/chunky/ui/render/tabs/LightingTab.fxml +++ b/chunky/src/res/se/llbit/chunky/ui/render/tabs/LightingTab.fxml @@ -12,6 +12,7 @@ + @@ -31,6 +32,15 @@