diff --git a/chunky/src/java/se/llbit/chunky/renderer/scene/PreviewRayTracer.java b/chunky/src/java/se/llbit/chunky/renderer/scene/PreviewRayTracer.java
index c2446e9c23..dc8719837c 100644
--- a/chunky/src/java/se/llbit/chunky/renderer/scene/PreviewRayTracer.java
+++ b/chunky/src/java/se/llbit/chunky/renderer/scene/PreviewRayTracer.java
@@ -95,6 +95,9 @@ public static boolean nextIntersection(Scene scene, Ray ray) {
if (scene.isWaterPlaneEnabled()) {
hit = waterPlaneIntersection(scene, ray) || hit;
}
+ if (scene.isGroundPlaneEnabled()) {
+ hit |= groundPlaneIntersection(scene, ray);
+ }
if (scene.intersect(ray)) {
// Octree tracer handles updating distance.
return true;
@@ -139,6 +142,30 @@ private static boolean waterPlaneIntersection(Scene scene, Ray ray) {
return false;
}
+ private static boolean groundPlaneIntersection(Scene scene, Ray ray) {
+ double t = (scene.getGroundPlaneHeight() - ray.o.y - scene.origin.y) / ray.d.y;
+ if (scene.getGroundPlaneChunkClip()) {
+ Vector3 pos = new Vector3(ray.o);
+ pos.scaleAdd(t, ray.d);
+ if (scene.isChunkLoaded((int)Math.floor(pos.x), (int)Math.floor(pos.y), (int)Math.floor(pos.z)))
+ return false;
+ }
+ if (ray.d.y < 0 && t > 0 && t < ray.t) {
+ double px = ray.o.x + t * ray.d.x;
+ double pz = ray.o.z + t * ray.d.z;
+
+ ray.u = px - Math.floor(px);
+ ray.v = pz - Math.floor(pz);
+
+ ray.t = t;
+ scene.getPalette().stone.getColor(ray);
+ ray.setNormal(0, 1, 0);
+ ray.setCurrentMaterial(scene.getPalette().stone);
+ return true;
+ }
+ return false;
+ }
+
// Chunk pattern config
private static final double chunkPatternLineWidth = 0.5; // in blocks
private static final double chunkPatternLinePosition = 8 - chunkPatternLineWidth / 2;
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 32b6b7340a..d561d21b4e 100644
--- a/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java
+++ b/chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java
@@ -228,6 +228,11 @@ public class Scene implements JsonSerializable, Refreshable {
protected double waterPlaneHeight = World.SEA_LEVEL;
protected boolean waterPlaneOffsetEnabled = true;
protected boolean waterPlaneChunkClip = true;
+
+ protected boolean groundPlaneEnabled = false;
+ protected double groundPlaneHeight = 0;
+ protected boolean groundPlaneChunkClip = true;
+
protected WaterShader waterShading = new SimplexWaterShader();
public final Fog fog = new Fog(this);
@@ -466,6 +471,11 @@ public synchronized void copyState(Scene other, boolean copyChunks) {
waterPlaneHeight = other.waterPlaneHeight;
waterPlaneOffsetEnabled = other.waterPlaneOffsetEnabled;
waterPlaneChunkClip = other.waterPlaneChunkClip;
+
+ groundPlaneEnabled = other.groundPlaneEnabled;
+ groundPlaneHeight = other.groundPlaneHeight;
+ groundPlaneChunkClip = other.groundPlaneChunkClip;
+
waterShading = other.waterShading.clone();
hideUnknownBlocks = other.hideUnknownBlocks;
@@ -1859,6 +1869,39 @@ public boolean getWaterPlaneChunkClip() {
return waterPlaneChunkClip;
}
+ public void setGroundPlaneEnabled(boolean enabled) {
+ if (enabled != groundPlaneEnabled) {
+ groundPlaneEnabled = enabled;
+ refresh();
+ }
+ }
+
+ public boolean isGroundPlaneEnabled() {
+ return groundPlaneEnabled;
+ }
+
+ public void setGroundPlaneHeight(double height) {
+ if (height != groundPlaneHeight) {
+ groundPlaneHeight = height;
+ refresh();
+ }
+ }
+
+ public double getGroundPlaneHeight() {
+ return groundPlaneHeight;
+ }
+
+ public void setGroundPlaneChunkClip(boolean enabled) {
+ if (enabled != groundPlaneChunkClip) {
+ groundPlaneChunkClip = enabled;
+ refresh();
+ }
+ }
+
+ public boolean getGroundPlaneChunkClip() {
+ return groundPlaneChunkClip;
+ }
+
/**
* @return the dumpFrequency
*/
@@ -2663,10 +2706,16 @@ public void setUseCustomWaterColor(boolean value) {
json.add("fog", fog.toJson());
json.add("biomeColorsEnabled", biomeColors);
json.add("transparentSky", transparentSky);
+
json.add("waterWorldEnabled", waterPlaneEnabled);
json.add("waterWorldHeight", waterPlaneHeight);
json.add("waterWorldHeightOffsetEnabled", waterPlaneOffsetEnabled);
json.add("waterWorldClipEnabled", waterPlaneChunkClip);
+
+ json.add("groundPlaneEnabled", groundPlaneEnabled);
+ json.add("groundPlaneHeight", groundPlaneHeight);
+ json.add("groundPlaneClipEnabled", groundPlaneChunkClip);
+
json.add("hideUnknownBlocks", hideUnknownBlocks);
if (!worldPath.isEmpty()) {
@@ -2972,6 +3021,10 @@ else if(waterShader.equals("SIMPLEX"))
waterPlaneChunkClip = json.get("waterWorldClipEnabled").boolValue(waterPlaneChunkClip);
}
+ groundPlaneEnabled = json.get("groundPlaneEnabled").boolValue(groundPlaneEnabled);
+ groundPlaneHeight = json.get("groundPlaneHeight").doubleValue(groundPlaneHeight);
+ groundPlaneChunkClip = json.get("groundPlaneClipEnabled").boolValue(groundPlaneChunkClip);
+
hideUnknownBlocks = json.get("hideUnknownBlocks").boolValue(hideUnknownBlocks);
materials = json.get("materials").object().copy().toMap();
diff --git a/chunky/src/java/se/llbit/chunky/ui/render/tabs/WaterTab.java b/chunky/src/java/se/llbit/chunky/ui/render/tabs/WaterTab.java
index 34f3a440b9..b9c47703a5 100644
--- a/chunky/src/java/se/llbit/chunky/ui/render/tabs/WaterTab.java
+++ b/chunky/src/java/se/llbit/chunky/ui/render/tabs/WaterTab.java
@@ -52,11 +52,18 @@ public class WaterTab extends ScrollPane implements RenderControlsTab, Initializ
@FXML private CheckBox useCustomWaterColor;
@FXML private LuxColorPicker waterColor;
@FXML private Button saveDefaults;
+
@FXML private CheckBox waterPlaneEnabled;
@FXML private DoubleAdjuster waterPlaneHeight;
@FXML private CheckBox waterPlaneOffsetEnabled;
@FXML private CheckBox waterPlaneClip;
@FXML private TitledPane waterWorldModeDetailsPane;
+
+ @FXML private CheckBox groundPlaneEnabled;
+ @FXML private DoubleAdjuster groundPlaneHeight;
+ @FXML private CheckBox groundPlaneClip;
+ @FXML private TitledPane groundPlaneDetailsPane;
+
@FXML private CheckBox useProceduralWater;
@FXML private IntegerAdjuster proceduralWaterIterations;
@FXML private DoubleAdjuster proceduralWaterFrequency;
@@ -104,6 +111,11 @@ public void update(Scene scene) {
waterPlaneOffsetEnabled.setSelected(scene.isWaterPlaneOffsetEnabled());
waterPlaneClip.setSelected(scene.getWaterPlaneChunkClip());
+ groundPlaneEnabled.setSelected(scene.isGroundPlaneEnabled());
+ groundPlaneHeight.setRange(scene.yClipMin, scene.yClipMax);
+ groundPlaneHeight.set(scene.getGroundPlaneHeight());
+ groundPlaneClip.setSelected(scene.getGroundPlaneChunkClip());
+
if(scene.getWaterShading() instanceof SimplexWaterShader) {
useProceduralWater.setSelected(true);
SimplexWaterShader simplexWaterShader = (SimplexWaterShader) scene.getWaterShading();
@@ -195,6 +207,26 @@ public void initialize(URL location, ResourceBundle resources) {
scene.setWaterPlaneChunkClip(newValue)
);
+ groundPlaneDetailsPane.setVisible(groundPlaneEnabled.isSelected());
+ groundPlaneDetailsPane.setExpanded(groundPlaneEnabled.isSelected());
+ groundPlaneDetailsPane.setManaged(groundPlaneEnabled.isSelected());
+
+ groundPlaneEnabled.setTooltip(new Tooltip("If enabled, an infinite ground fills the scene."));
+ groundPlaneEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
+ scene.setGroundPlaneEnabled(newValue);
+ groundPlaneDetailsPane.setVisible(newValue);
+ groundPlaneDetailsPane.setExpanded(newValue);
+ groundPlaneDetailsPane.setManaged(newValue);
+ });
+
+ groundPlaneHeight.setName("Ground height");
+ groundPlaneHeight.setTooltip("The default ground height is at y=0.");
+ groundPlaneHeight.onValueChange(value -> scene.setGroundPlaneHeight(value));
+
+ groundPlaneClip.selectedProperty().addListener((observable, oldValue, newValue) ->
+ scene.setGroundPlaneChunkClip(newValue)
+ );
+
proceduralWaterDetailsPane.setVisible(useProceduralWater.isSelected());
proceduralWaterDetailsPane.setExpanded(useProceduralWater.isSelected());
proceduralWaterDetailsPane.setManaged(useProceduralWater.isSelected());
diff --git a/chunky/src/res/se/llbit/chunky/ui/render/tabs/WaterTab.fxml b/chunky/src/res/se/llbit/chunky/ui/render/tabs/WaterTab.fxml
index 39ff6f2d90..6d39ea1a70 100644
--- a/chunky/src/res/se/llbit/chunky/ui/render/tabs/WaterTab.fxml
+++ b/chunky/src/res/se/llbit/chunky/ui/render/tabs/WaterTab.fxml
@@ -23,6 +23,7 @@
+
@@ -34,6 +35,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+