Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to disable "fancier translucency" #1615

Merged
merged 3 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2626,6 +2628,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 @@ -2885,6 +2888,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 @@ -3393,6 +3397,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