From a44b1c1cfb354e5e70d65502a21913791bc9ac3d Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Fri, 11 Aug 2023 02:34:43 -0500 Subject: [PATCH 1/2] add toggle for "fancier translucency" --- .../chunky/renderer/scene/PathTracer.java | 94 ++++++++++--------- .../se/llbit/chunky/renderer/scene/Scene.java | 12 +++ .../chunky/ui/render/tabs/AdvancedTab.java | 9 ++ .../chunky/ui/render/tabs/AdvancedTab.fxml | 1 + 4 files changed, 72 insertions(+), 44 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 dbabef3c21..579d48b77b 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java @@ -21,7 +21,6 @@ import se.llbit.chunky.block.Air; import se.llbit.chunky.block.Water; import se.llbit.chunky.renderer.EmitterSamplingStrategy; -import se.llbit.chunky.renderer.SunSamplingStrategy; import se.llbit.chunky.renderer.WorkerState; import se.llbit.chunky.world.Material; import se.llbit.math.*; @@ -105,7 +104,7 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add float pSpecular = currentMat.specular; - double pDiffuse = 1 - Math.sqrt(1 - ray.color.w); + double pDiffuse = scene.fancierTranslucency ? 1 - Math.sqrt(1 - ray.color.w) : ray.color.w; float n1 = prevMat.ior; float n2 = currentMat.ior; @@ -421,50 +420,57 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add } private static void translucentRayColor(Scene scene, Ray ray, Ray next, double opacity) { - // Color-based transmission value - double colorTrans = (ray.color.x + ray.color.y + ray.color.z)/3; - // Total amount of light we want to transmit (overall transparency of texture) - double shouldTrans = 1 - opacity; - // Amount of each color to transmit - default to overall transparency if RGB values add to 0 (e.g. regular glass) - Vector3 rgbTrans = new Vector3(shouldTrans, shouldTrans, shouldTrans); - if(colorTrans > 0) { - // Amount to transmit of each color is scaled so the total transmitted amount matches the texture's transparency - rgbTrans.set(ray.color.toVec3()); - rgbTrans.scale(shouldTrans / colorTrans); - } - double transmissivityCap = scene.transmissivityCap; - // Determine the color with the highest transmissivity - double maxTrans = Math.max(rgbTrans.x, Math.max(rgbTrans.y, rgbTrans.z)); - if(maxTrans > transmissivityCap) { - if (maxTrans == rgbTrans.x) { - // Give excess transmission from red to green and blue - double gTransNew = reassignTransmissivity(rgbTrans.x, rgbTrans.y, rgbTrans.z, shouldTrans, transmissivityCap); - rgbTrans.z = reassignTransmissivity(rgbTrans.x, rgbTrans.z, rgbTrans.y, shouldTrans, transmissivityCap); - rgbTrans.y = gTransNew; - rgbTrans.x = transmissivityCap; - } else if (maxTrans == rgbTrans.y) { - // Give excess transmission from green to red and blue - double rTransNew = reassignTransmissivity(rgbTrans.y, rgbTrans.x, rgbTrans.z, shouldTrans, transmissivityCap); - rgbTrans.z = reassignTransmissivity(rgbTrans.y, rgbTrans.z, rgbTrans.x, shouldTrans, transmissivityCap); - rgbTrans.x = rTransNew; - rgbTrans.y = transmissivityCap; - } else if (maxTrans == rgbTrans.z) { - // Give excess transmission from blue to green and red - double gTransNew = reassignTransmissivity(rgbTrans.z, rgbTrans.y, rgbTrans.x, shouldTrans, transmissivityCap); - rgbTrans.x = reassignTransmissivity(rgbTrans.z, rgbTrans.x, rgbTrans.y, shouldTrans, transmissivityCap); - rgbTrans.y = gTransNew; - rgbTrans.z = transmissivityCap; + Vector3 rgbTrans; + if(scene.fancierTranslucency) { + // Color-based transmission value + double colorTrans = (ray.color.x + ray.color.y + ray.color.z) / 3; + // Total amount of light we want to transmit (overall transparency of texture) + double shouldTrans = 1 - opacity; + // Amount of each color to transmit - default to overall transparency if RGB values add to 0 (e.g. regular glass) + rgbTrans = new Vector3(shouldTrans, shouldTrans, shouldTrans); + if (colorTrans > 0) { + // Amount to transmit of each color is scaled so the total transmitted amount matches the texture's transparency + rgbTrans.set(ray.color.toVec3()); + rgbTrans.scale(shouldTrans / colorTrans); } - } - // Don't need to check for energy gain if transmissivity cap is 1 - if(transmissivityCap > 1) { - double currentEnergy = rgbTrans.x * next.color.x + rgbTrans.y * next.color.y + rgbTrans.z * next.color.z; - double nextEnergy = next.color.x + next.color.y + next.color.z; - double energyRatio = nextEnergy / currentEnergy; - // Normalize if there is net energy gain across all channels (more likely for higher transmissivityCap combined with high-saturation light source) - if(energyRatio < 1) { - rgbTrans.scale(energyRatio); + double transmissivityCap = scene.transmissivityCap; + // Determine the color with the highest transmissivity + double maxTrans = Math.max(rgbTrans.x, Math.max(rgbTrans.y, rgbTrans.z)); + if (maxTrans > transmissivityCap) { + if (maxTrans == rgbTrans.x) { + // Give excess transmission from red to green and blue + double gTransNew = reassignTransmissivity(rgbTrans.x, rgbTrans.y, rgbTrans.z, shouldTrans, transmissivityCap); + rgbTrans.z = reassignTransmissivity(rgbTrans.x, rgbTrans.z, rgbTrans.y, shouldTrans, transmissivityCap); + rgbTrans.y = gTransNew; + rgbTrans.x = transmissivityCap; + } else if (maxTrans == rgbTrans.y) { + // Give excess transmission from green to red and blue + double rTransNew = reassignTransmissivity(rgbTrans.y, rgbTrans.x, rgbTrans.z, shouldTrans, transmissivityCap); + rgbTrans.z = reassignTransmissivity(rgbTrans.y, rgbTrans.z, rgbTrans.x, shouldTrans, transmissivityCap); + rgbTrans.x = rTransNew; + rgbTrans.y = transmissivityCap; + } else if (maxTrans == rgbTrans.z) { + // Give excess transmission from blue to green and red + double gTransNew = reassignTransmissivity(rgbTrans.z, rgbTrans.y, rgbTrans.x, shouldTrans, transmissivityCap); + rgbTrans.x = reassignTransmissivity(rgbTrans.z, rgbTrans.x, rgbTrans.y, shouldTrans, transmissivityCap); + rgbTrans.y = gTransNew; + rgbTrans.z = transmissivityCap; + } } + // Don't need to check for energy gain if transmissivity cap is 1 + if (transmissivityCap > 1) { + double currentEnergy = rgbTrans.x * next.color.x + rgbTrans.y * next.color.y + rgbTrans.z * next.color.z; + double nextEnergy = next.color.x + next.color.y + next.color.z; + double energyRatio = nextEnergy / currentEnergy; + // Normalize if there is net energy gain across all channels (more likely for higher transmissivityCap combined with high-saturation light source) + if (energyRatio < 1) { + rgbTrans.scale(energyRatio); + } + } + } else { + // Old method (see https://github.com/chunky-dev/chunky/pull/1513) + rgbTrans = new Vector3(1 - opacity, 1 - opacity, 1 - opacity); + rgbTrans.scaleAdd(opacity, ray.color.toVec3()); } // Scale color based on next ray ray.color.multiplyEntrywise(new Vector4(rgbTrans, 1), next.color); 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 0fbf095fa5..f199dfdb58 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java @@ -207,6 +207,7 @@ public class Scene implements JsonSerializable, Refreshable { protected boolean emittersEnabled = DEFAULT_EMITTERS_ENABLED; protected double emitterIntensity = DEFAULT_EMITTER_INTENSITY; protected EmitterSamplingStrategy emitterSamplingStrategy = EmitterSamplingStrategy.NONE; + protected boolean fancierTranslucency = true; protected double transmissivityCap = DEFAULT_TRANSMISSIVITY_CAP; protected SunSamplingStrategy sunSamplingStrategy = SunSamplingStrategy.FAST; @@ -446,6 +447,7 @@ public synchronized void copyState(Scene other, boolean copyChunks) { emitterIntensity = other.emitterIntensity; emitterSamplingStrategy = other.emitterSamplingStrategy; preventNormalEmitterWithSampling = other.preventNormalEmitterWithSampling; + fancierTranslucency = other.fancierTranslucency; transmissivityCap = other.transmissivityCap; transparentSky = other.transparentSky; yClipMin = other.yClipMin; @@ -2614,6 +2616,7 @@ public void setUseCustomWaterColor(boolean value) { json.add("saveSnapshots", saveSnapshots); json.add("emittersEnabled", emittersEnabled); json.add("emitterIntensity", emitterIntensity); + json.add("fancierTranslucency", fancierTranslucency); json.add("transmissivityCap", transmissivityCap); json.add("sunSamplingStrategy", sunSamplingStrategy.getId()); json.add("stillWater", stillWater); @@ -2872,6 +2875,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); + fancierTranslucency = json.get("fancierTranslucency").boolValue(fancierTranslucency); transmissivityCap = json.get("transmissivityCap").doubleValue(transmissivityCap); if (json.get("sunSamplingStrategy").isUnknown()) { @@ -3380,6 +3384,14 @@ public boolean getHideUnknownBlocks() { public void setHideUnknownBlocks(boolean hideUnknownBlocks) { this.hideUnknownBlocks = hideUnknownBlocks; } + public boolean getFancierTranslucency() { + return fancierTranslucency; + } + + public void setFancierTranslucency(boolean value) { + fancierTranslucency = value; + refresh(); + } public double getTransmissivityCap() { return transmissivityCap; diff --git a/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java b/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java index 672b99ba2e..34395d2128 100644 --- a/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java +++ b/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java @@ -67,6 +67,7 @@ public class AdvancedTab extends ScrollPane implements RenderControlsTab, Initia @FXML private Button mergeRenderDump; @FXML private CheckBox shutdown; @FXML private CheckBox fastFog; + @FXML private CheckBox fancierTranslucency; @FXML private DoubleAdjuster transmissivityCap; @FXML private IntegerAdjuster cacheResolution; @FXML private DoubleAdjuster animationTime; @@ -142,6 +143,13 @@ public PictureExportFormat fromString(String string) { fastFog.setTooltip(new Tooltip("Enable faster fog rendering algorithm.")); fastFog.selectedProperty() .addListener((observable, oldValue, newValue) -> scene.setFastFog(newValue)); + fancierTranslucency.setTooltip(new Tooltip("Enable more sophisticated algorithm for computing color changes through translucent materials.")); + fancierTranslucency.selectedProperty() + .addListener((observable, oldValue, newValue) -> { + scene.setFancierTranslucency(newValue); + transmissivityCap.setVisible(newValue); + transmissivityCap.setManaged(newValue); + }); transmissivityCap.setName("Transmissivity cap"); transmissivityCap.setRange(Scene.MIN_TRANSMISSIVITY_CAP, Scene.MAX_TRANSMISSIVITY_CAP); transmissivityCap.clampBoth(); @@ -309,6 +317,7 @@ public boolean shutdownAfterCompletedRender() { public void update(Scene scene) { outputMode.getSelectionModel().select(scene.getOutputMode()); fastFog.setSelected(scene.fog.fastFog()); + fancierTranslucency.setSelected(scene.getFancierTranslucency()); transmissivityCap.set(scene.getTransmissivityCap()); renderThreads.set(PersistentSettings.getNumThreads()); cpuLoad.set(PersistentSettings.getCPULoad()); diff --git a/chunky/src/res/se/llbit/chunky/ui/render/tabs/AdvancedTab.fxml b/chunky/src/res/se/llbit/chunky/ui/render/tabs/AdvancedTab.fxml index d1b69e5d42..c1f20b8daf 100644 --- a/chunky/src/res/se/llbit/chunky/ui/render/tabs/AdvancedTab.fxml +++ b/chunky/src/res/se/llbit/chunky/ui/render/tabs/AdvancedTab.fxml @@ -23,6 +23,7 @@ + From 0c30d7a7af9e2cf0febeade9182c860f6a4d92e8 Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Fri, 11 Aug 2023 02:42:02 -0500 Subject: [PATCH 2/2] small UI fix --- .../src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java b/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java index 34395d2128..7b1191ca69 100644 --- a/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java +++ b/chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java @@ -150,6 +150,9 @@ public PictureExportFormat fromString(String string) { transmissivityCap.setVisible(newValue); transmissivityCap.setManaged(newValue); }); + boolean tcapVisible = scene != null && scene.getFancierTranslucency(); + transmissivityCap.setVisible(tcapVisible); + transmissivityCap.setManaged(tcapVisible); transmissivityCap.setName("Transmissivity cap"); transmissivityCap.setRange(Scene.MIN_TRANSMISSIVITY_CAP, Scene.MAX_TRANSMISSIVITY_CAP); transmissivityCap.clampBoth();