Skip to content

Commit e0ae950

Browse files
committed
Add configurable min ray depth for russian roulette and clamp the probability.
1 parent 6756d86 commit e0ae950

5 files changed

Lines changed: 51 additions & 5 deletions

File tree

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,14 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state,
129129
ray.depth += 1;
130130

131131
// Russian Roulette
132-
if (!firstReflection) {
133-
double q = (1 - Math.max(ray.color.x, Math.max(ray.color.y, ray.color.z)));
134-
if (random.nextDouble() < q) {
132+
if (!firstReflection && ray.depth >= scene.minRayDepth) {
133+
double max = FastMath.max(ray.color.x, FastMath.max(ray.color.y, ray.color.z));
134+
double p = QuickMath.clamp(max, 0.05, 1.0);
135+
if (random.nextDouble() > p) {
136+
ray.color.set(0, 0, 0, 0);
135137
break;
136138
} else {
137-
ray.color.scale(1. / (1. - q));
139+
ray.color.scale(1 / p);
138140
}
139141
}
140142

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ public class Scene implements JsonSerializable {
191191
* Recursive ray depth limit (not including Russian Roulette).
192192
*/
193193
protected int rayDepth = PersistentSettings.getRayDepthDefault();
194+
/**
195+
* Minimum number of ray bounces before Russian Roulette starts.
196+
*/
197+
protected int minRayDepth = PersistentSettings.getMinRayDepthDefault();
194198
protected String worldPath = "";
195199
protected int worldDimension = 0;
196200
protected RenderMode mode = RenderMode.PREVIEW;
@@ -1685,13 +1689,32 @@ public synchronized void setRayDepth(int value) {
16851689
}
16861690
}
16871691

1692+
/**
1693+
* Set the minimum recursive ray depth before Russian Roulette starts
1694+
*/
1695+
public synchronized void setMinRayDepth(int value) {
1696+
value = Math.max(1, value);
1697+
if (minRayDepth != value) {
1698+
minRayDepth = value;
1699+
PersistentSettings.setMinRayDepth(minRayDepth);
1700+
refresh();
1701+
}
1702+
}
1703+
16881704
/**
16891705
* @return Recursive ray depth limit
16901706
*/
16911707
public int getRayDepth() {
16921708
return rayDepth;
16931709
}
16941710

1711+
/**
1712+
* @return Minimum ray depth before Russion Roulette is applied
1713+
*/
1714+
public int getMinRayDepth() {
1715+
return minRayDepth;
1716+
}
1717+
16951718
/**
16961719
* Clear the scene refresh flag
16971720
*/
@@ -1939,6 +1962,7 @@ public synchronized void copyTransients(Scene other) {
19391962
sppTarget = other.sppTarget;
19401963
branchCount = other.branchCount;
19411964
rayDepth = other.rayDepth;
1965+
minRayDepth = other.minRayDepth;
19421966
mode = other.mode;
19431967
pictureExportFormat = other.pictureExportFormat;
19441968
cameraPresets = other.cameraPresets;
@@ -2624,6 +2648,7 @@ public void setUseCustomWaterColor(boolean value) {
26242648
json.add("sppTarget", sppTarget);
26252649
json.add("branchCount", branchCount);
26262650
json.add("rayDepth", rayDepth);
2651+
json.add("minRayDepth", minRayDepth);
26272652
json.add("pathTrace", mode != RenderMode.PREVIEW);
26282653
json.add("dumpFrequency", dumpFrequency);
26292654
json.add("saveSnapshots", saveSnapshots);
@@ -2880,6 +2905,7 @@ public synchronized void importFromJson(JsonObject json) {
28802905
sppTarget = json.get("sppTarget").intValue(sppTarget);
28812906
branchCount = json.get("branchCount").intValue(branchCount);
28822907
rayDepth = json.get("rayDepth").intValue(rayDepth);
2908+
minRayDepth = json.get("minRayDepth").intValue(minRayDepth);
28832909
if (!json.get("pathTrace").isUnknown()) {
28842910
boolean pathTrace = json.get("pathTrace").boolValue(false);
28852911
if (pathTrace) {

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public class AdvancedTab extends ScrollPane implements RenderControlsTab, Initia
6464
@FXML private IntegerAdjuster renderThreads;
6565
@FXML private IntegerAdjuster cpuLoad;
6666
@FXML private IntegerAdjuster rayDepth;
67+
@FXML private IntegerAdjuster minRayDepth;
6768
@FXML private IntegerAdjuster branchCount;
6869
@FXML private Button mergeRenderDump;
6970
@FXML private CheckBox shutdown;
@@ -104,10 +105,15 @@ public void initialize(URL location, ResourceBundle resources) {
104105
controller.getRenderManager().setCPULoad(value);
105106
});
106107
rayDepth.setName("Ray depth");
107-
rayDepth.setTooltip("Sets the minimum recursive ray depth.");
108+
rayDepth.setTooltip("Sets the maximum recursive ray depth.");
108109
rayDepth.setRange(1, 25);
109110
rayDepth.clampMin();
110111
rayDepth.onValueChange(value -> scene.setRayDepth(value));
112+
minRayDepth.setName("Min ray depth");
113+
minRayDepth.setTooltip("Sets the minimum recursive ray depth before Russian Roulette is applied.");
114+
minRayDepth.setRange(1, 25);
115+
minRayDepth.clampMin();
116+
minRayDepth.onValueChange(value -> scene.setMinRayDepth(value));
111117

112118
branchCount.setName("Branch count");
113119
branchCount.setTooltip("Sets the number of rays cast after the first intersection, effectively reusing the first ray that many times." +
@@ -339,6 +345,7 @@ public void update(Scene scene) {
339345
renderThreads.set(PersistentSettings.getNumThreads());
340346
cpuLoad.set(PersistentSettings.getCPULoad());
341347
rayDepth.set(scene.getRayDepth());
348+
minRayDepth.set(scene.getMinRayDepth());
342349
branchCount.set(scene.getBranchCount());
343350
octreeImplementation.getSelectionModel().select(scene.getOctreeImplementation());
344351
bvhMethod.getSelectionModel().select(scene.getBvhImplementation());

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
@@ -18,6 +18,7 @@
1818
<IntegerAdjuster fx:id="cpuLoad" />
1919
<Separator prefWidth="200.0" />
2020
<IntegerAdjuster fx:id="rayDepth" />
21+
<IntegerAdjuster fx:id="minRayDepth" />
2122
<IntegerAdjuster fx:id="branchCount" />
2223
<Separator layoutX="20.0" layoutY="90.0" prefWidth="200.0" />
2324
<Button fx:id="mergeRenderDump" mnemonicParsing="false" text="Merge render dumps" />

lib/src/se/llbit/chunky/PersistentSettings.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public final class PersistentSettings {
6363
public static final double DEFAULT_FOG_BLUE = 1;
6464

6565
public static final int DEFAULT_RAY_DEPTH = 5;
66+
public static final int DEFAULT_MIN_RAY_DEPTH = 3;
6667
public static final int DEFAULT_BRANCH_COUNT = 10;
6768
public static final int DEFAULT_SPP_TARGET = 1000;
6869

@@ -272,13 +273,22 @@ public static void setRayDepth(int rayDepth) {
272273
save();
273274
}
274275

276+
public static void setMinRayDepth(int rayDepth) {
277+
settings.setInt("minRayDepth", rayDepth);
278+
save();
279+
}
280+
275281
/**
276282
* @return the default configured ray depth
277283
*/
278284
public static int getRayDepthDefault() {
279285
return settings.getInt("rayDepth", DEFAULT_RAY_DEPTH);
280286
}
281287

288+
public static int getMinRayDepthDefault() {
289+
return settings.getInt("minRayDepth", DEFAULT_MIN_RAY_DEPTH);
290+
}
291+
282292
public static int get3DCanvasHeight() {
283293
return settings.getInt("3dcanvas.height", DEFAULT_3D_CANVAS_HEIGHT);
284294
}

0 commit comments

Comments
 (0)