Skip to content

Commit e27e28a

Browse files
Add option to disable "fancier translucency" (#1615)
* add toggle for "fancier translucency" * small UI fix
1 parent 1aeda96 commit e27e28a

File tree

4 files changed

+75
-43
lines changed

4 files changed

+75
-43
lines changed

chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add
104104

105105
float pSpecular = currentMat.specular;
106106

107-
double pDiffuse = 1 - Math.sqrt(1 - ray.color.w);
107+
double pDiffuse = scene.fancierTranslucency ? 1 - Math.sqrt(1 - ray.color.w) : ray.color.w;
108108

109109
float n1 = prevMat.ior;
110110
float n2 = currentMat.ior;
@@ -425,50 +425,57 @@ private static boolean doTransmission(Ray ray, Ray next, Vector4 cumulativeColor
425425
}
426426

427427
private static void translucentRayColor(Scene scene, Ray ray, Ray next, Vector4 cumulativeColor, double opacity) {
428-
// Color-based transmission value
429-
double colorTrans = (ray.color.x + ray.color.y + ray.color.z)/3;
430-
// Total amount of light we want to transmit (overall transparency of texture)
431-
double shouldTrans = 1 - opacity;
432-
// Amount of each color to transmit - default to overall transparency if RGB values add to 0 (e.g. regular glass)
433-
Vector3 rgbTrans = new Vector3(shouldTrans, shouldTrans, shouldTrans);
434-
if(colorTrans > 0) {
435-
// Amount to transmit of each color is scaled so the total transmitted amount matches the texture's transparency
436-
rgbTrans.set(ray.color.toVec3());
437-
rgbTrans.scale(shouldTrans / colorTrans);
438-
}
439-
double transmissivityCap = scene.transmissivityCap;
440-
// Determine the color with the highest transmissivity
441-
double maxTrans = Math.max(rgbTrans.x, Math.max(rgbTrans.y, rgbTrans.z));
442-
if(maxTrans > transmissivityCap) {
443-
if (maxTrans == rgbTrans.x) {
444-
// Give excess transmission from red to green and blue
445-
double gTransNew = reassignTransmissivity(rgbTrans.x, rgbTrans.y, rgbTrans.z, shouldTrans, transmissivityCap);
446-
rgbTrans.z = reassignTransmissivity(rgbTrans.x, rgbTrans.z, rgbTrans.y, shouldTrans, transmissivityCap);
447-
rgbTrans.y = gTransNew;
448-
rgbTrans.x = transmissivityCap;
449-
} else if (maxTrans == rgbTrans.y) {
450-
// Give excess transmission from green to red and blue
451-
double rTransNew = reassignTransmissivity(rgbTrans.y, rgbTrans.x, rgbTrans.z, shouldTrans, transmissivityCap);
452-
rgbTrans.z = reassignTransmissivity(rgbTrans.y, rgbTrans.z, rgbTrans.x, shouldTrans, transmissivityCap);
453-
rgbTrans.x = rTransNew;
454-
rgbTrans.y = transmissivityCap;
455-
} else if (maxTrans == rgbTrans.z) {
456-
// Give excess transmission from blue to green and red
457-
double gTransNew = reassignTransmissivity(rgbTrans.z, rgbTrans.y, rgbTrans.x, shouldTrans, transmissivityCap);
458-
rgbTrans.x = reassignTransmissivity(rgbTrans.z, rgbTrans.x, rgbTrans.y, shouldTrans, transmissivityCap);
459-
rgbTrans.y = gTransNew;
460-
rgbTrans.z = transmissivityCap;
428+
Vector3 rgbTrans;
429+
if(scene.fancierTranslucency) {
430+
// Color-based transmission value
431+
double colorTrans = (ray.color.x + ray.color.y + ray.color.z) / 3;
432+
// Total amount of light we want to transmit (overall transparency of texture)
433+
double shouldTrans = 1 - opacity;
434+
// Amount of each color to transmit - default to overall transparency if RGB values add to 0 (e.g. regular glass)
435+
rgbTrans = new Vector3(shouldTrans, shouldTrans, shouldTrans);
436+
if (colorTrans > 0) {
437+
// Amount to transmit of each color is scaled so the total transmitted amount matches the texture's transparency
438+
rgbTrans.set(ray.color.toVec3());
439+
rgbTrans.scale(shouldTrans / colorTrans);
461440
}
462-
}
463-
// Don't need to check for energy gain if transmissivity cap is 1
464-
if(transmissivityCap > 1) {
465-
double currentEnergy = rgbTrans.x * next.color.x + rgbTrans.y * next.color.y + rgbTrans.z * next.color.z;
466-
double nextEnergy = next.color.x + next.color.y + next.color.z;
467-
double energyRatio = nextEnergy / currentEnergy;
468-
// Normalize if there is net energy gain across all channels (more likely for higher transmissivityCap combined with high-saturation light source)
469-
if(energyRatio < 1) {
470-
rgbTrans.scale(energyRatio);
441+
double transmissivityCap = scene.transmissivityCap;
442+
// Determine the color with the highest transmissivity
443+
double maxTrans = Math.max(rgbTrans.x, Math.max(rgbTrans.y, rgbTrans.z));
444+
if (maxTrans > transmissivityCap) {
445+
if (maxTrans == rgbTrans.x) {
446+
// Give excess transmission from red to green and blue
447+
double gTransNew = reassignTransmissivity(rgbTrans.x, rgbTrans.y, rgbTrans.z, shouldTrans, transmissivityCap);
448+
rgbTrans.z = reassignTransmissivity(rgbTrans.x, rgbTrans.z, rgbTrans.y, shouldTrans, transmissivityCap);
449+
rgbTrans.y = gTransNew;
450+
rgbTrans.x = transmissivityCap;
451+
} else if (maxTrans == rgbTrans.y) {
452+
// Give excess transmission from green to red and blue
453+
double rTransNew = reassignTransmissivity(rgbTrans.y, rgbTrans.x, rgbTrans.z, shouldTrans, transmissivityCap);
454+
rgbTrans.z = reassignTransmissivity(rgbTrans.y, rgbTrans.z, rgbTrans.x, shouldTrans, transmissivityCap);
455+
rgbTrans.x = rTransNew;
456+
rgbTrans.y = transmissivityCap;
457+
} else if (maxTrans == rgbTrans.z) {
458+
// Give excess transmission from blue to green and red
459+
double gTransNew = reassignTransmissivity(rgbTrans.z, rgbTrans.y, rgbTrans.x, shouldTrans, transmissivityCap);
460+
rgbTrans.x = reassignTransmissivity(rgbTrans.z, rgbTrans.x, rgbTrans.y, shouldTrans, transmissivityCap);
461+
rgbTrans.y = gTransNew;
462+
rgbTrans.z = transmissivityCap;
463+
}
471464
}
465+
// Don't need to check for energy gain if transmissivity cap is 1
466+
if (transmissivityCap > 1) {
467+
double currentEnergy = rgbTrans.x * next.color.x + rgbTrans.y * next.color.y + rgbTrans.z * next.color.z;
468+
double nextEnergy = next.color.x + next.color.y + next.color.z;
469+
double energyRatio = nextEnergy / currentEnergy;
470+
// Normalize if there is net energy gain across all channels (more likely for higher transmissivityCap combined with high-saturation light source)
471+
if (energyRatio < 1) {
472+
rgbTrans.scale(energyRatio);
473+
}
474+
}
475+
} else {
476+
// Old method (see https://github.com/chunky-dev/chunky/pull/1513)
477+
rgbTrans = new Vector3(1 - opacity, 1 - opacity, 1 - opacity);
478+
rgbTrans.scaleAdd(opacity, ray.color.toVec3());
472479
}
473480
// Scale color based on next ray
474481
Vector4 outputColor = new Vector4(0, 0, 0, 0);

chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ public class Scene implements JsonSerializable, Refreshable {
211211
protected boolean emittersEnabled = DEFAULT_EMITTERS_ENABLED;
212212
protected double emitterIntensity = DEFAULT_EMITTER_INTENSITY;
213213
protected EmitterSamplingStrategy emitterSamplingStrategy = EmitterSamplingStrategy.NONE;
214+
protected boolean fancierTranslucency = true;
214215
protected double transmissivityCap = DEFAULT_TRANSMISSIVITY_CAP;
215216

216217
protected SunSamplingStrategy sunSamplingStrategy = SunSamplingStrategy.FAST;
@@ -451,6 +452,7 @@ public synchronized void copyState(Scene other, boolean copyChunks) {
451452
emitterIntensity = other.emitterIntensity;
452453
emitterSamplingStrategy = other.emitterSamplingStrategy;
453454
preventNormalEmitterWithSampling = other.preventNormalEmitterWithSampling;
455+
fancierTranslucency = other.fancierTranslucency;
454456
transmissivityCap = other.transmissivityCap;
455457
transparentSky = other.transparentSky;
456458
yClipMin = other.yClipMin;
@@ -2643,6 +2645,7 @@ public void setUseCustomWaterColor(boolean value) {
26432645
json.add("saveSnapshots", saveSnapshots);
26442646
json.add("emittersEnabled", emittersEnabled);
26452647
json.add("emitterIntensity", emitterIntensity);
2648+
json.add("fancierTranslucency", fancierTranslucency);
26462649
json.add("transmissivityCap", transmissivityCap);
26472650
json.add("sunSamplingStrategy", sunSamplingStrategy.getId());
26482651
json.add("stillWater", stillWater);
@@ -2902,6 +2905,7 @@ public synchronized void importFromJson(JsonObject json) {
29022905
saveSnapshots = json.get("saveSnapshots").boolValue(saveSnapshots);
29032906
emittersEnabled = json.get("emittersEnabled").boolValue(emittersEnabled);
29042907
emitterIntensity = json.get("emitterIntensity").doubleValue(emitterIntensity);
2908+
fancierTranslucency = json.get("fancierTranslucency").boolValue(fancierTranslucency);
29052909
transmissivityCap = json.get("transmissivityCap").doubleValue(transmissivityCap);
29062910

29072911
if (json.get("sunSamplingStrategy").isUnknown()) {
@@ -3410,6 +3414,14 @@ public boolean getHideUnknownBlocks() {
34103414
public void setHideUnknownBlocks(boolean hideUnknownBlocks) {
34113415
this.hideUnknownBlocks = hideUnknownBlocks;
34123416
}
3417+
public boolean getFancierTranslucency() {
3418+
return fancierTranslucency;
3419+
}
3420+
3421+
public void setFancierTranslucency(boolean value) {
3422+
fancierTranslucency = value;
3423+
refresh();
3424+
}
34133425

34143426
public double getTransmissivityCap() {
34153427
return transmissivityCap;

chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public class AdvancedTab extends ScrollPane implements RenderControlsTab, Initia
6868
@FXML private Button mergeRenderDump;
6969
@FXML private CheckBox shutdown;
7070
@FXML private CheckBox fastFog;
71+
@FXML private CheckBox fancierTranslucency;
7172
@FXML private DoubleAdjuster transmissivityCap;
7273
@FXML private IntegerAdjuster cacheResolution;
7374
@FXML private DoubleAdjuster animationTime;
@@ -155,6 +156,16 @@ public PictureExportFormat fromString(String string) {
155156
fastFog.setTooltip(new Tooltip("Enable faster fog rendering algorithm."));
156157
fastFog.selectedProperty()
157158
.addListener((observable, oldValue, newValue) -> scene.setFastFog(newValue));
159+
fancierTranslucency.setTooltip(new Tooltip("Enable more sophisticated algorithm for computing color changes through translucent materials."));
160+
fancierTranslucency.selectedProperty()
161+
.addListener((observable, oldValue, newValue) -> {
162+
scene.setFancierTranslucency(newValue);
163+
transmissivityCap.setVisible(newValue);
164+
transmissivityCap.setManaged(newValue);
165+
});
166+
boolean tcapVisible = scene != null && scene.getFancierTranslucency();
167+
transmissivityCap.setVisible(tcapVisible);
168+
transmissivityCap.setManaged(tcapVisible);
158169
transmissivityCap.setName("Transmissivity cap");
159170
transmissivityCap.setRange(Scene.MIN_TRANSMISSIVITY_CAP, Scene.MAX_TRANSMISSIVITY_CAP);
160171
transmissivityCap.clampBoth();
@@ -322,6 +333,7 @@ public boolean shutdownAfterCompletedRender() {
322333
public void update(Scene scene) {
323334
outputMode.getSelectionModel().select(scene.getOutputMode());
324335
fastFog.setSelected(scene.fog.fastFog());
336+
fancierTranslucency.setSelected(scene.getFancierTranslucency());
325337
transmissivityCap.set(scene.getTransmissivityCap());
326338
renderThreads.set(PersistentSettings.getNumThreads());
327339
cpuLoad.set(PersistentSettings.getCPULoad());

chunky/src/res/se/llbit/chunky/ui/render/tabs/AdvancedTab.fxml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<Separator prefWidth="200.0" />
2525
<CheckBox fx:id="shutdown" mnemonicParsing="false" text="Shutdown computer when render completes" />
2626
<CheckBox fx:id="fastFog" mnemonicParsing="false" text="Fast fog" />
27+
<CheckBox fx:id="fancierTranslucency" mnemonicParsing="false" text="Fancier translucency" />
2728
<DoubleAdjuster fx:id="transmissivityCap" />
2829
<IntegerAdjuster fx:id="cacheResolution" />
2930
<DoubleAdjuster fx:id="animationTime" />

0 commit comments

Comments
 (0)