Skip to content

Commit

Permalink
Add option to disable "fancier translucency" (#1615)
Browse files Browse the repository at this point in the history
* add toggle for "fancier translucency"

* small UI fix
  • Loading branch information
JustinTimeCuber authored Sep 9, 2023
1 parent 1aeda96 commit e27e28a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 43 deletions.
93 changes: 50 additions & 43 deletions chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,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;
Expand Down Expand Up @@ -425,50 +425,57 @@ private static boolean doTransmission(Ray ray, Ray next, Vector4 cumulativeColor
}

private static void translucentRayColor(Scene scene, Ray ray, Ray next, Vector4 cumulativeColor, 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
Vector4 outputColor = new Vector4(0, 0, 0, 0);
Expand Down
12 changes: 12 additions & 0 deletions chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,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;
Expand Down Expand Up @@ -451,6 +452,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;
Expand Down Expand Up @@ -2643,6 +2645,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);
Expand Down Expand Up @@ -2902,6 +2905,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()) {
Expand Down Expand Up @@ -3410,6 +3414,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;
Expand Down
12 changes: 12 additions & 0 deletions chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,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;
Expand Down Expand Up @@ -155,6 +156,16 @@ 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);
});
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();
Expand Down Expand Up @@ -322,6 +333,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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<Separator prefWidth="200.0" />
<CheckBox fx:id="shutdown" mnemonicParsing="false" text="Shutdown computer when render completes" />
<CheckBox fx:id="fastFog" mnemonicParsing="false" text="Fast fog" />
<CheckBox fx:id="fancierTranslucency" mnemonicParsing="false" text="Fancier translucency" />
<DoubleAdjuster fx:id="transmissivityCap" />
<IntegerAdjuster fx:id="cacheResolution" />
<DoubleAdjuster fx:id="animationTime" />
Expand Down

0 comments on commit e27e28a

Please sign in to comment.