| … | … | @@ -15,6 +15,7 @@ |
| 15 | 15 | #include "dc_generator.h" |
| 16 | 16 | #include "geiss_sdf_glsl.h" |
| 17 | 17 | |
| 18 | #include <cmath> | |
| 18 | 19 | #include <cstdint> |
| 19 | 20 | #include <cstdio> |
| 20 | 21 | #include <string> |
| … | … | @@ -55,10 +56,22 @@ public: |
| 55 | 56 | return true; |
| 56 | 57 | } |
| 57 | 58 | |
| 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 | } | |
| 62 | 75 | |
| 63 | 76 | private: |
| 64 | 77 | // 5-int header (w, h, d, bytes-per-texel, body-bytes), then RGBA half |
| … | … | @@ -309,4 +309,39 @@ void DCTerrainGeneratorScript::_bind_methods() { |
| 309 | 309 | GDVIRTUAL_BIND(_evaluate, "x", "y", "z", "lod_voxel_size") |
| 310 | 310 | } |
| 311 | 311 | |
| 312 | ||
| 313 | ||
| 314 | // --------------------------------------------------------------------------- | |
| 315 | // DCTerrainGeneratorGeiss | |
| 316 | // --------------------------------------------------------------------------- | |
| 317 | ||
| 318 | void 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 | ||
| 327 | void DCTerrainGeneratorGeiss::set_volume_dir(const String& p_path) { | |
| 328 | if (volume_dir_ == p_path) return; | |
| 329 | volume_dir_ = p_path; | |
| 330 | reload(); | |
| 331 | } | |
| 332 | ||
| 333 | bool 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 | ||
| 312 | 347 | } // namespace godot |
| … | … | @@ -8,6 +8,7 @@ |
| 8 | 8 | #include "dc_generator.h" |
| 9 | 9 | #include "dc_generator_noise.h" |
| 10 | 10 | #include "dc_generator_mesh_sdf.h" |
| 11 | #include "dc_generator_geiss.h" | |
| 11 | 12 | |
| 12 | 13 | namespace godot { |
| 13 | 14 | |
| … | … | @@ -143,6 +144,38 @@ public: |
| 143 | 144 | int get_triangle_count() const; |
| 144 | 145 | }; |
| 145 | 146 | |
| 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 | // --------------------------------------------------------------------------- | |
| 158 | class DCTerrainGeneratorGeiss : public DCTerrainGenerator { | |
| 159 | GDCLASS(DCTerrainGeneratorGeiss, DCTerrainGenerator) | |
| 160 | ||
| 161 | DCGeneratorGeiss impl_; | |
| 162 | String volume_dir_; | |
| 163 | bool loaded_ = false; | |
| 164 | ||
| 165 | protected: | |
| 166 | static void _bind_methods(); | |
| 167 | ||
| 168 | public: | |
| 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 | ||
| 146 | 179 | // --------------------------------------------------------------------------- |
| 147 | 180 | // DCTerrainGeneratorScript — calls GDScript virtual _evaluate() |
| 148 | 181 | // --------------------------------------------------------------------------- |
| … | … | @@ -16,6 +16,7 @@ void initialize_dc_terrain_module(ModuleInitializationLevel p_level) { |
| 16 | 16 | GDREGISTER_CLASS(DCTerrainGeneratorNoise); |
| 17 | 17 | GDREGISTER_CLASS(DCTerrainGeneratorMeshSDF); |
| 18 | 18 | GDREGISTER_CLASS(DCTerrainGeneratorScript); |
| 19 | GDREGISTER_CLASS(DCTerrainGeneratorGeiss); | |
| 19 | 20 | GDREGISTER_CLASS(DCTerrainGeneratorProcNodes); |
| 20 | 21 | GDREGISTER_CLASS(DCTerrain); |
| 21 | 22 | GDREGISTER_CLASS(DCTerrainUtils); |