From 31ce4bf5e871a7c0cfa8645ae0dad6546ae18b9b Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Fri, 1 Sep 2023 15:24:03 -0400 Subject: [PATCH 01/15] Configurable exponent for emitter mapping --- .../chunky/renderer/scene/PathTracer.java | 6 ++-- .../se/llbit/chunky/renderer/scene/Scene.java | 33 +++++++++++++++++++ .../chunky/ui/render/tabs/LightingTab.java | 8 +++++ .../chunky/ui/render/tabs/LightingTab.fxml | 1 + 4 files changed, 45 insertions(+), 3 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 277f8ec3f0..cf0654f600 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java @@ -228,9 +228,9 @@ private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMa if (scene.emittersEnabled && (!scene.isPreventNormalEmitterWithSampling() || scene.getEmitterSamplingStrategy() == EmitterSamplingStrategy.NONE || ray.depth == 0) && currentMat.emittance > Ray.EPSILON) { - // Quadratic emittance mapping, so a pixel that's 50% darker will emit only 25% as much light - // This is arbitrary but gives pretty good results in most cases. - emittance = new Vector3(ray.color.x * ray.color.x, ray.color.y * ray.color.y, ray.color.z * ray.color.z); + // Exponential emittance mapping + double exp = scene.getEmitterMappingExponent(); + emittance = new Vector3(FastMath.pow(ray.color.x, exp), FastMath.pow(ray.color.y, exp), FastMath.pow(ray.color.z, exp)); emittance.scale(currentMat.emittance * scene.emitterIntensity); hit = true; diff --git a/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java b/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java index fd1c4536d7..c263d7c081 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java @@ -115,6 +115,10 @@ public class Scene implements JsonSerializable, Refreshable { * Default emitter intensity. */ public static final double DEFAULT_EMITTER_INTENSITY = 13; + /** + * Default exponent for emitter mapping. + */ + public static final double DEFAULT_EMITTER_MAPPING_EXPONENT = 2; /** * Minimum emitter intensity. @@ -126,6 +130,16 @@ public class Scene implements JsonSerializable, Refreshable { */ public static final double MAX_EMITTER_INTENSITY = 1000; + /** + * Minimum emitter mapping exponent. + */ + public static final double MIN_EMITTER_MAPPING_EXPONENT = 0; + + /** + * Maximum emitter mapping exponent. + */ + public static final double MAX_EMITTER_MAPPING_EXPONENT = 5; + /** * Default transmissivity cap. */ @@ -210,6 +224,7 @@ public class Scene implements JsonSerializable, Refreshable { protected boolean saveSnapshots = false; protected boolean emittersEnabled = DEFAULT_EMITTERS_ENABLED; protected double emitterIntensity = DEFAULT_EMITTER_INTENSITY; + protected double emitterMappingExponent = DEFAULT_EMITTER_MAPPING_EXPONENT; protected EmitterSamplingStrategy emitterSamplingStrategy = EmitterSamplingStrategy.NONE; protected boolean fancierTranslucency = true; protected double transmissivityCap = DEFAULT_TRANSMISSIVITY_CAP; @@ -455,6 +470,7 @@ public synchronized void copyState(Scene other, boolean copyChunks) { sunSamplingStrategy = other.sunSamplingStrategy; emittersEnabled = other.emittersEnabled; emitterIntensity = other.emitterIntensity; + emitterMappingExponent = other.emitterMappingExponent; emitterSamplingStrategy = other.emitterSamplingStrategy; preventNormalEmitterWithSampling = other.preventNormalEmitterWithSampling; fancierTranslucency = other.fancierTranslucency; @@ -1755,6 +1771,21 @@ public void setEmitterIntensity(double value) { refresh(); } + /** + * @return The current emitter mapping exponent + */ + public double getEmitterMappingExponent() { + return emitterMappingExponent; + } + + /** + * Set the emitter mapping exponent. + */ + public void setEmitterMappingExponent(double value) { + emitterMappingExponent = value; + refresh(); + } + /** * Set the transparent sky option. */ @@ -2642,6 +2673,7 @@ public void setUseCustomWaterColor(boolean value) { json.add("saveSnapshots", saveSnapshots); json.add("emittersEnabled", emittersEnabled); json.add("emitterIntensity", emitterIntensity); + json.add("emitterMappingExponent", emitterMappingExponent); json.add("fancierTranslucency", fancierTranslucency); json.add("transmissivityCap", transmissivityCap); json.add("sunSamplingStrategy", sunSamplingStrategy.getId()); @@ -2910,6 +2942,7 @@ public synchronized void importFromJson(JsonObject json) { saveSnapshots = json.get("saveSnapshots").boolValue(saveSnapshots); emittersEnabled = json.get("emittersEnabled").boolValue(emittersEnabled); emitterIntensity = json.get("emitterIntensity").doubleValue(emitterIntensity); + emitterMappingExponent = json.get("emitterMappingExponent").doubleValue(emitterMappingExponent); fancierTranslucency = json.get("fancierTranslucency").boolValue(fancierTranslucency); transmissivityCap = json.get("transmissivityCap").doubleValue(transmissivityCap); 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..d32ebd1246 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 @@ -52,6 +52,7 @@ public class LightingTab extends ScrollPane implements RenderControlsTab, Initia @FXML private DoubleAdjuster skyIntensity; @FXML private DoubleAdjuster apparentSkyBrightness; @FXML private DoubleAdjuster emitterIntensity; + @FXML private DoubleAdjuster emitterMappingExponent; @FXML private DoubleAdjuster sunIntensity; @FXML private CheckBox drawSun; @FXML private ComboBox sunSamplingStrategy; @@ -110,6 +111,12 @@ public LightingTab() throws IOException { emitterIntensity.clampMin(); emitterIntensity.onValueChange(value -> scene.setEmitterIntensity(value)); + emitterMappingExponent.setName("Emitter mapping exponent"); + emitterMappingExponent.setTooltip("Determines how much light is emitted from darker or lighter pixels.\nHigher values will result in darker pixels emitting less light."); + emitterMappingExponent.setRange(Scene.MIN_EMITTER_MAPPING_EXPONENT, Scene.MAX_EMITTER_MAPPING_EXPONENT); + emitterMappingExponent.clampMin(); + emitterMappingExponent.onValueChange(value -> scene.setEmitterMappingExponent(value)); + emitterSamplingStrategy.getItems().addAll(EmitterSamplingStrategy.values()); emitterSamplingStrategy.getSelectionModel().selectedItemProperty() .addListener((observable, oldvalue, newvalue) -> { @@ -194,6 +201,7 @@ public void setController(RenderControlsFxController controller) { skyIntensity.set(scene.sky().getSkyLight()); apparentSkyBrightness.set(scene.sky().getApparentSkyLight()); emitterIntensity.set(scene.getEmitterIntensity()); + emitterMappingExponent.set(scene.getEmitterMappingExponent()); sunIntensity.set(scene.sun().getIntensity()); sunLuminosity.set(scene.sun().getLuminosity()); apparentSunBrightness.set(scene.sun().getApparentBrightness()); 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..cbaaede717 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 @@ -21,6 +21,7 @@ +