| … | … | @@ -21,6 +21,99 @@ |
| 21 | 21 | namespace godot { |
| 22 | 22 | |
| 23 | 23 | void DCTerrainGeneratorProcNodes::_bind_methods() { |
| 24 | ClassDB::bind_method(D_METHOD("set_mountain_scale", "value"), &DCTerrainGeneratorProcNodes::set_mountain_scale); |
| 25 | ClassDB::bind_method(D_METHOD("get_mountain_scale"), &DCTerrainGeneratorProcNodes::get_mountain_scale); |
| 26 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mountain_scale"), "set_mountain_scale", "get_mountain_scale"); |
| 27 | ClassDB::bind_method(D_METHOD("set_mountain_height", "value"), &DCTerrainGeneratorProcNodes::set_mountain_height); |
| 28 | ClassDB::bind_method(D_METHOD("get_mountain_height"), &DCTerrainGeneratorProcNodes::get_mountain_height); |
| 29 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mountain_height"), "set_mountain_height", "get_mountain_height"); |
| 30 | ClassDB::bind_method(D_METHOD("set_mountain_gain", "value"), &DCTerrainGeneratorProcNodes::set_mountain_gain); |
| 31 | ClassDB::bind_method(D_METHOD("get_mountain_gain"), &DCTerrainGeneratorProcNodes::get_mountain_gain); |
| 32 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mountain_gain"), "set_mountain_gain", "get_mountain_gain"); |
| 33 | ClassDB::bind_method(D_METHOD("set_mountain_variance", "value"), &DCTerrainGeneratorProcNodes::set_mountain_variance); |
| 34 | ClassDB::bind_method(D_METHOD("get_mountain_variance"), &DCTerrainGeneratorProcNodes::get_mountain_variance); |
| 35 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mountain_variance"), "set_mountain_variance", "get_mountain_variance"); |
| 36 | ClassDB::bind_method(D_METHOD("set_relief_scale", "value"), &DCTerrainGeneratorProcNodes::set_relief_scale); |
| 37 | ClassDB::bind_method(D_METHOD("get_relief_scale"), &DCTerrainGeneratorProcNodes::get_relief_scale); |
| 38 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "relief_scale"), "set_relief_scale", "get_relief_scale"); |
| 39 | ClassDB::bind_method(D_METHOD("set_relief_floor", "value"), &DCTerrainGeneratorProcNodes::set_relief_floor); |
| 40 | ClassDB::bind_method(D_METHOD("get_relief_floor"), &DCTerrainGeneratorProcNodes::get_relief_floor); |
| 41 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "relief_floor"), "set_relief_floor", "get_relief_floor"); |
| 42 | ClassDB::bind_method(D_METHOD("set_detail_scale", "value"), &DCTerrainGeneratorProcNodes::set_detail_scale); |
| 43 | ClassDB::bind_method(D_METHOD("get_detail_scale"), &DCTerrainGeneratorProcNodes::get_detail_scale); |
| 44 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_scale"), "set_detail_scale", "get_detail_scale"); |
| 45 | ClassDB::bind_method(D_METHOD("set_detail_height", "value"), &DCTerrainGeneratorProcNodes::set_detail_height); |
| 46 | ClassDB::bind_method(D_METHOD("get_detail_height"), &DCTerrainGeneratorProcNodes::get_detail_height); |
| 47 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_height"), "set_detail_height", "get_detail_height"); |
| 48 | ClassDB::bind_method(D_METHOD("set_detail_gain", "value"), &DCTerrainGeneratorProcNodes::set_detail_gain); |
| 49 | ClassDB::bind_method(D_METHOD("get_detail_gain"), &DCTerrainGeneratorProcNodes::get_detail_gain); |
| 50 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_gain"), "set_detail_gain", "get_detail_gain"); |
| 51 | ClassDB::bind_method(D_METHOD("set_noise_lacunarity", "value"), &DCTerrainGeneratorProcNodes::set_noise_lacunarity); |
| 52 | ClassDB::bind_method(D_METHOD("get_noise_lacunarity"), &DCTerrainGeneratorProcNodes::get_noise_lacunarity); |
| 53 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "noise_lacunarity"), "set_noise_lacunarity", "get_noise_lacunarity"); |
| 54 | ClassDB::bind_method(D_METHOD("set_erosion_scale", "value"), &DCTerrainGeneratorProcNodes::set_erosion_scale); |
| 55 | ClassDB::bind_method(D_METHOD("get_erosion_scale"), &DCTerrainGeneratorProcNodes::get_erosion_scale); |
| 56 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "erosion_scale"), "set_erosion_scale", "get_erosion_scale"); |
| 57 | ClassDB::bind_method(D_METHOD("set_input_height_amplitude", "value"), &DCTerrainGeneratorProcNodes::set_input_height_amplitude); |
| 58 | ClassDB::bind_method(D_METHOD("get_input_height_amplitude"), &DCTerrainGeneratorProcNodes::get_input_height_amplitude); |
| 59 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "input_height_amplitude"), "set_input_height_amplitude", "get_input_height_amplitude"); |
| 60 | ClassDB::bind_method(D_METHOD("set_octave_lacunarity", "value"), &DCTerrainGeneratorProcNodes::set_octave_lacunarity); |
| 61 | ClassDB::bind_method(D_METHOD("get_octave_lacunarity"), &DCTerrainGeneratorProcNodes::get_octave_lacunarity); |
| 62 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "octave_lacunarity"), "set_octave_lacunarity", "get_octave_lacunarity"); |
| 63 | ClassDB::bind_method(D_METHOD("set_gully_depth", "value"), &DCTerrainGeneratorProcNodes::set_gully_depth); |
| 64 | ClassDB::bind_method(D_METHOD("get_gully_depth"), &DCTerrainGeneratorProcNodes::get_gully_depth); |
| 65 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gully_depth"), "set_gully_depth", "get_gully_depth"); |
| 66 | ClassDB::bind_method(D_METHOD("set_fine_gully_slope_restriction", "value"), &DCTerrainGeneratorProcNodes::set_fine_gully_slope_restriction); |
| 67 | ClassDB::bind_method(D_METHOD("get_fine_gully_slope_restriction"), &DCTerrainGeneratorProcNodes::get_fine_gully_slope_restriction); |
| 68 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fine_gully_slope_restriction"), "set_fine_gully_slope_restriction", "get_fine_gully_slope_restriction"); |
| 69 | ClassDB::bind_method(D_METHOD("set_gully_normalize_threshold", "value"), &DCTerrainGeneratorProcNodes::set_gully_normalize_threshold); |
| 70 | ClassDB::bind_method(D_METHOD("get_gully_normalize_threshold"), &DCTerrainGeneratorProcNodes::get_gully_normalize_threshold); |
| 71 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gully_normalize_threshold"), "set_gully_normalize_threshold", "get_gully_normalize_threshold"); |
| 72 | ClassDB::bind_method(D_METHOD("set_height_offset", "value"), &DCTerrainGeneratorProcNodes::set_height_offset); |
| 73 | ClassDB::bind_method(D_METHOD("get_height_offset"), &DCTerrainGeneratorProcNodes::get_height_offset); |
| 74 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_offset"), "set_height_offset", "get_height_offset"); |
| 75 | ClassDB::bind_method(D_METHOD("set_height_offset_follows_altitude", "value"), &DCTerrainGeneratorProcNodes::set_height_offset_follows_altitude); |
| 76 | ClassDB::bind_method(D_METHOD("get_height_offset_follows_altitude"), &DCTerrainGeneratorProcNodes::get_height_offset_follows_altitude); |
| 77 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_offset_follows_altitude"), "set_height_offset_follows_altitude", "get_height_offset_follows_altitude"); |
| 78 | ClassDB::bind_method(D_METHOD("set_crease_rounding", "value"), &DCTerrainGeneratorProcNodes::set_crease_rounding); |
| 79 | ClassDB::bind_method(D_METHOD("get_crease_rounding"), &DCTerrainGeneratorProcNodes::get_crease_rounding); |
| 80 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "crease_rounding"), "set_crease_rounding", "get_crease_rounding"); |
| 81 | ClassDB::bind_method(D_METHOD("set_ridge_rounding", "value"), &DCTerrainGeneratorProcNodes::set_ridge_rounding); |
| 82 | ClassDB::bind_method(D_METHOD("get_ridge_rounding"), &DCTerrainGeneratorProcNodes::get_ridge_rounding); |
| 83 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ridge_rounding"), "set_ridge_rounding", "get_ridge_rounding"); |
| 84 | ClassDB::bind_method(D_METHOD("set_input_feature_rounding", "value"), &DCTerrainGeneratorProcNodes::set_input_feature_rounding); |
| 85 | ClassDB::bind_method(D_METHOD("get_input_feature_rounding"), &DCTerrainGeneratorProcNodes::get_input_feature_rounding); |
| 86 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "input_feature_rounding"), "set_input_feature_rounding", "get_input_feature_rounding"); |
| 87 | ClassDB::bind_method(D_METHOD("set_rounding_per_octave", "value"), &DCTerrainGeneratorProcNodes::set_rounding_per_octave); |
| 88 | ClassDB::bind_method(D_METHOD("get_rounding_per_octave"), &DCTerrainGeneratorProcNodes::get_rounding_per_octave); |
| 89 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rounding_per_octave"), "set_rounding_per_octave", "get_rounding_per_octave"); |
| 90 | ClassDB::bind_method(D_METHOD("set_gully_onset_slope", "value"), &DCTerrainGeneratorProcNodes::set_gully_onset_slope); |
| 91 | ClassDB::bind_method(D_METHOD("get_gully_onset_slope"), &DCTerrainGeneratorProcNodes::get_gully_onset_slope); |
| 92 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gully_onset_slope"), "set_gully_onset_slope", "get_gully_onset_slope"); |
| 93 | ClassDB::bind_method(D_METHOD("set_octave_onset_slope", "value"), &DCTerrainGeneratorProcNodes::set_octave_onset_slope); |
| 94 | ClassDB::bind_method(D_METHOD("get_octave_onset_slope"), &DCTerrainGeneratorProcNodes::get_octave_onset_slope); |
| 95 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "octave_onset_slope"), "set_octave_onset_slope", "get_octave_onset_slope"); |
| 96 | ClassDB::bind_method(D_METHOD("set_ridge_onset_slope", "value"), &DCTerrainGeneratorProcNodes::set_ridge_onset_slope); |
| 97 | ClassDB::bind_method(D_METHOD("get_ridge_onset_slope"), &DCTerrainGeneratorProcNodes::get_ridge_onset_slope); |
| 98 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ridge_onset_slope"), "set_ridge_onset_slope", "get_ridge_onset_slope"); |
| 99 | ClassDB::bind_method(D_METHOD("set_ridge_octave_onset", "value"), &DCTerrainGeneratorProcNodes::set_ridge_octave_onset); |
| 100 | ClassDB::bind_method(D_METHOD("get_ridge_octave_onset"), &DCTerrainGeneratorProcNodes::get_ridge_octave_onset); |
| 101 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ridge_octave_onset"), "set_ridge_octave_onset", "get_ridge_octave_onset"); |
| 102 | ClassDB::bind_method(D_METHOD("set_assumed_slope", "value"), &DCTerrainGeneratorProcNodes::set_assumed_slope); |
| 103 | ClassDB::bind_method(D_METHOD("get_assumed_slope"), &DCTerrainGeneratorProcNodes::get_assumed_slope); |
| 104 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "assumed_slope"), "set_assumed_slope", "get_assumed_slope"); |
| 105 | ClassDB::bind_method(D_METHOD("set_assumed_slope_mix", "value"), &DCTerrainGeneratorProcNodes::set_assumed_slope_mix); |
| 106 | ClassDB::bind_method(D_METHOD("get_assumed_slope_mix"), &DCTerrainGeneratorProcNodes::get_assumed_slope_mix); |
| 107 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "assumed_slope_mix"), "set_assumed_slope_mix", "get_assumed_slope_mix"); |
| 108 | ClassDB::bind_method(D_METHOD("set_mountain_octaves", "value"), &DCTerrainGeneratorProcNodes::set_mountain_octaves); |
| 109 | ClassDB::bind_method(D_METHOD("get_mountain_octaves"), &DCTerrainGeneratorProcNodes::get_mountain_octaves); |
| 110 | ADD_PROPERTY(PropertyInfo(Variant::INT, "mountain_octaves"), "set_mountain_octaves", "get_mountain_octaves"); |
| 111 | ClassDB::bind_method(D_METHOD("set_detail_octaves", "value"), &DCTerrainGeneratorProcNodes::set_detail_octaves); |
| 112 | ClassDB::bind_method(D_METHOD("get_detail_octaves"), &DCTerrainGeneratorProcNodes::get_detail_octaves); |
| 113 | ADD_PROPERTY(PropertyInfo(Variant::INT, "detail_octaves"), "set_detail_octaves", "get_detail_octaves"); |
| 114 | ClassDB::bind_method(D_METHOD("set_lookdev_wrapper", "value"), &DCTerrainGeneratorProcNodes::set_lookdev_wrapper); |
| 115 | ClassDB::bind_method(D_METHOD("get_lookdev_wrapper"), &DCTerrainGeneratorProcNodes::get_lookdev_wrapper); |
| 116 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lookdev_wrapper"), "set_lookdev_wrapper", "get_lookdev_wrapper"); |
| 24 | 117 | ClassDB::bind_method(D_METHOD("set_graph", "graph"), &DCTerrainGeneratorProcNodes::set_graph); |
| 25 | 118 | ClassDB::bind_method(D_METHOD("get_graph"), &DCTerrainGeneratorProcNodes::get_graph); |
| 26 | 119 | ClassDB::bind_method(D_METHOD("set_terrain_height", "height"), &DCTerrainGeneratorProcNodes::set_terrain_height); |
| … | … | @@ -70,6 +163,223 @@ void DCTerrainGeneratorProcNodes::_bind_methods() { |
| 70 | 163 | "set_height_space_sqrt", "get_height_space_sqrt"); |
| 71 | 164 | } |
| 72 | 165 | |
| 166 | void DCTerrainGeneratorProcNodes::set_mountain_scale(float p_val) { |
| 167 | if (mountain_scale_ == p_val) return; |
| 168 | mountain_scale_ = p_val; |
| 169 | _recompile_glsl(); |
| 170 | emit_changed(); |
| 171 | } |
| 172 | |
| 173 | void DCTerrainGeneratorProcNodes::set_mountain_height(float p_val) { |
| 174 | if (mountain_height_ == p_val) return; |
| 175 | mountain_height_ = p_val; |
| 176 | _recompile_glsl(); |
| 177 | emit_changed(); |
| 178 | } |
| 179 | |
| 180 | void DCTerrainGeneratorProcNodes::set_mountain_gain(float p_val) { |
| 181 | if (mountain_gain_ == p_val) return; |
| 182 | mountain_gain_ = p_val; |
| 183 | _recompile_glsl(); |
| 184 | emit_changed(); |
| 185 | } |
| 186 | |
| 187 | void DCTerrainGeneratorProcNodes::set_mountain_variance(float p_val) { |
| 188 | if (mountain_variance_ == p_val) return; |
| 189 | mountain_variance_ = p_val; |
| 190 | _recompile_glsl(); |
| 191 | emit_changed(); |
| 192 | } |
| 193 | |
| 194 | void DCTerrainGeneratorProcNodes::set_relief_scale(float p_val) { |
| 195 | if (relief_scale_ == p_val) return; |
| 196 | relief_scale_ = p_val; |
| 197 | _recompile_glsl(); |
| 198 | emit_changed(); |
| 199 | } |
| 200 | |
| 201 | void DCTerrainGeneratorProcNodes::set_relief_floor(float p_val) { |
| 202 | if (relief_floor_ == p_val) return; |
| 203 | relief_floor_ = p_val; |
| 204 | _recompile_glsl(); |
| 205 | emit_changed(); |
| 206 | } |
| 207 | |
| 208 | void DCTerrainGeneratorProcNodes::set_detail_scale(float p_val) { |
| 209 | if (detail_scale_ == p_val) return; |
| 210 | detail_scale_ = p_val; |
| 211 | _recompile_glsl(); |
| 212 | emit_changed(); |
| 213 | } |
| 214 | |
| 215 | void DCTerrainGeneratorProcNodes::set_detail_height(float p_val) { |
| 216 | if (detail_height_ == p_val) return; |
| 217 | detail_height_ = p_val; |
| 218 | _recompile_glsl(); |
| 219 | emit_changed(); |
| 220 | } |
| 221 | |
| 222 | void DCTerrainGeneratorProcNodes::set_detail_gain(float p_val) { |
| 223 | if (detail_gain_ == p_val) return; |
| 224 | detail_gain_ = p_val; |
| 225 | _recompile_glsl(); |
| 226 | emit_changed(); |
| 227 | } |
| 228 | |
| 229 | void DCTerrainGeneratorProcNodes::set_noise_lacunarity(float p_val) { |
| 230 | if (noise_lacunarity_ == p_val) return; |
| 231 | noise_lacunarity_ = p_val; |
| 232 | _recompile_glsl(); |
| 233 | emit_changed(); |
| 234 | } |
| 235 | |
| 236 | void DCTerrainGeneratorProcNodes::set_erosion_scale(float p_val) { |
| 237 | if (erosion_scale_ == p_val) return; |
| 238 | erosion_scale_ = p_val; |
| 239 | _recompile_glsl(); |
| 240 | emit_changed(); |
| 241 | } |
| 242 | |
| 243 | void DCTerrainGeneratorProcNodes::set_input_height_amplitude(float p_val) { |
| 244 | if (input_height_amplitude_ == p_val) return; |
| 245 | input_height_amplitude_ = p_val; |
| 246 | _recompile_glsl(); |
| 247 | emit_changed(); |
| 248 | } |
| 249 | |
| 250 | void DCTerrainGeneratorProcNodes::set_octave_lacunarity(float p_val) { |
| 251 | if (octave_lacunarity_ == p_val) return; |
| 252 | octave_lacunarity_ = p_val; |
| 253 | _recompile_glsl(); |
| 254 | emit_changed(); |
| 255 | } |
| 256 | |
| 257 | void DCTerrainGeneratorProcNodes::set_gully_depth(float p_val) { |
| 258 | if (gully_depth_ == p_val) return; |
| 259 | gully_depth_ = p_val; |
| 260 | _recompile_glsl(); |
| 261 | emit_changed(); |
| 262 | } |
| 263 | |
| 264 | void DCTerrainGeneratorProcNodes::set_fine_gully_slope_restriction(float p_val) { |
| 265 | if (fine_gully_slope_restriction_ == p_val) return; |
| 266 | fine_gully_slope_restriction_ = p_val; |
| 267 | _recompile_glsl(); |
| 268 | emit_changed(); |
| 269 | } |
| 270 | |
| 271 | void DCTerrainGeneratorProcNodes::set_gully_normalize_threshold(float p_val) { |
| 272 | if (gully_normalize_threshold_ == p_val) return; |
| 273 | gully_normalize_threshold_ = p_val; |
| 274 | _recompile_glsl(); |
| 275 | emit_changed(); |
| 276 | } |
| 277 | |
| 278 | void DCTerrainGeneratorProcNodes::set_height_offset(float p_val) { |
| 279 | if (height_offset_ == p_val) return; |
| 280 | height_offset_ = p_val; |
| 281 | _recompile_glsl(); |
| 282 | emit_changed(); |
| 283 | } |
| 284 | |
| 285 | void DCTerrainGeneratorProcNodes::set_height_offset_follows_altitude(float p_val) { |
| 286 | if (height_offset_follows_altitude_ == p_val) return; |
| 287 | height_offset_follows_altitude_ = p_val; |
| 288 | _recompile_glsl(); |
| 289 | emit_changed(); |
| 290 | } |
| 291 | |
| 292 | void DCTerrainGeneratorProcNodes::set_crease_rounding(float p_val) { |
| 293 | if (crease_rounding_ == p_val) return; |
| 294 | crease_rounding_ = p_val; |
| 295 | _recompile_glsl(); |
| 296 | emit_changed(); |
| 297 | } |
| 298 | |
| 299 | void DCTerrainGeneratorProcNodes::set_ridge_rounding(float p_val) { |
| 300 | if (ridge_rounding_ == p_val) return; |
| 301 | ridge_rounding_ = p_val; |
| 302 | _recompile_glsl(); |
| 303 | emit_changed(); |
| 304 | } |
| 305 | |
| 306 | void DCTerrainGeneratorProcNodes::set_input_feature_rounding(float p_val) { |
| 307 | if (input_feature_rounding_ == p_val) return; |
| 308 | input_feature_rounding_ = p_val; |
| 309 | _recompile_glsl(); |
| 310 | emit_changed(); |
| 311 | } |
| 312 | |
| 313 | void DCTerrainGeneratorProcNodes::set_rounding_per_octave(float p_val) { |
| 314 | if (rounding_per_octave_ == p_val) return; |
| 315 | rounding_per_octave_ = p_val; |
| 316 | _recompile_glsl(); |
| 317 | emit_changed(); |
| 318 | } |
| 319 | |
| 320 | void DCTerrainGeneratorProcNodes::set_gully_onset_slope(float p_val) { |
| 321 | if (gully_onset_slope_ == p_val) return; |
| 322 | gully_onset_slope_ = p_val; |
| 323 | _recompile_glsl(); |
| 324 | emit_changed(); |
| 325 | } |
| 326 | |
| 327 | void DCTerrainGeneratorProcNodes::set_octave_onset_slope(float p_val) { |
| 328 | if (octave_onset_slope_ == p_val) return; |
| 329 | octave_onset_slope_ = p_val; |
| 330 | _recompile_glsl(); |
| 331 | emit_changed(); |
| 332 | } |
| 333 | |
| 334 | void DCTerrainGeneratorProcNodes::set_ridge_onset_slope(float p_val) { |
| 335 | if (ridge_onset_slope_ == p_val) return; |
| 336 | ridge_onset_slope_ = p_val; |
| 337 | _recompile_glsl(); |
| 338 | emit_changed(); |
| 339 | } |
| 340 | |
| 341 | void DCTerrainGeneratorProcNodes::set_ridge_octave_onset(float p_val) { |
| 342 | if (ridge_octave_onset_ == p_val) return; |
| 343 | ridge_octave_onset_ = p_val; |
| 344 | _recompile_glsl(); |
| 345 | emit_changed(); |
| 346 | } |
| 347 | |
| 348 | void DCTerrainGeneratorProcNodes::set_assumed_slope(float p_val) { |
| 349 | if (assumed_slope_ == p_val) return; |
| 350 | assumed_slope_ = p_val; |
| 351 | _recompile_glsl(); |
| 352 | emit_changed(); |
| 353 | } |
| 354 | |
| 355 | void DCTerrainGeneratorProcNodes::set_assumed_slope_mix(float p_val) { |
| 356 | if (assumed_slope_mix_ == p_val) return; |
| 357 | assumed_slope_mix_ = p_val; |
| 358 | _recompile_glsl(); |
| 359 | emit_changed(); |
| 360 | } |
| 361 | |
| 362 | void DCTerrainGeneratorProcNodes::set_mountain_octaves(int p_val) { |
| 363 | if (mountain_octaves_ == p_val) return; |
| 364 | mountain_octaves_ = p_val; |
| 365 | _recompile_glsl(); |
| 366 | emit_changed(); |
| 367 | } |
| 368 | |
| 369 | void DCTerrainGeneratorProcNodes::set_detail_octaves(int p_val) { |
| 370 | if (detail_octaves_ == p_val) return; |
| 371 | detail_octaves_ = p_val; |
| 372 | _recompile_glsl(); |
| 373 | emit_changed(); |
| 374 | } |
| 375 | |
| 376 | void DCTerrainGeneratorProcNodes::set_lookdev_wrapper(bool p_val) { |
| 377 | if (lookdev_wrapper_ == p_val) return; |
| 378 | lookdev_wrapper_ = p_val; |
| 379 | _recompile_glsl(); |
| 380 | emit_changed(); |
| 381 | } |
| 382 | |
| 73 | 383 | void DCTerrainGeneratorProcNodes::set_terrain_height(float p_height) { |
| 74 | 384 | if (terrain_height_ == p_height) return; |
| 75 | 385 | terrain_height_ = p_height; |
| … | … | @@ -451,11 +761,44 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 451 | 761 | emit_cell_scale = (float)(double)gp.default_value; |
| 452 | 762 | } |
| 453 | 763 | |
| 764 | // HEIGHT SCALE CANNOT BE ZERO. |
| 765 | // |
| 766 | // It is the erosion node's HeightScale socket and the divisor of the whole |
| 767 | // vertical mapping, and the terrain panel gives it a slider that starts at |
| 768 | // 0. At zero, y_range / height_scale is infinite and String::num emits the |
| 769 | // literal "inf" -- which GLSL has no identifier for: |
| 770 | // |
| 771 | // ERROR: 0:1751: 'inf' : undeclared identifier |
| 772 | // |
| 773 | // The density shader then never compiles, EVERY chunk falls back, and the |
| 774 | // world has no terrain. It is sticky, too: the value came from a socket the |
| 775 | // panel writes and GameState persists durably, so it survives a restart and |
| 776 | // every later rebuild re-emits "inf". |
| 777 | // |
| 778 | // Emission must not be able to produce a shader that cannot compile. |
| 779 | if (!(height_scale > 1e-6f)) { |
| 780 | UtilityFunctions::push_warning( |
| 781 | "DCTerrainGeneratorProcNodes: Erosion Noise/HeightScale is ", height_scale, |
| 782 | " — clamping to 1e-6 so the shader still compiles."); |
| 783 | height_scale = 1e-6f; |
| 784 | } |
| 454 | 785 | String yscale_str = String::num(height_scale / y_range, 9); |
| 455 | 786 | String inv_yscale_str = String::num(y_range / height_scale, 9); |
| 456 | | // The mountain, relief and detail literals that used to be prepared here are |
| 457 | | // gone with the blocks that emitted them. Every one of those layers is a |
| 458 | | // node, and a node bakes its own sockets. |
| 787 | // detail_height_ is in METRES; mtn_offset is in units where 1.0 == y_range |
| 788 | // metres (y_mapped divides by y_scale = height_scale / y_range). Convert once |
| 789 | // here so the shader carries a plain fraction. |
| 790 | float detail_frac = (y_range > 0.01f) ? (detail_height_ / y_range) : 0.0f; |
| 791 | String mgain_str = String::num(mountain_gain_, 4); |
| 792 | String lac_str = String::num(noise_lacunarity_, 4); |
| 793 | String dscale_str = String::num(detail_scale_, 4); |
| 794 | String dfrac_str = String::num(detail_frac, 8); |
| 795 | String doct_str = itos(detail_octaves_); |
| 796 | String dgain_str = String::num(detail_gain_, 4); |
| 797 | String rscale_str = String::num(relief_scale_, 4); |
| 798 | String rfloor_str = String::num(relief_floor_, 4); |
| 799 | String mscale_str = String::num(mountain_scale_, 4); |
| 800 | String mheight_str = String::num(mountain_height_, 4); |
| 801 | String moct_str = itos(mountain_octaves_); |
| 459 | 802 | |
| 460 | 803 | // ── Baked heightfield, if one is loaded ──────────────────────────────── |
| 461 | 804 | // The SAMPLER is ours (storage is per-consumer); the metres -> filter-space |
| … | … | @@ -507,20 +850,43 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 507 | 850 | + String(erosion_heightmap_gn_glsl().c_str()); |
| 508 | 851 | } |
| 509 | 852 | |
| 510 | | // THE LOOKDEV-WRAPPER EMISSION MODE IS GONE. |
| 511 | | // |
| 512 | | // It emitted erosion_wrapper_glsl.h's gpu_wrapper() in place of this file's |
| 513 | | // assembly, so the engine ran the lookdev harness's own shader rather than a |
| 514 | | // transcription of it. That was worth having while this file assembled 47 KB |
| 515 | | // of terrain by hand; the wrapper is now four lines and the layers are nodes, |
| 516 | | // so there is no transcription left to check against. |
| 517 | | // |
| 518 | | // It was also switched OFF everywhere -- its only reference in the tree was |
| 519 | | // map_dc_diffusion passing false -- and it read six generator properties that |
| 520 | | // no longer exist, since the layers own their parameters now. |
| 521 | | // |
| 522 | | // test_erosion_parity.cpp still compiles erosion_wrapper_glsl.h directly and |
| 523 | | // does not go through this class, so the parity oracle is unaffected. |
| 853 | // ── LOOKDEV WRAPPER ──────────────────────────────────────────────────── |
| 854 | if (lookdev_wrapper_ && hblk_n_ > 0) { |
| 855 | ErosionWrapperParams wp; |
| 856 | wp.floor_y = floor_y_; |
| 857 | wp.ceiling_y = ceiling_y_; |
| 858 | wp.terrain_height = terrain_height_; |
| 859 | wp.noise_lacunarity = noise_lacunarity_; |
| 860 | wp.detail_scale = detail_scale_; |
| 861 | wp.detail_height = detail_height_; |
| 862 | wp.detail_gain = detail_gain_; |
| 863 | wp.detail_octaves = detail_octaves_; |
| 864 | wp.en_erosion_scale = erosion_scale_; |
| 865 | wp.voxel_size = 1.0f; |
| 866 | wp.heightmap_source = true; |
| 867 | wp.heightmap_step = hblk_mpp_; |
| 868 | for (int i = 0; i < discovered_params_.size(); i++) { |
| 869 | const GraphParam &gp = discovered_params_[i]; |
| 870 | if (gp.node_title != "Erosion Noise") continue; |
| 871 | if (gp.socket_name == "HeightScale") wp.en_height_scale = (float)(double)gp.default_value; |
| 872 | else if (gp.socket_name == "ErosionStr") wp.en_strength = (float)(double)gp.default_value; |
| 873 | else if (gp.socket_name == "SlopePower") wp.en_slope_power = (float)(double)gp.default_value; |
| 874 | else if (gp.socket_name == "CellScale") wp.en_cell_scale = (float)(double)gp.default_value; |
| 875 | else if (gp.socket_name == "Octaves") wp.en_octaves = (int)gp.default_value; |
| 876 | else if (gp.socket_name == "Gain") wp.en_gain = (float)(double)gp.default_value; |
| 877 | } |
| 878 | String lk = String("int pn_max_octaves = 99;\n") + proc_glsl + "\n" + hblk_glsl_sampler |
| 879 | + String(erosion_wrapper_glsl(wp).c_str()) |
| 880 | + "float evaluate_density(float x, float y, float z) {\n" |
| 881 | " return gpu_wrapper(x, y, z);\n" |
| 882 | "}\n"; |
| 883 | CharString u8 = lk.utf8(); |
| 884 | cached_glsl_ = std::string(u8.get_data(), u8.length()); |
| 885 | UtilityFunctions::print("[DCTerrainGeneratorProcNodes] LOOKDEV WRAPPER: ", |
| 886 | String::num_int64(cached_glsl_.size()), " bytes; detail_scale=", |
| 887 | detail_scale_, " (0 = heightmap + erosion ONLY)"); |
| 888 | return; |
| 889 | } |
| 524 | 890 | |
| 525 | 891 | // DOES THE GRAPH BRING THE NOISE LIBRARY? |
| 526 | 892 | // |
| … | … | @@ -532,15 +898,8 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 532 | 898 | // a silent fallback. So the wrapper's noise layers are emitted only when |
| 533 | 899 | // there is a library to support them. |
| 534 | 900 | const bool has_noise_lib = proc_glsl.find("fractal_noise_2d_lod") != -1; |
| 535 | | // want_mountain is GONE with the block it gated. It was |
| 536 | | // `has_noise_lib && mountain_height_ != 0.0f`, and because the erosion |
| 537 | | // filter's parameters were emitted inside the same branch, setting |
| 538 | | // MOUNTAIN_HEIGHT to 0 -- which every heightfield map does by definition, |
| 539 | | // the baked field REPLACING the mountain layer -- silently unconfigured the |
| 540 | | // filter as well. That is hyper-games #53 section 2, and it cannot recur: |
| 541 | | // the mountain is a node and the filter's knobs are its own sockets. |
| 542 | | // want_detail is GONE with the block it gated, as want_mountain was. The |
| 543 | | // detail layer is a node; a node is in the graph or it is not. |
| 901 | const bool want_mountain = has_noise_lib && mountain_height_ != 0.0f; |
| 902 | const bool want_detail = has_noise_lib && detail_scale_ > 0.0f; |
| 544 | 903 | |
| 545 | 904 | String adapted = |
| 546 | 905 | "// Octave limit — fixed high value for LOD-consistent surface position.\n" |
| … | … | @@ -565,52 +924,94 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 565 | 924 | "float evaluate_density(float x, float y, float z) {\n" |
| 566 | 925 | " float inv_scale = 1.0 / " + th_str + ";\n" |
| 567 | 926 | " pn_max_octaves = 99;\n" |
| 568 | | // THE MOUNTAIN LAYER IS A NODE (proc-nodes MountainNode). |
| 569 | | // |
| 570 | | // This block emitted the multifractal, the relief envelope and the |
| 571 | | // conversion into filter space, assigning them to the global |
| 572 | | // pn_terrain_offset -- with a second branch that replaced the whole |
| 573 | | // thing with heightmap_gn() when a baked field was loaded. Both are |
| 574 | | // graph shapes now: a Mountain node, or a Heightfield node, or both |
| 575 | | // summed through Math(Add) + VectorMath(Add). |
| 576 | | // |
| 577 | | // The `want_mountain` flag it was gated on is what made the erosion |
| 578 | | // filter's own parameters unreachable on every heightfield map |
| 579 | | // (hyper-games #53 section 2), because they were emitted in the same |
| 580 | | // branch. There is no flag now: a layer is in the graph or it is not. |
| 581 | | // THE FILTER'S PARAMETERS BELONG TO THE FILTER, AND NOW LIVE THERE. |
| 582 | | // |
| 583 | | // This block used to assign twenty globals -- pn_fade_div, |
| 584 | | // pn_erosion_scale, seventeen pn_ero_*, and a computed |
| 585 | | // pn_ero_max_octaves -- that the erosion node then read. It was emitted |
| 586 | | // INSIDE the want_mountain branch, and want_mountain is |
| 587 | | // `has_noise_lib && mountain_height_ != 0.0`, which is false for every |
| 588 | | // heightfield map because the baked field REPLACES the mountain layer. |
| 589 | | // So on exactly the maps the filter exists for, none of it was set and |
| 590 | | // the filter ran on the noise library's declaration defaults. |
| 591 | | // |
| 592 | | // They are input sockets on ErosionNoiseNode now |
| 593 | | // (docs/spec-graph-composition.md section 5.3), baked into the emitted |
| 594 | | // GLSL as literals by GpuCompiler. A socket has no branch to sit inside. |
| 595 | | // THE DETAIL LAYER IS A NODE (proc-nodes DetailNode), AND SO IS THE |
| 596 | | // SUBTRACTION IT USED TO MAKE HERE. |
| 597 | | // |
| 598 | | // This emitted a fBm into det_offset and then subtracted it from |
| 599 | | // y_mapped. Density is (eroded - y_mapped), so subtracting from |
| 600 | | // y_mapped and adding to the eroded height are one operation seen from |
| 601 | | // two ends -- and only the second can be a node, because only the second |
| 602 | | // happens after the filter has run. |
| 603 | | // |
| 604 | | // What is left of y_mapped is the vertical mapping and nothing else, |
| 605 | | // which is all a wrapper should ever have been. |
| 927 | " // MOUNTAIN LAYER, height AND gradient. The gradient used to be computed and\n" |
| 928 | " // thrown away: mtn_offset was added to y_mapped AFTER the erosion, so the\n" |
| 929 | " // filter never saw the range it was carving and aligned its gullies to gn\n" |
| 930 | " // alone -- three octaves at gain 0.1, i.e. one smooth 6.7 km blob. It read\n" |
| 931 | " // as noise laid over a mountain rather than erosion of one.\n" |
| 932 | " // MULTIFRACTAL. variance 0 is bit-identical to fractal_noise_2d, so the\n" |
| 933 | " // default costs nothing; above 0 each octave is weighted by the elevation\n" |
| 934 | " // accumulated so far, putting the roughness on high ground. Plain fBm is\n" |
| 935 | " // statistically homogeneous -- equally rugged in the basins and on the\n" |
| 936 | " // peaks -- which is what reads as every range looking the same.\n" |
| 937 | " // NYQUIST LIMITS. voxel_scale is the LOD's voxel size in metres and is\n" |
| 938 | " // declared by BOTH shaders this body is injected into (density_fill.glsl\n" |
| 939 | " // and edge_intersect.glsl), above the injection point. One cycle of a\n" |
| 940 | " // layer spans terrain_height/scale world metres, so that is its base\n" |
| 941 | " // wavelength. Fractional, so an octave fades in as a chunk refines\n" |
| 942 | " // rather than snapping on and moving the surface underfoot.\n" |
| 943 | + (want_mountain ? String( |
| 944 | " float mtn_lim = nyquist_octaves(" + th_str + " / max(" + mscale_str + ", 1e-6), voxel_scale, " + lac_str + ");\n" |
| 945 | " float rel_lim = nyquist_octaves(" + th_str + " / max(" + rscale_str + ", 1e-6), voxel_scale, 2.0);\n" |
| 946 | " float det_lim = nyquist_octaves(" + th_str + " / max(" + dscale_str + ", 1e-6), voxel_scale, " + lac_str + ");\n" |
| 947 | " vec3 mtn = fractal_multifractal_2d_lod(vec2(x, z) * inv_scale * " + mscale_str + ", 1.0, " + moct_str + ", " + lac_str + ", " + mgain_str + ", " + String::num(mountain_variance_, 4) + ", mtn_lim);\n" |
| 948 | " float relief_amp = 1.0;\n" |
| 949 | " if (" + rscale_str + " > 0.0) {\n" |
| 950 | " vec3 rel = fractal_noise_2d_lod(vec2(x, z) * inv_scale * " + rscale_str + ", 1.0, 2, 2.0, 0.5, rel_lim);\n" |
| 951 | " float t = clamp(rel.x * 0.5 + 0.5, 0.0, 1.0);\n" |
| 952 | " relief_amp = " + rfloor_str + " + (1.0 - " + rfloor_str + ") * t;\n" |
| 953 | " }\n" |
| 954 | " float mtn_amp = " + mheight_str + " * relief_amp;\n" |
| 955 | " // mtn is evaluated at p * mountain_scale, so d/dp = mtn.yz * mountain_scale.\n" |
| 956 | " // d(relief_amp)/dp is dropped: relief is a 40 km envelope, orders coarser\n" |
| 957 | " // than anything gully direction responds to. The 8.0 is exact, not fitted --\n" |
| 958 | " // gn reaches the surface as gn.x * HEIGHT_AMP * 0.5 = gn.x * 0.125, so\n" |
| 959 | " // dividing the offset by 0.125 reproduces the identical base surface at\n" |
| 960 | " // zero erosion strength.\n" |
| 961 | + (hblk_n_ > 0 |
| 962 | ? String(" pn_terrain_offset = heightmap_gn(x, z);\n") |
| 963 | : String(" pn_terrain_offset = vec3(mtn.x, mtn.y * ") + mscale_str + ", mtn.z * " + mscale_str + ") * mtn_amp * 8.0;\n") |
| 964 | + |
| 965 | " // DETAIL rides ON TOP of the eroded surface and is deliberately NOT folded\n" |
| 966 | " // into pn_terrain_offset: its gradient carries a factor of detail_scale, so\n" |
| 967 | " // inside one gully cell the direction flips several times and the stripes go\n" |
| 968 | " // chaotic -- measured 77.6 m of relief across a 2 m step, i.e. vertical\n" |
| 969 | " // noise. Detail is what water runs over, not what steers it.\n" |
| 970 | ) : String()) |
| 971 | // GATED ON THE NOISE LIBRARY, because that is what DECLARES every name |
| 972 | // below. A graph with no erosion node -- a heightfield on its own, which |
| 973 | // is what the map's EROSION_ENABLED toggle produces -- brings no library, |
| 974 | // and assigning to pn_fade_div / pn_ero_* / calling nyquist_octaves then |
| 975 | // references identifiers that do not exist and the shader does not |
| 976 | // compile. Same reason want_mountain and want_detail are gated. |
| 977 | + (has_noise_lib ? String( |
| 978 | " pn_fade_div = 4.8;\n" |
| 979 | " pn_erosion_scale = " + String::num(erosion_scale_, 6) + ";\n" |
| 980 | " pn_ero_input_height_amplitude = " + String::num(input_height_amplitude_, 9) + ";\n" |
| 981 | " pn_ero_octave_lacunarity = " + String::num(octave_lacunarity_, 9) + ";\n" |
| 982 | " pn_ero_gully_depth = " + String::num(gully_depth_, 9) + ";\n" |
| 983 | " pn_ero_fine_gully_slope_restriction = " + String::num(fine_gully_slope_restriction_, 9) + ";\n" |
| 984 | " pn_ero_gully_normalize_threshold = " + String::num(gully_normalize_threshold_, 9) + ";\n" |
| 985 | " pn_ero_height_offset = " + String::num(height_offset_, 9) + ";\n" |
| 986 | " pn_ero_height_offset_follows_altitude = " + String::num(height_offset_follows_altitude_, 9) + ";\n" |
| 987 | " pn_ero_crease_rounding = " + String::num(crease_rounding_, 9) + ";\n" |
| 988 | " pn_ero_ridge_rounding = " + String::num(ridge_rounding_, 9) + ";\n" |
| 989 | " pn_ero_input_feature_rounding = " + String::num(input_feature_rounding_, 9) + ";\n" |
| 990 | " pn_ero_rounding_per_octave = " + String::num(rounding_per_octave_, 9) + ";\n" |
| 991 | " pn_ero_gully_onset_slope = " + String::num(gully_onset_slope_, 9) + ";\n" |
| 992 | " pn_ero_octave_onset_slope = " + String::num(octave_onset_slope_, 9) + ";\n" |
| 993 | " pn_ero_ridge_onset_slope = " + String::num(ridge_onset_slope_, 9) + ";\n" |
| 994 | " pn_ero_ridge_octave_onset = " + String::num(ridge_octave_onset_, 9) + ";\n" |
| 995 | " pn_ero_assumed_slope = " + String::num(assumed_slope_, 9) + ";\n" |
| 996 | " pn_ero_assumed_slope_mix = " + String::num(assumed_slope_mix_, 9) + ";\n" |
| 997 | " pn_ero_max_octaves = nyquist_octaves(" + |
| 998 | String::num(terrain_height_ * erosion_scale_ * emit_cell_scale, 6) + |
| 999 | ", voxel_scale, 2.0);\n" |
| 1000 | ) : String()) |
| 1001 | + String(" float det_offset = 0.0;\n") |
| 1002 | + (want_detail ? String( |
| 1003 | " if (" + dscale_str + " > 0.0) {\n" |
| 1004 | " vec3 det = fractal_noise_2d_lod(vec2(x, z) * inv_scale * " + dscale_str + ", 1.0, " + doct_str + ", " + lac_str + ", " + dgain_str + ", det_lim);\n" |
| 1005 | " det_offset = det.x * " + dfrac_str + ";\n" |
| 1006 | " }\n" |
| 1007 | ) : String()) |
| 606 | 1008 | + (height_space_sqrt_ |
| 607 | | // SIGNED-SQRT HEIGHT SPACE. Endpoints are unchanged (H=0 -> floor_y, |
| 608 | | // H=height_scale -> ceiling_y), so no other parameter shifts meaning; |
| 609 | | // the surface becomes y = floor_y + y_range * (H/height_scale)^2, so a |
| 610 | | // constant noise amplitude produces elevation-proportional relief. |
| 611 | 1009 | ? String(" float un = (y - ") + floor_str + ") / " + String::num(y_range, 4) + ";\n" |
| 612 | | " float y_mapped = sign(un) * sqrt(abs(un)) * " + String::num(height_scale, 4) + ";\n" |
| 613 | | : String(" float y_mapped = (y - ") + floor_str + ") * " + yscale_str + ";\n") |
| 1010 | " float y_mapped = sign(un) * sqrt(abs(un)) * " + String::num(height_scale, 4) + |
| 1011 | " - det_offset * " + String::num(height_scale, 4) + ";\n" |
| 1012 | : String(" float y_mapped = (y - ") + floor_str + ") * " + yscale_str + |
| 1013 | " - det_offset * " + String::num(height_scale, 4) + ";\n") |
| 1014 | + "" |
| 614 | 1015 | + "" |
| 615 | 1016 | " float d = proc_density(vec3(x * inv_scale, y_mapped, z * inv_scale));\n" |
| 616 | 1017 | " d *= " + inv_yscale_str + ";\n" |
| … | … | @@ -644,6 +1045,9 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 644 | 1045 | float terrain_height = owner_->terrain_height_; |
| 645 | 1046 | float floor_y = owner_->floor_y_; |
| 646 | 1047 | float ceiling_y = owner_->ceiling_y_; |
| 1048 | float mtn_scale = owner_->mountain_scale_; |
| 1049 | float mtn_height = owner_->mountain_height_; |
| 1050 | int mtn_octaves = owner_->mountain_octaves_; |
| 647 | 1051 | |
| 648 | 1052 | // Extract noise params from discovered graph parameters |
| 649 | 1053 | // gn_detail defaults to ZERO, not 3. These defaults stand in for a node that |
| … | … | @@ -654,31 +1058,11 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 654 | 1058 | float base_freq = 3.0f, gn_detail = 0, gn_gain = 0.1f; |
| 655 | 1059 | float en_height_scale = 5.0f, en_erosion_str = 0.16f, en_slope_power = 0.6f; |
| 656 | 1060 | float en_cell_scale = 1.0f; int en_octaves = 5; float en_gain = 0.5f; |
| 657 | | // Defaults are ErosionNoiseNode's own socket defaults, so a graph whose |
| 658 | | // erosion node predates these sockets evaluates exactly as before. |
| 659 | | float ero_terrain_height = 60000.0f, ero_band_scale = 0.15f, ero_fade_div = 4.8f; |
| 660 | | float ero_height_amp = 0.25f, ero_oct_lac = 2.0f, ero_gully_depth = 0.5f; |
| 661 | | float ero_fine_restrict = 1.5f, ero_normalize = 0.5f; |
| 662 | | float ero_off_a = -0.65f, ero_off_b = 0.0f; |
| 663 | | float ero_round_x = 0.1f, ero_round_y = 0.0f, ero_round_z = 0.1f, ero_round_w = 2.0f; |
| 664 | | float ero_onset_x = 1.25f, ero_onset_y = 1.25f, ero_onset_z = 2.8f, ero_onset_w = 1.5f; |
| 665 | | float ero_slope_mag = 0.7f, ero_slope_mix = 1.0f; |
| 666 | 1061 | // MountainNode's sockets. Height 0 means "no mountain node in this graph", |
| 667 | 1062 | // which is the honest default: a layer that is not in the graph contributes |
| 668 | 1063 | // nothing. The generator's own mountain_* properties are not read here any |
| 669 | 1064 | // more -- they are what made the CPU compute a layer the shader had stopped |
| 670 | 1065 | // emitting, and vice versa. |
| 671 | | // DetailNode's sockets. Scale 0 -- the node's own default -- switches the |
| 672 | | // layer off, so a graph without one evaluates as if it were never there. |
| 673 | | bool has_detail = false; |
| 674 | | float dt_th = 60000.0f, dt_scale = 0.0f, dt_amp = 0.0f; |
| 675 | | int dt_octaves = 4; |
| 676 | | float dt_gain = 0.5f, dt_lac = 1.87f; |
| 677 | | bool has_mountain = false; |
| 678 | | float mn_th = 60000.0f, mn_scale = 1.0f, mn_height = 0.0f; |
| 679 | | int mn_octaves = 8, mn_mode = 0; |
| 680 | | float mn_gain = 0.68f, mn_lac = 1.87f, mn_variance = 0.0f, mn_damping = 1.0f; |
| 681 | | float mn_relief_scale = 0.0f, mn_relief_floor = 0.15f, mn_filter_amp = 0.25f; |
| 682 | 1066 | for (int i = 0; i < owner_->discovered_params_.size(); i++) { |
| 683 | 1067 | const auto &gp = owner_->discovered_params_[i]; |
| 684 | 1068 | if (gp.node_title == "Gradient Noise" && gp.socket_name == "Scale") |
| … | … | @@ -699,69 +1083,6 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 699 | 1083 | en_octaves = (int)gp.default_value; |
| 700 | 1084 | if (gp.node_title == "Erosion Noise" && gp.socket_name == "Gain") |
| 701 | 1085 | en_gain = (float)(double)gp.default_value; |
| 702 | | if (gp.node_title == "Detail") { |
| 703 | | has_detail = true; |
| 704 | | const String &dn = gp.socket_name; |
| 705 | | float dv = (gp.type == Variant::INT) ? (float)(int)gp.default_value |
| 706 | | : (float)(double)gp.default_value; |
| 707 | | if (dn == "TerrainHeight") dt_th = dv; |
| 708 | | else if (dn == "Scale") dt_scale = dv; |
| 709 | | else if (dn == "Amplitude") dt_amp = dv; |
| 710 | | else if (dn == "Octaves") dt_octaves = (int)dv; |
| 711 | | else if (dn == "Gain") dt_gain = dv; |
| 712 | | else if (dn == "Lacunarity") dt_lac = dv; |
| 713 | | continue; |
| 714 | | } |
| 715 | | if (gp.node_title == "Mountain") { |
| 716 | | has_mountain = true; |
| 717 | | const String &mn = gp.socket_name; |
| 718 | | float mv = (gp.type == Variant::INT) ? (float)(int)gp.default_value |
| 719 | | : (float)(double)gp.default_value; |
| 720 | | if (mn == "TerrainHeight") mn_th = mv; |
| 721 | | else if (mn == "Scale") mn_scale = mv; |
| 722 | | else if (mn == "Height") mn_height = mv; |
| 723 | | else if (mn == "Octaves") mn_octaves = (int)mv; |
| 724 | | else if (mn == "Gain") mn_gain = mv; |
| 725 | | else if (mn == "Lacunarity") mn_lac = mv; |
| 726 | | else if (mn == "Variance") mn_variance = mv; |
| 727 | | else if (mn == "Mode") mn_mode = (int)mv; |
| 728 | | else if (mn == "Damping") mn_damping = mv; |
| 729 | | else if (mn == "ReliefScale") mn_relief_scale = mv; |
| 730 | | else if (mn == "ReliefFloor") mn_relief_floor = mv; |
| 731 | | else if (mn == "FilterHeightAmplitude") mn_filter_amp = mv; |
| 732 | | continue; |
| 733 | | } |
| 734 | | // THE FILTER'S OWN KNOBS, read from the same sockets the shader bakes. |
| 735 | | // |
| 736 | | // This path called erosion_node_eval -- TEN arguments, runevision's |
| 737 | | // reference values baked inside -- while the GPU called |
| 738 | | // erosion_node_eval_full with NINETEEN. So every one of the seventeen |
| 739 | | // was already a CPU/GPU divergence: turn one and the surface you see |
| 740 | | // moves while the surface you collide with does not. Collision reads |
| 741 | | // this function; rendering reads the shader. |
| 742 | | if (gp.node_title != "Erosion Noise") continue; |
| 743 | | const String &sn = gp.socket_name; |
| 744 | | float v = (float)(double)gp.default_value; |
| 745 | | if (sn == "TerrainHeight") ero_terrain_height = v; |
| 746 | | else if (sn == "GullyBandScale") ero_band_scale = v; |
| 747 | | else if (sn == "PeakHeightDivisor") ero_fade_div = v; |
| 748 | | else if (sn == "InputHeightAmplitude") ero_height_amp = v; |
| 749 | | else if (sn == "OctaveLacunarity") ero_oct_lac = v; |
| 750 | | else if (sn == "GullyDepth") ero_gully_depth = v; |
| 751 | | else if (sn == "FineGullySlopeRestriction") ero_fine_restrict = v; |
| 752 | | else if (sn == "GullyNormalizeThreshold") ero_normalize = v; |
| 753 | | else if (sn == "HeightOffset") ero_off_a = v; |
| 754 | | else if (sn == "HeightOffsetFollowsAltitude") ero_off_b = v; |
| 755 | | else if (sn == "CreaseRounding") ero_round_x = v; |
| 756 | | else if (sn == "RidgeRounding") ero_round_y = v; |
| 757 | | else if (sn == "InputFeatureRounding") ero_round_z = v; |
| 758 | | else if (sn == "RoundingPerOctave") ero_round_w = v; |
| 759 | | else if (sn == "GullyOnsetSlope") ero_onset_x = v; |
| 760 | | else if (sn == "OctaveOnsetSlope") ero_onset_y = v; |
| 761 | | else if (sn == "RidgeOnsetSlope") ero_onset_z = v; |
| 762 | | else if (sn == "RidgeOctaveOnset") ero_onset_w = v; |
| 763 | | else if (sn == "AssumedSlope") ero_slope_mag = v; |
| 764 | | else if (sn == "AssumedSlopeMix") ero_slope_mix = v; |
| 765 | 1086 | } |
| 766 | 1087 | |
| 767 | 1088 | float inv_scale = 1.0f / terrain_height; |
| … | … | @@ -841,45 +1162,30 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 841 | 1162 | return d; |
| 842 | 1163 | } |
| 843 | 1164 | |
| 844 | | // The three Nyquist limits that used to be computed here for three layers at |
| 845 | | // once are computed inside each layer's own block now, from that layer's own |
| 846 | | // sockets -- which is what stopped the detail layer depending on a local the |
| 847 | | // mountain layer happened to declare. |
| 848 | | |
| 849 | | // THE MOUNTAIN LAYER — MountainNode's CPU twin, term for term. |
| 850 | | // |
| 851 | | // Read from the NODE's sockets, not from generator properties. While these |
| 852 | | // were two independent parameter sets the CPU could compute a layer the |
| 853 | | // shader had stopped emitting, which is precisely how sample_density came |
| 854 | | // to report a surface 5.3 km from the one being drawn. |
| 855 | | vec3 mtn = vec3(0.0f, 0.0f, 0.0f); |
| 856 | | float mtn_amp = 0.0f; |
| 857 | | if (has_mountain) { |
| 858 | | float mn_lim = dcerosion::nyquist_octaves(mn_th / MAX(mn_scale, 1e-6f), |
| 859 | | lod_voxel_size, mn_lac); |
| 860 | | vec2 mn_p = vec2(x, z) * inv_scale * mn_scale; |
| 861 | | mtn = (mn_mode == 1) |
| 862 | | ? dcerosion::fractal_gradient_2d_lod(mn_p, 1.0f, mn_octaves, mn_lac, |
| 863 | | mn_gain, mn_damping, mn_lim) |
| 864 | | : dcerosion::fractal_multifractal_2d_lod(mn_p, 1.0f, mn_octaves, mn_lac, |
| 865 | | mn_gain, mn_variance, mn_lim); |
| 866 | | float relief_amp = 1.0f; |
| 867 | | if (mn_relief_scale > 0.0f) { |
| 868 | | vec3 rel = dcerosion::fractal_noise_2d_lod(vec2(x, z) * inv_scale * mn_relief_scale, |
| 869 | | 1.0f, 2, 2.0f, 0.5f, |
| 870 | | dcerosion::nyquist_octaves(mn_th / MAX(mn_relief_scale, 1e-6f), |
| 871 | | lod_voxel_size, 2.0f)); |
| 872 | | float t = dcerosion::clamp(rel.x * 0.5f + 0.5f, 0.0f, 1.0f); |
| 873 | | relief_amp = mn_relief_floor + (1.0f - mn_relief_floor) * t; |
| 874 | | } |
| 875 | | // 1/(FilterHeightAmplitude * 0.5) -- the wrapper's `* 8.0`, derived |
| 876 | | // rather than baked, and it must match the erosion node's |
| 877 | | // InputHeightAmplitude. |
| 878 | | mtn_amp = (mn_height * relief_amp) / (mn_filter_amp * 0.5f); |
| 1165 | // MUST match the GLSL above: same base wavelengths, same lacunarities. |
| 1166 | const float lac = owner_->noise_lacunarity_; |
| 1167 | float mtn_lim = dcerosion::nyquist_octaves(terrain_height / MAX(mtn_scale, 1e-6f), |
| 1168 | lod_voxel_size, lac); |
| 1169 | float rel_lim = dcerosion::nyquist_octaves( |
| 1170 | terrain_height / MAX(owner_->relief_scale_, 1e-6f), lod_voxel_size, 2.0f); |
| 1171 | float det_lim = dcerosion::nyquist_octaves( |
| 1172 | terrain_height / MAX(owner_->detail_scale_, 1e-6f), lod_voxel_size, lac); |
| 1173 | |
| 1174 | vec3 mtn = dcerosion::fractal_multifractal_2d_lod(vec2(x, z) * inv_scale * mtn_scale, 1.0f, |
| 1175 | mtn_octaves, lac, owner_->mountain_gain_, |
| 1176 | owner_->mountain_variance_, mtn_lim); |
| 1177 | // Relief field — MUST stay identical to the GLSL above. |
| 1178 | float relief_amp = 1.0f; |
| 1179 | if (owner_->relief_scale_ > 0.0f) { |
| 1180 | vec3 rel = dcerosion::fractal_noise_2d_lod(vec2(x, z) * inv_scale * owner_->relief_scale_, |
| 1181 | 1.0f, 2, 2.0f, 0.5f, rel_lim); |
| 1182 | float t = dcerosion::clamp(rel.x * 0.5f + 0.5f, 0.0f, 1.0f); |
| 1183 | relief_amp = owner_->relief_floor_ + (1.0f - owner_->relief_floor_) * t; |
| 879 | 1184 | } |
| 880 | | // The mountain's HEIGHT AND GRADIENT in gn units, which is what the Add |
| 881 | | // nodes in the graph sum into the erosion filter's Height and Slope inputs. |
| 882 | | vec3 terrain_offset = vec3(mtn.x, mtn.y * mn_scale, mtn.z * mn_scale) * mtn_amp; |
| 1185 | float mtn_amp = mtn_height * relief_amp; |
| 1186 | // The mountain's HEIGHT AND GRADIENT, in gn units, to hand to the erosion — |
| 1187 | // the pn_terrain_offset the GLSL sets. |
| 1188 | vec3 terrain_offset = vec3(mtn.x, mtn.y * mtn_scale, mtn.z * mtn_scale) * (mtn_amp * 8.0f); |
| 883 | 1189 | |
| 884 | 1190 | // THE SAME SUBSTITUTION THE GLSL MAKES. |
| 885 | 1191 | // |
| … | … | @@ -942,29 +1248,24 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 942 | 1248 | /* height_amp */ 0.25f, hmpp, sample, oh, odx, odz); |
| 943 | 1249 | terrain_offset = vec3(oh, odx, odz); |
| 944 | 1250 | } |
| 945 | | // DETAIL — DetailNode's CPU twin, read from its sockets. |
| 946 | | // |
| 947 | | // It is ADDED to the eroded height rather than subtracted from y_mapped. |
| 948 | | // Those are the same algebra, since density is (eroded - y_mapped), but only |
| 949 | | // the first can run after the filter, which is where a layer that rides on |
| 950 | | // the eroded surface belongs. |
| 1251 | // Detail rides on TOP and is NOT folded in — MUST stay identical to the GLSL. |
| 951 | 1252 | float det_offset = 0.0f; |
| 952 | | if (has_detail && dt_scale > 0.0f) { |
| 953 | | vec3 det = dcerosion::fractal_noise_2d_lod(vec2(x, z) * inv_scale * dt_scale, |
| 954 | | 1.0f, dt_octaves, dt_lac, dt_gain, |
| 955 | | dcerosion::nyquist_octaves(dt_th / MAX(dt_scale, 1e-6f), lod_voxel_size, dt_lac)); |
| 956 | | det_offset = det.x * dt_amp; |
| 1253 | if (owner_->detail_scale_ > 0.0f) { |
| 1254 | float detail_frac = (y_range > 0.01f) ? (owner_->detail_height_ / y_range) : 0.0f; |
| 1255 | vec3 det = dcerosion::fractal_noise_2d_lod(vec2(x, z) * inv_scale * owner_->detail_scale_, |
| 1256 | 1.0f, owner_->detail_octaves_, lac, owner_->detail_gain_, det_lim); |
| 1257 | det_offset = det.x * detail_frac; |
| 957 | 1258 | } |
| 958 | 1259 | |
| 959 | | // THE VERTICAL MAPPING, and nothing else -- the wrapper's whole remaining |
| 960 | | // job. MUST mirror the GLSL above, both branches. |
| 1260 | // Map world Y to proc_density space |
| 1261 | // MUST mirror the GLSL above, both branches. |
| 961 | 1262 | float y_mapped; |
| 962 | 1263 | if (owner_->height_space_sqrt_) { |
| 963 | 1264 | float un = (y - floor_y) / y_range; |
| 964 | 1265 | float su = (un < 0.0f) ? -sqrtf(-un) : sqrtf(un); |
| 965 | | y_mapped = su * en_height_scale; |
| 1266 | y_mapped = su * en_height_scale - det_offset * en_height_scale; |
| 966 | 1267 | } else { |
| 967 | | y_mapped = (y - floor_y) * y_scale; |
| 1268 | y_mapped = (y - floor_y) * y_scale - det_offset * en_height_scale; |
| 968 | 1269 | } |
| 969 | 1270 | |
| 970 | 1271 | // GradientNoiseNode. Lacunarity is hardcoded 2.0 in the node |
| … | … | @@ -991,32 +1292,19 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 991 | 1292 | // |
| 992 | 1293 | // The coarsest gully spans terrain_height * gully_band_scale * cell_size in |
| 993 | 1294 | // world metres and halves per octave, so that is the base wavelength. |
| 994 | | // THE SAME EXPRESSION THE NODE EMITS, from the same sockets: the coarsest |
| 995 | | // gully spans TerrainHeight * GullyBandScale * CellScale in world metres and |
| 996 | | // halves per octave. If these two ever differ the surface you walk on and |
| 997 | | // the surface you see part company by however much an octave is worth. |
| 998 | 1295 | float ero_max_oct = 999.0f; |
| 999 | 1296 | if (lod_voxel_size > 0.0f) { |
| 1000 | 1297 | ero_max_oct = dcerosion::nyquist_octaves( |
| 1001 | | ero_terrain_height * ero_band_scale * en_cell_scale, |
| 1298 | terrain_height * owner_->erosion_scale_ * en_cell_scale, |
| 1002 | 1299 | lod_voxel_size, 2.0f); |
| 1003 | 1300 | } |
| 1004 | | // NINETEEN ARGUMENTS, matching the shader. See the note above the socket |
| 1005 | | // reads for what calling the ten-argument form cost. |
| 1006 | | vec2 en = dcerosion::erosion_node_eval_full( |
| 1301 | vec2 en = dcerosion::erosion_node_eval( |
| 1007 | 1302 | uv, gn + terrain_offset, en_height_scale, en_erosion_str, |
| 1008 | | en_cell_scale, en_octaves, en_gain, ero_fade_div, ero_band_scale, |
| 1009 | | ero_height_amp, ero_oct_lac, ero_gully_depth, ero_fine_restrict, |
| 1010 | | ero_normalize, dcerosion::vec2(ero_off_a, ero_off_b), |
| 1011 | | dcerosion::vec4(ero_round_x, ero_round_y, ero_round_z, ero_round_w), |
| 1012 | | dcerosion::vec4(ero_onset_x, ero_onset_y, ero_onset_z, ero_onset_w), |
| 1013 | | dcerosion::vec2(ero_slope_mag, ero_slope_mix), |
| 1014 | | ero_max_oct); |
| 1015 | | |
| 1016 | | // SDF convention: negative = inside, positive = outside. det_offset is added |
| 1017 | | // to the eroded height, which is exactly what DetailNode's `pos.y += ...` |
| 1018 | | // does on the GPU. |
| 1019 | | float d = (en.x + det_offset) - y_mapped; |
| 1303 | en_cell_scale, en_octaves, en_gain, 4.8f, |
| 1304 | owner_->erosion_scale_, ero_max_oct); |
| 1305 | |
| 1306 | // SDF convention: negative = inside, positive = outside. |
| 1307 | float d = en.x - y_mapped; |
| 1020 | 1308 | d *= inv_y_scale; |
| 1021 | 1309 | |
| 1022 | 1310 | // Clip: solid below floor_y, air above ceiling_y |