| … | … | @@ -98,6 +98,22 @@ void DCTerrainGeneratorProcNodes::_bind_methods() { |
| 98 | 98 | ClassDB::bind_method(D_METHOD("set_crease_rounding", "value"), &DCTerrainGeneratorProcNodes::set_crease_rounding); |
| 99 | 99 | ClassDB::bind_method(D_METHOD("get_crease_rounding"), &DCTerrainGeneratorProcNodes::get_crease_rounding); |
| 100 | 100 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "crease_rounding"), "set_crease_rounding", "get_crease_rounding"); |
| 101 | ClassDB::bind_method(D_METHOD("set_submarine_amp", "v"), &DCTerrainGeneratorProcNodes::set_submarine_amp); |
| 102 | ClassDB::bind_method(D_METHOD("get_submarine_amp"), &DCTerrainGeneratorProcNodes::get_submarine_amp); |
| 103 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "submarine_amp"), "set_submarine_amp", "get_submarine_amp"); |
| 104 | ClassDB::bind_method(D_METHOD("set_submarine_wavelength", "v"), &DCTerrainGeneratorProcNodes::set_submarine_wavelength); |
| 105 | ClassDB::bind_method(D_METHOD("get_submarine_wavelength"), &DCTerrainGeneratorProcNodes::get_submarine_wavelength); |
| 106 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "submarine_wavelength"), "set_submarine_wavelength", "get_submarine_wavelength"); |
| 107 | ClassDB::bind_method(D_METHOD("set_submarine_octaves", "v"), &DCTerrainGeneratorProcNodes::set_submarine_octaves); |
| 108 | ClassDB::bind_method(D_METHOD("get_submarine_octaves"), &DCTerrainGeneratorProcNodes::get_submarine_octaves); |
| 109 | ADD_PROPERTY(PropertyInfo(Variant::INT, "submarine_octaves"), "set_submarine_octaves", "get_submarine_octaves"); |
| 110 | ClassDB::bind_method(D_METHOD("set_submarine_buffer", "a", "b"), &DCTerrainGeneratorProcNodes::set_submarine_buffer); |
| 111 | ClassDB::bind_method(D_METHOD("set_erosion_mask_depth", "v"), &DCTerrainGeneratorProcNodes::set_erosion_mask_depth); |
| 112 | ClassDB::bind_method(D_METHOD("get_erosion_mask_depth"), &DCTerrainGeneratorProcNodes::get_erosion_mask_depth); |
| 113 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "erosion_mask_depth"), "set_erosion_mask_depth", "get_erosion_mask_depth"); |
| 114 | ClassDB::bind_method(D_METHOD("set_submarine_water_y", "v"), &DCTerrainGeneratorProcNodes::set_submarine_water_y); |
| 115 | ClassDB::bind_method(D_METHOD("get_submarine_water_y"), &DCTerrainGeneratorProcNodes::get_submarine_water_y); |
| 116 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "submarine_water_y"), "set_submarine_water_y", "get_submarine_water_y"); |
| 101 | 117 | ClassDB::bind_method(D_METHOD("set_detail_slope_lo", "value"), &DCTerrainGeneratorProcNodes::set_detail_slope_lo); |
| 102 | 118 | ClassDB::bind_method(D_METHOD("get_detail_slope_lo"), &DCTerrainGeneratorProcNodes::get_detail_slope_lo); |
| 103 | 119 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_slope_lo"), "set_detail_slope_lo", "get_detail_slope_lo"); |
| … | … | @@ -373,6 +389,31 @@ float DCTerrainGeneratorProcNodes::get_waterline_norm() const { |
| 373 | 389 | hypso_peak_gain_).x; |
| 374 | 390 | } |
| 375 | 391 | |
| 392 | void DCTerrainGeneratorProcNodes::set_submarine_amp(float v) { |
| 393 | if (submarine_amp_ == v) return; |
| 394 | submarine_amp_ = v; _recompile_glsl(); emit_changed(); |
| 395 | } |
| 396 | void DCTerrainGeneratorProcNodes::set_submarine_wavelength(float v) { |
| 397 | if (submarine_wavelength_ == v) return; |
| 398 | submarine_wavelength_ = v; _recompile_glsl(); emit_changed(); |
| 399 | } |
| 400 | void DCTerrainGeneratorProcNodes::set_submarine_octaves(int v) { |
| 401 | if (submarine_octaves_ == v) return; |
| 402 | submarine_octaves_ = v; _recompile_glsl(); emit_changed(); |
| 403 | } |
| 404 | void DCTerrainGeneratorProcNodes::set_submarine_buffer(float a, float b) { |
| 405 | submarine_buffer_start_ = a; submarine_buffer_end_ = b; |
| 406 | _recompile_glsl(); emit_changed(); |
| 407 | } |
| 408 | void DCTerrainGeneratorProcNodes::set_erosion_mask_depth(float v) { |
| 409 | if (erosion_mask_depth_ == v) return; |
| 410 | erosion_mask_depth_ = v; _recompile_glsl(); emit_changed(); |
| 411 | } |
| 412 | void DCTerrainGeneratorProcNodes::set_submarine_water_y(float v) { |
| 413 | if (submarine_water_y_ == v) return; |
| 414 | submarine_water_y_ = v; _recompile_glsl(); emit_changed(); |
| 415 | } |
| 416 | |
| 376 | 417 | void DCTerrainGeneratorProcNodes::set_detail_slope_lo(float p_val) { |
| 377 | 418 | if (detail_slope_lo_ == p_val) return; |
| 378 | 419 | detail_slope_lo_ = p_val; |
| … | … | @@ -1308,6 +1349,28 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 1308 | 1349 | // output, and is deliberately not done here. |
| 1309 | 1350 | " pn_terrain_offset = vec3(hc.x, mtn.y * " + mscale_str + " * hc.y, mtn.z * " |
| 1310 | 1351 | + mscale_str + " * hc.y) * " + mheight_str + " * 8.0;\n" |
| 1352 | // EROSION IS SUBAERIAL. hc.x is the elevation BEFORE the filter runs, |
| 1353 | // so the column's depth is known here and the mask can be set before |
| 1354 | // proc_density is entered. Metres per curve unit is mountain_height * |
| 1355 | // inv_yscale: pn_terrain_offset carries hc.x * mheight * 8 and reaches |
| 1356 | // the surface through a factor of 0.125, so the base surface in mapped |
| 1357 | // METRES PER CURVE UNIT = mountain_height * erosion height_scale * |
| 1358 | // inv_yscale. The full chain: pn_terrain_offset carries hc.x * mheight |
| 1359 | // * 8, gn reaches the surface through input_height_amplitude * 0.5 = |
| 1360 | // 0.125, and erosion_node_eval scales the result by height_scale. So |
| 1361 | // 8 * 0.125 * height_scale = height_scale. |
| 1362 | // |
| 1363 | // ⚠ The height_scale factor was MISSING at first, giving 0.55 * 4200 = |
| 1364 | // 2310 m/unit against a world whose own relief readout says 11550 -- |
| 1365 | // exactly 5x out, which is height_scale. Caught by comparing the |
| 1366 | // emitted constant against a number the map already prints. |
| 1367 | + (erosion_mask_depth_ > 0.0f ? String( |
| 1368 | " pn_erosion_mask = 1.0 - smoothstep(0.0, ") |
| 1369 | + String::num(erosion_mask_depth_, 3) + ", (" |
| 1370 | + String::num(get_waterline_norm(), 8) + " - hc.x) * " |
| 1371 | + String::num(mountain_height_ * erosion_height_scale_, 6) |
| 1372 | + " * " + inv_yscale_str + ");\n" |
| 1373 | : String()) |
| 1311 | 1374 | : String(" pn_terrain_offset = vec3(mtn.x, mtn.y * ") + mscale_str |
| 1312 | 1375 | + ", mtn.z * " + mscale_str + ") * mtn_amp * 8.0;\n"; |
| 1313 | 1376 | |
| … | … | @@ -1465,6 +1528,31 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 1465 | 1528 | " pn_out_grad = vec2(0.0);\n") |
| 1466 | 1529 | : String( |
| 1467 | 1530 | " pn_out_grad *= inv_scale * ") + inv_yscale_str + ";\n") |
| 1531 | // ── SUBMARINE TERRAIN ────────────────────────────────────────── |
| 1532 | // Geiss (GPU Gems 3 ch.1): add a 3D fBm to a heightfield density and |
| 1533 | // the surface stops being single-valued -- caves, arches and overhangs |
| 1534 | // appear wherever the 3D term outruns the vertical gradient. A |
| 1535 | // heightfield seabed cannot have any of those, and the whole world is |
| 1536 | // meant to be reachable. |
| 1537 | // |
| 1538 | // GATED ON DEPTH, not applied globally. sea_depth uses the UNPERTURBED |
| 1539 | // surface (y + d before this line), so the weight is a property of the |
| 1540 | // column and cannot feed back on itself. The first tens of metres stay |
| 1541 | // a pure heightfield because beaches and the waterline need a |
| 1542 | // single-valued surface -- a cave mouth at the shoreline has no clean |
| 1543 | // coastline, and the ocean's depth query assumes d = H - y holds. |
| 1544 | + (submarine_amp_ > 0.0f ? String( |
| 1545 | " // Submarine volumetric seabed, below a smooth coastal buffer.\n" |
| 1546 | " float sea_depth = ") + String::num(submarine_water_y_, 3) + " - (y + d);\n" |
| 1547 | " float sub_w = smoothstep(" + String::num(submarine_buffer_start_, 3) + ", " |
| 1548 | + String::num(submarine_buffer_end_, 3) + ", sea_depth);\n" |
| 1549 | " if (sub_w > 0.0) {\n" |
| 1550 | " float sub_f = 1.0 / " + String::num(submarine_wavelength_, 4) + ";\n" |
| 1551 | " d += ps_fbm_noise_3d(x * sub_f, y * sub_f, z * sub_f, " |
| 1552 | + String::num_int64(submarine_octaves_) + ", " |
| 1553 | + String::num(submarine_roughness_, 4) + ", 2.0) * " |
| 1554 | + String::num(submarine_amp_, 4) + " * sub_w;\n" |
| 1555 | " }\n" : String()) |
| 1468 | 1556 | + String(" // Clip: solid below floor_y, air above ceiling_y.\n" |
| 1469 | 1557 | " d = max(d, (") + floor_str + " - y) * 2.0);\n" |
| 1470 | 1558 | " d = min(d, (" + ceil_str + " - y) * 2.0);\n" |