OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain commits / 399713d

geiss: reachable from GDScript, and a fallback that cannot be mistaken for terrain
DCTerrainGeneratorGeiss wraps the native generator as a Resource with a volume_dir property, following DCTerrainGeneratorMeshSDF. Loading is all or nothing: if any of the eight .vol files is missing the generator stays GPU-disabled and warns, rather than meshing a field that silently differs from the raymarched one. The CPU fallback is now an 8-metre CHECKERBOARD rather than a flat plane. There is no CPU port of this field, so any chunk that falls back is invalid data for the A/B -- and a flat plane reads as "terrain that came out wrong", which would pollute a run quietly. Solid/air cubes read as "the GPU shader is not running", which is the same service dc-terrain's blue noise map already performs when a custom shader fails to compile. An obviously broken fallback is worth more than a plausible one. Verified: the class is registered, instantiates from GDScript, and all eight volumes load from the demo's texture directory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
399713d156dbac3cf5d57d290a05544564b3e0ec
by plankatron <fleeky@gmail.com> · 2026-09-07T22:37:03.000Z

Changed files (4) +86 -4

libdc/include/dc_generator_geiss.h +17 -4
……@@ -15,6 +15,7 @@
1515#include "dc_generator.h"
1616#include "geiss_sdf_glsl.h"
1717
18#include <cmath>
1819#include <cstdint>
1920#include <cstdio>
2021#include <string>
……@@ -55,10 +56,22 @@ public:
5556 return true;
5657 }
5758
58 // CPU fallback. The GPU path is the point of this generator, so this exists
59 // only so a chunk requested while the GPU is unavailable is air rather than
60 // a crash -- it is NOT the field, and a mesh built from it would be wrong.
61 float evaluate(float, float y, float, float) override { return -y; }
59 // CPU fallback -- deliberately a CHECKERBOARD, not terrain.
60 //
61 // The GPU path is the entire point of this generator; there is no CPU port
62 // of the field and a mesh built from this one is invalid data. So it must
63 // be impossible to mistake for the real thing. A flat plane, or anything
64 // smooth, reads as "terrain that came out wrong" and would quietly pollute
65 // an A/B run; 8-metre solid/air cubes read as "the GPU shader is not
66 // running", which is the same service dc-terrain's blue noise map performs
67 // when a custom shader fails to compile.
68 float evaluate(float x, float y, float z, float) override {
69 const float k = 8.0f;
70 const int cx = int(std::floor(x / k));
71 const int cy = int(std::floor(y / k));
72 const int cz = int(std::floor(z / k));
73 return (((cx ^ cy ^ cz) & 1) != 0) ? 1.0f : -1.0f;
74 }
6275
6376private:
6477 // 5-int header (w, h, d, bytes-per-texel, body-bytes), then RGBA half
src/dc_terrain_generator.cpp +35 -0
……@@ -309,4 +309,39 @@ void DCTerrainGeneratorScript::_bind_methods() {
309309 GDVIRTUAL_BIND(_evaluate, "x", "y", "z", "lod_voxel_size")
310310}
311311
312
313
314// ---------------------------------------------------------------------------
315// DCTerrainGeneratorGeiss
316// ---------------------------------------------------------------------------
317
318void DCTerrainGeneratorGeiss::_bind_methods() {
319 ClassDB::bind_method(D_METHOD("set_volume_dir", "path"), &DCTerrainGeneratorGeiss::set_volume_dir);
320 ClassDB::bind_method(D_METHOD("get_volume_dir"), &DCTerrainGeneratorGeiss::get_volume_dir);
321 ClassDB::bind_method(D_METHOD("reload"), &DCTerrainGeneratorGeiss::reload);
322 ClassDB::bind_method(D_METHOD("is_loaded"), &DCTerrainGeneratorGeiss::is_loaded);
323 ADD_PROPERTY(PropertyInfo(Variant::STRING, "volume_dir", PROPERTY_HINT_DIR),
324 "set_volume_dir", "get_volume_dir");
325}
326
327void DCTerrainGeneratorGeiss::set_volume_dir(const String& p_path) {
328 if (volume_dir_ == p_path) return;
329 volume_dir_ = p_path;
330 reload();
331}
332
333bool DCTerrainGeneratorGeiss::reload() {
334 loaded_ = false;
335 if (volume_dir_.is_empty()) return false;
336 // globalize so a res:// path works from the editor as well as an export.
337 const String abs = ProjectSettings::get_singleton()->globalize_path(volume_dir_);
338 loaded_ = impl_.load_volumes(std::string(abs.utf8().get_data()));
339 if (!loaded_) {
340 UtilityFunctions::push_warning(
341 "DCTerrainGeneratorGeiss: could not load the eight .vol files from ", volume_dir_,
342 " -- the generator stays GPU-disabled and will produce only air.");
343 }
344 return loaded_;
345}
346
312347} // namespace godot
src/dc_terrain_generator.h +33 -0
……@@ -8,6 +8,7 @@
88#include "dc_generator.h"
99#include "dc_generator_noise.h"
1010#include "dc_generator_mesh_sdf.h"
11#include "dc_generator_geiss.h"
1112
1213namespace godot {
1314
……@@ -143,6 +144,38 @@ public:
143144 int get_triangle_count() const;
144145};
145146
147// ---------------------------------------------------------------------------
148// DCTerrainGeneratorGeiss — GPU Gems 3 ch.1 (Geiss) terrain
149//
150// Exists to be COMPARED: the same field hyper-tps raymarches, meshed here, so
151// marching and meshing can be measured against each other on identical terrain.
152//
153// GPU ONLY. The field samples eight 16^3 noise volumes, and until volume_dir
154// points at them has_gpu_shader() is false and the generator produces nothing
155// but air -- deliberately, so a half-loaded field can never be mistaken for the
156// real one. Check is_loaded() before trusting a mesh built from it.
157// ---------------------------------------------------------------------------
158class DCTerrainGeneratorGeiss : public DCTerrainGenerator {
159 GDCLASS(DCTerrainGeneratorGeiss, DCTerrainGenerator)
160
161 DCGeneratorGeiss impl_;
162 String volume_dir_;
163 bool loaded_ = false;
164
165protected:
166 static void _bind_methods();
167
168public:
169 DCGenerator* get_native_generator() override { return &impl_; }
170
171 void set_volume_dir(const String& p_path);
172 String get_volume_dir() const { return volume_dir_; }
173
174 // Loads the eight .vol files from volume_dir. All or nothing.
175 bool reload();
176 bool is_loaded() const { return loaded_; }
177};
178
146179// ---------------------------------------------------------------------------
147180// DCTerrainGeneratorScript — calls GDScript virtual _evaluate()
148181// ---------------------------------------------------------------------------
src/register_types.cpp +1 -0
……@@ -16,6 +16,7 @@ void initialize_dc_terrain_module(ModuleInitializationLevel p_level) {
1616 GDREGISTER_CLASS(DCTerrainGeneratorNoise);
1717 GDREGISTER_CLASS(DCTerrainGeneratorMeshSDF);
1818 GDREGISTER_CLASS(DCTerrainGeneratorScript);
19 GDREGISTER_CLASS(DCTerrainGeneratorGeiss);
1920 GDREGISTER_CLASS(DCTerrainGeneratorProcNodes);
2021 GDREGISTER_CLASS(DCTerrain);
2122 GDREGISTER_CLASS(DCTerrainUtils);