| … | … | @@ -437,10 +437,19 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 437 | 437 | " // accumulated so far, putting the roughness on high ground. Plain fBm is\n" |
| 438 | 438 | " // statistically homogeneous -- equally rugged in the basins and on the\n" |
| 439 | 439 | " // peaks -- which is what reads as every range looking the same.\n" |
| 440 | " vec3 mtn = fractal_multifractal_2d(vec2(x, z) * inv_scale * " + mscale_str + ", 1.0, " + moct_str + ", " + lac_str + ", " + mgain_str + ", " + String::num(mountain_variance_, 4) + ");\n" | |
| 440 | " // NYQUIST LIMITS. voxel_scale is the LOD's voxel size in metres and is\n" | |
| 441 | " // declared by BOTH shaders this body is injected into (density_fill.glsl\n" | |
| 442 | " // and edge_intersect.glsl), above the injection point. One cycle of a\n" | |
| 443 | " // layer spans terrain_height/scale world metres, so that is its base\n" | |
| 444 | " // wavelength. Fractional, so an octave fades in as a chunk refines\n" | |
| 445 | " // rather than snapping on and moving the surface underfoot.\n" | |
| 446 | " float mtn_lim = nyquist_octaves(" + th_str + " / max(" + mscale_str + ", 1e-6), voxel_scale, " + lac_str + ");\n" | |
| 447 | " float rel_lim = nyquist_octaves(" + th_str + " / max(" + rscale_str + ", 1e-6), voxel_scale, 2.0);\n" | |
| 448 | " float det_lim = nyquist_octaves(" + th_str + " / max(" + dscale_str + ", 1e-6), voxel_scale, " + lac_str + ");\n" | |
| 449 | " 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" | |
| 441 | 450 | " float relief_amp = 1.0;\n" |
| 442 | 451 | " if (" + rscale_str + " > 0.0) {\n" |
| 443 | " vec3 rel = fractal_noise_2d(vec2(x, z) * inv_scale * " + rscale_str + ", 1.0, 2, 2.0, 0.5);\n" | |
| 452 | " vec3 rel = fractal_noise_2d_lod(vec2(x, z) * inv_scale * " + rscale_str + ", 1.0, 2, 2.0, 0.5, rel_lim);\n" | |
| 444 | 453 | " float t = clamp(rel.x * 0.5 + 0.5, 0.0, 1.0);\n" |
| 445 | 454 | " relief_amp = " + rfloor_str + " + (1.0 - " + rfloor_str + ") * t;\n" |
| 446 | 455 | " }\n" |
| … | … | @@ -461,7 +470,7 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 461 | 470 | " // noise. Detail is what water runs over, not what steers it.\n" |
| 462 | 471 | " float det_offset = 0.0;\n" |
| 463 | 472 | " if (" + dscale_str + " > 0.0) {\n" |
| 464 | " vec3 det = fractal_noise_2d(vec2(x, z) * inv_scale * " + dscale_str + ", 1.0, " + doct_str + ", " + lac_str + ", " + dgain_str + ");\n" | |
| 473 | " vec3 det = fractal_noise_2d_lod(vec2(x, z) * inv_scale * " + dscale_str + ", 1.0, " + doct_str + ", " + lac_str + ", " + dgain_str + ", det_lim);\n" | |
| 465 | 474 | " det_offset = det.x * " + dfrac_str + ";\n" |
| 466 | 475 | " }\n" |
| 467 | 476 | + (height_space_sqrt_ |
| … | … | @@ -492,7 +501,12 @@ void DCTerrainGeneratorProcNodes::_recompile_glsl() { |
| 492 | 501 | |
| 493 | 502 | float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 494 | 503 | float x, float y, float z, float lod_voxel_size) { |
| 495 | (void)lod_voxel_size; | |
| 504 | // lod_voxel_size USED to be discarded here, which is why this generator had | |
| 505 | // no Nyquist protection on any layer: the wrapper passed literal octave | |
| 506 | // counts and the graph nodes' min(N, pn_max_octaves) is disarmed by | |
| 507 | // pn_max_octaves = 99. DCTerrain::sample_density passes 0 on purpose | |
| 508 | // (dc_terrain.cpp:2841) and nyquist_octaves reads that as "no limit", so | |
| 509 | // collision keeps evaluating the full field. | |
| 496 | 510 | |
| 497 | 511 | // Read graph parameters (same values as the GLSL adapter uses) |
| 498 | 512 | float terrain_height = owner_->terrain_height_; |
| … | … | @@ -543,14 +557,23 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 543 | 557 | // remaining piece. |
| 544 | 558 | using dcerosion::vec2; |
| 545 | 559 | using dcerosion::vec3; |
| 546 | vec3 mtn = dcerosion::fractal_multifractal_2d(vec2(x, z) * inv_scale * mtn_scale, 1.0f, | |
| 547 | mtn_octaves, owner_->noise_lacunarity_, owner_->mountain_gain_, | |
| 548 | owner_->mountain_variance_); | |
| 560 | // MUST match the GLSL above: same base wavelengths, same lacunarities. | |
| 561 | const float lac = owner_->noise_lacunarity_; | |
| 562 | float mtn_lim = dcerosion::nyquist_octaves(terrain_height / MAX(mtn_scale, 1e-6f), | |
| 563 | lod_voxel_size, lac); | |
| 564 | float rel_lim = dcerosion::nyquist_octaves( | |
| 565 | terrain_height / MAX(owner_->relief_scale_, 1e-6f), lod_voxel_size, 2.0f); | |
| 566 | float det_lim = dcerosion::nyquist_octaves( | |
| 567 | terrain_height / MAX(owner_->detail_scale_, 1e-6f), lod_voxel_size, lac); | |
| 568 | ||
| 569 | vec3 mtn = dcerosion::fractal_multifractal_2d_lod(vec2(x, z) * inv_scale * mtn_scale, 1.0f, | |
| 570 | mtn_octaves, lac, owner_->mountain_gain_, | |
| 571 | owner_->mountain_variance_, mtn_lim); | |
| 549 | 572 | // Relief field — MUST stay identical to the GLSL above. |
| 550 | 573 | float relief_amp = 1.0f; |
| 551 | 574 | if (owner_->relief_scale_ > 0.0f) { |
| 552 | vec3 rel = dcerosion::fractal_noise_2d(vec2(x, z) * inv_scale * owner_->relief_scale_, | |
| 553 | 1.0f, 2, 2.0f, 0.5f); | |
| 575 | vec3 rel = dcerosion::fractal_noise_2d_lod(vec2(x, z) * inv_scale * owner_->relief_scale_, | |
| 576 | 1.0f, 2, 2.0f, 0.5f, rel_lim); | |
| 554 | 577 | float t = dcerosion::clamp(rel.x * 0.5f + 0.5f, 0.0f, 1.0f); |
| 555 | 578 | relief_amp = owner_->relief_floor_ + (1.0f - owner_->relief_floor_) * t; |
| 556 | 579 | } |
| … | … | @@ -563,8 +586,8 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 563 | 586 | float det_offset = 0.0f; |
| 564 | 587 | if (owner_->detail_scale_ > 0.0f) { |
| 565 | 588 | float detail_frac = (y_range > 0.01f) ? (owner_->detail_height_ / y_range) : 0.0f; |
| 566 | vec3 det = dcerosion::fractal_noise_2d(vec2(x, z) * inv_scale * owner_->detail_scale_, | |
| 567 | 1.0f, owner_->detail_octaves_, owner_->noise_lacunarity_, owner_->detail_gain_); | |
| 589 | vec3 det = dcerosion::fractal_noise_2d_lod(vec2(x, z) * inv_scale * owner_->detail_scale_, | |
| 590 | 1.0f, owner_->detail_octaves_, lac, owner_->detail_gain_, det_lim); | |
| 568 | 591 | det_offset = det.x * detail_frac; |
| 569 | 592 | } |
| 570 | 593 |
| … | … | @@ -109,7 +109,13 @@ static const float MAP_MOUNTAIN_HEIGHT = 0.55f; // map_dc_erosion.gd:55 |
| 109 | 109 | static const float MAP_RELIEF_SCALE = 0.5f; // map_dc_erosion.gd:60 |
| 110 | 110 | static const float MAP_RELIEF_FLOOR = 0.08f; // map_dc_erosion.gd:62 |
| 111 | 111 | static const float MAP_MOUNTAIN_GAIN = 0.68f; |
| 112 | static const float MAP_MOUNTAIN_VARIANCE = 0.0f; // generator "mountain_variance" // map_dc_erosion.gd:69 | |
| 112 | static const float MAP_MOUNTAIN_VARIANCE = 0.0f; // generator "mountain_variance" | |
| 113 | ||
| 114 | // The LOD voxel size the wrappers are compared AT. Both sides must use the same | |
| 115 | // value or the Nyquist clamp alone would make them disagree -- the clamp is a | |
| 116 | // function of it. 1.0 m is LOD 0, where nothing is clamped; raise it to compare | |
| 117 | // the wrappers at a coarse LOD instead. | |
| 118 | static float MAP_VOXEL_SIZE = 1.0f; // map_dc_erosion.gd:69 | |
| 113 | 119 | #ifndef MAP_DETAIL_SCALE_OVERRIDE |
| 114 | 120 | #define MAP_DETAIL_SCALE_OVERRIDE 600.0f |
| 115 | 121 | #endif |
| … | … | @@ -149,15 +155,19 @@ static const float EN_HEIGHT_AMP = 0.25f; |
| 149 | 155 | // gn.x * HEIGHT_AMP * 0.5 = gn.x * 0.125. |
| 150 | 156 | static vec3 terrain_offset(float x, float z) { |
| 151 | 157 | const float inv_scale = 1.0f / MAP_TERRAIN_HEIGHT; |
| 152 | vec3 mtn = dcerosion::fractal_multifractal_2d( | |
| 158 | float mtn_lim = dcerosion::nyquist_octaves( | |
| 159 | MAP_TERRAIN_HEIGHT / MAP_MOUNTAIN_SCALE, MAP_VOXEL_SIZE, MAP_NOISE_LACUNARITY); | |
| 160 | vec3 mtn = dcerosion::fractal_multifractal_2d_lod( | |
| 153 | 161 | vec2(x, z) * inv_scale * MAP_MOUNTAIN_SCALE, 1.0f, |
| 154 | 162 | MAP_MOUNTAIN_OCT, MAP_NOISE_LACUNARITY, MAP_MOUNTAIN_GAIN, |
| 155 | MAP_MOUNTAIN_VARIANCE); | |
| 163 | MAP_MOUNTAIN_VARIANCE, mtn_lim); | |
| 156 | 164 | |
| 157 | 165 | float relief_amp = 1.0f; |
| 158 | 166 | if (MAP_RELIEF_SCALE > 0.0f) { |
| 159 | vec3 rel = dcerosion::fractal_noise_2d( | |
| 160 | vec2(x, z) * inv_scale * MAP_RELIEF_SCALE, 1.0f, 2, 2.0f, 0.5f); | |
| 167 | vec3 rel = dcerosion::fractal_noise_2d_lod( | |
| 168 | vec2(x, z) * inv_scale * MAP_RELIEF_SCALE, 1.0f, 2, 2.0f, 0.5f, | |
| 169 | dcerosion::nyquist_octaves(MAP_TERRAIN_HEIGHT / MAP_RELIEF_SCALE, | |
| 170 | MAP_VOXEL_SIZE, 2.0f)); | |
| 161 | 171 | float t = dcerosion::clamp(rel.x * 0.5f + 0.5f, 0.0f, 1.0f); |
| 162 | 172 | relief_amp = MAP_RELIEF_FLOOR + (1.0f - MAP_RELIEF_FLOOR) * t; |
| 163 | 173 | } |
| … | … | @@ -170,9 +180,11 @@ static float detail_offset(float x, float z) { |
| 170 | 180 | if (MAP_DETAIL_SCALE <= 0.0f) return 0.0f; |
| 171 | 181 | const float inv_scale = 1.0f / MAP_TERRAIN_HEIGHT; |
| 172 | 182 | const float y_range = MAP_CEILING_Y - MAP_FLOOR_Y; |
| 173 | vec3 det = dcerosion::fractal_noise_2d( | |
| 183 | vec3 det = dcerosion::fractal_noise_2d_lod( | |
| 174 | 184 | vec2(x, z) * inv_scale * MAP_DETAIL_SCALE, 1.0f, |
| 175 | MAP_DETAIL_OCT, MAP_NOISE_LACUNARITY, MAP_DETAIL_GAIN); | |
| 185 | MAP_DETAIL_OCT, MAP_NOISE_LACUNARITY, MAP_DETAIL_GAIN, | |
| 186 | dcerosion::nyquist_octaves(MAP_TERRAIN_HEIGHT / MAP_DETAIL_SCALE, | |
| 187 | MAP_VOXEL_SIZE, MAP_NOISE_LACUNARITY)); | |
| 176 | 188 | return det.x * (MAP_DETAIL_HEIGHT / y_range); |
| 177 | 189 | } |
| 178 | 190 | |
| … | … | @@ -450,6 +462,7 @@ static std::string build_shader(const std::string& inc) { |
| 450 | 462 | "const float M_FLOOR_Y=%.9g, M_CEIL_Y=%.9g, M_TH=%.9g;\n" |
| 451 | 463 | "const float M_MSCALE=%.9g, M_MHEIGHT=%.9g, M_MGAIN=%.9g;\n" |
| 452 | 464 | "const float M_MVAR=%.9g;\n" |
| 465 | "const float M_VOXEL=%.9g;\n" | |
| 453 | 466 | "const int M_MOCT=%d;\n" |
| 454 | 467 | "const float M_RSCALE=%.9g, M_RFLOOR=%.9g;\n" |
| 455 | 468 | "const float M_DSCALE=%.9g, M_DHEIGHT=%.9g, M_DGAIN=%.9g;\n" |
| … | … | @@ -462,7 +475,7 @@ static std::string build_shader(const std::string& inc) { |
| 462 | 475 | "const float EN_ESCALE=%.9g;\n", |
| 463 | 476 | MAP_FLOOR_Y, MAP_CEILING_Y, MAP_TERRAIN_HEIGHT, |
| 464 | 477 | MAP_MOUNTAIN_SCALE, MAP_MOUNTAIN_HEIGHT, MAP_MOUNTAIN_GAIN, |
| 465 | MAP_MOUNTAIN_VARIANCE, MAP_MOUNTAIN_OCT, | |
| 478 | MAP_MOUNTAIN_VARIANCE, MAP_VOXEL_SIZE, MAP_MOUNTAIN_OCT, | |
| 466 | 479 | MAP_RELIEF_SCALE, MAP_RELIEF_FLOOR, |
| 467 | 480 | MAP_DETAIL_SCALE, MAP_DETAIL_HEIGHT, MAP_DETAIL_GAIN, MAP_DETAIL_OCT, |
| 468 | 481 | MAP_NOISE_LACUNARITY, |
| … | … | @@ -474,10 +487,11 @@ static std::string build_shader(const std::string& inc) { |
| 474 | 487 | s += |
| 475 | 488 | "vec3 terrain_offset(float x, float z) {\n" |
| 476 | 489 | " float inv_scale = 1.0 / M_TH;\n" |
| 477 | " vec3 mtn = fractal_multifractal_2d(vec2(x,z)*inv_scale*M_MSCALE, 1.0, M_MOCT, M_LAC, M_MGAIN, M_MVAR);\n" | |
| 490 | " float mtn_lim = nyquist_octaves(M_TH / M_MSCALE, M_VOXEL, M_LAC);\n" | |
| 491 | " vec3 mtn = fractal_multifractal_2d_lod(vec2(x,z)*inv_scale*M_MSCALE, 1.0, M_MOCT, M_LAC, M_MGAIN, M_MVAR, mtn_lim);\n" | |
| 478 | 492 | " float relief_amp = 1.0;\n" |
| 479 | 493 | " if (M_RSCALE > 0.0) {\n" |
| 480 | " vec3 rel = fractal_noise_2d(vec2(x,z)*inv_scale*M_RSCALE, 1.0, 2, 2.0, 0.5);\n" | |
| 494 | " vec3 rel = fractal_noise_2d_lod(vec2(x,z)*inv_scale*M_RSCALE, 1.0, 2, 2.0, 0.5, nyquist_octaves(M_TH/M_RSCALE, M_VOXEL, 2.0));\n" | |
| 481 | 495 | " float t = clamp(rel.x*0.5+0.5, 0.0, 1.0);\n" |
| 482 | 496 | " relief_amp = M_RFLOOR + (1.0-M_RFLOOR)*t;\n" |
| 483 | 497 | " }\n" |
| … | … | @@ -488,7 +502,7 @@ static std::string build_shader(const std::string& inc) { |
| 488 | 502 | " if (M_DSCALE <= 0.0) return 0.0;\n" |
| 489 | 503 | " float inv_scale = 1.0 / M_TH;\n" |
| 490 | 504 | " float y_range = M_CEIL_Y - M_FLOOR_Y;\n" |
| 491 | " vec3 det = fractal_noise_2d(vec2(x,z)*inv_scale*M_DSCALE, 1.0, M_DOCT, M_LAC, M_DGAIN);\n" | |
| 505 | " vec3 det = fractal_noise_2d_lod(vec2(x,z)*inv_scale*M_DSCALE, 1.0, M_DOCT, M_LAC, M_DGAIN, nyquist_octaves(M_TH/M_DSCALE, M_VOXEL, M_LAC));\n" | |
| 492 | 506 | " return det.x * (M_DHEIGHT / y_range);\n" |
| 493 | 507 | "}\n" |
| 494 | 508 | "float y_mapped_of(float y, float det_off) {\n" |
| … | … | @@ -538,6 +552,7 @@ int main(int argc, char** argv) { |
| 538 | 552 | for (int i = 1; i < argc; i++) { |
| 539 | 553 | if (!strcmp(argv[i], "--inc") && i + 1 < argc) inc_path = argv[++i]; |
| 540 | 554 | else if (!strcmp(argv[i], "--columns") && i + 1 < argc) columns = atoi(argv[++i]); |
| 555 | else if (!strcmp(argv[i], "--voxel") && i + 1 < argc) MAP_VOXEL_SIZE = (float)atof(argv[++i]); | |
| 541 | 556 | } |
| 542 | 557 | |
| 543 | 558 | std::string inc = read_file(inc_path); |