| … | … | @@ -541,6 +541,30 @@ void DCTerrainGeneratorProcNodes::_collect_node_data() { |
| 541 | 541 | if (d.is_empty()) continue; |
| 542 | 542 | hblk_.assign(d.ptr(), d.ptr() + d.size()); |
| 543 | 543 | hblk_version_++; |
| 544 | // THE PACKED TILE GRID, if the node supplied one. Without this the CPU |
| 545 | // twin would keep reading the buffer as a single hblk_n_ square -- which |
| 546 | // is now the INDEX TABLE followed by tile rects, so it would return |
| 547 | // table entries as elevations and the collision surface would be |
| 548 | // somewhere else entirely from the rendered one. |
| 549 | hgrid_ = HeightGridDesc(); |
| 550 | if (node_obj->has_method("get_grid_info")) { |
| 551 | Dictionary gi = node_obj->call("get_grid_info"); |
| 552 | if ((bool)gi.get("active", false)) { |
| 553 | hgrid_.nx = (int)gi.get("nx", 0); |
| 554 | hgrid_.ny = (int)gi.get("ny", 0); |
| 555 | hgrid_.tx0 = (int)gi.get("tx0", 0); |
| 556 | hgrid_.ty0 = (int)gi.get("ty0", 0); |
| 557 | hgrid_.payload = (int)gi.get("payload", 0); |
| 558 | hgrid_.apron = (int)gi.get("apron", 0); |
| 559 | hgrid_.n = (int)gi.get("n", 0); |
| 560 | hgrid_.table = (int)gi.get("table", 0); |
| 561 | hgrid_.mpp = (float)(double)gi.get("mpp", 30.0); |
| 562 | hgrid_.stub = (float)(double)gi.get("stub", 0.0); |
| 563 | UtilityFunctions::print("[DCTerrainGeneratorProcNodes] tile grid ", |
| 564 | hgrid_.nx, "x", hgrid_.ny, " cells, ", (int)gi.get("tiles", 0), |
| 565 | " tiles resident"); |
| 566 | } |
| 567 | } |
| 544 | 568 | // ASK THE NODE FOR THE SIDE LENGTH; DO NOT DERIVE IT FROM THE ARRAY. |
| 545 | 569 | // |
| 546 | 570 | // get_gpu_data() returns the MIP PYRAMID, not one square: 1,403,226 |
| … | … | @@ -572,6 +596,26 @@ void DCTerrainGeneratorProcNodes::_collect_node_data() { |
| 572 | 596 | } |
| 573 | 597 | } |
| 574 | 598 | |
| 599 | // ONE CPU heightfield sampler, for the four sites that used to each carry their |
| 600 | // own bilinear. Paged when the node supplied a tile grid, a plain square |
| 601 | // otherwise -- and the paged half is erosion_wrapper_glsl.h's, the same file |
| 602 | // that emits the GLSL, so the twin cannot drift. |
| 603 | float DCTerrainGeneratorProcNodes::_hblk_sample_cpu(float x, float z) const { |
| 604 | if (hblk_.empty()) return 0.0f; |
| 605 | if (hgrid_.active()) |
| 606 | return erosion_heightmap_grid_sample(hblk_.data(), hgrid_, x, z); |
| 607 | const int hn = hblk_n_; |
| 608 | const float u0 = dcerosion::clamp((x - hblk_ox_) / hblk_mpp_, 0.0f, (float)(hn - 1)); |
| 609 | const float v0 = dcerosion::clamp((z - hblk_oz_) / hblk_mpp_, 0.0f, (float)(hn - 1)); |
| 610 | const int i0 = (int)floorf(u0), j0 = (int)floorf(v0); |
| 611 | const int i1 = MIN(i0 + 1, hn - 1), j1 = MIN(j0 + 1, hn - 1); |
| 612 | const float fu = u0 - (float)i0, fv = v0 - (float)j0; |
| 613 | const float h00 = hblk_[(size_t)j0*hn + i0], h10 = hblk_[(size_t)j0*hn + i1]; |
| 614 | const float h01 = hblk_[(size_t)j1*hn + i0], h11 = hblk_[(size_t)j1*hn + i1]; |
| 615 | const float a = h00 + (h10 - h00) * fu, b = h01 + (h11 - h01) * fu; |
| 616 | return a + (b - a) * fv; |
| 617 | } |
| 618 | |
| 575 | 619 | void DCTerrainGeneratorProcNodes::_discover_params() { |
| 576 | 620 | discovered_params_.clear(); |
| 577 | 621 | if (graph_.is_null()) return; |
| … | … | @@ -1235,18 +1279,8 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 1235 | 1279 | if (!graph_has_erosion && owner_->hblk_n_ > 0) { |
| 1236 | 1280 | // Heightfield alone: density IS height minus query, exactly what the |
| 1237 | 1281 | // node emits. No filter space, no offsets, nothing to get wrong. |
| 1238 | | const std::vector<float> &hb = owner_->hblk_; |
| 1239 | | const int hn = owner_->hblk_n_; |
| 1240 | | const float hox = owner_->hblk_ox_, hoz = owner_->hblk_oz_, hmpp = owner_->hblk_mpp_; |
| 1241 | | float u = dcerosion::clamp((x - hox) / hmpp, 0.0f, (float)(hn - 1)); |
| 1242 | | float v = dcerosion::clamp((z - hoz) / hmpp, 0.0f, (float)(hn - 1)); |
| 1243 | | int i0 = (int)floorf(u), j0 = (int)floorf(v); |
| 1244 | | int i1 = MIN(i0 + 1, hn - 1), j1 = MIN(j0 + 1, hn - 1); |
| 1245 | | float fu = u - (float)i0, fv = v - (float)j0; |
| 1246 | | float h00 = hb[(size_t)j0*hn + i0], h10 = hb[(size_t)j0*hn + i1]; |
| 1247 | | float h01 = hb[(size_t)j1*hn + i0], h11 = hb[(size_t)j1*hn + i1]; |
| 1248 | | float a0 = h00 + (h10 - h00) * fu, b0 = h01 + (h11 - h01) * fu; |
| 1249 | | float d = (a0 + (b0 - a0) * fv) - y; |
| 1282 | const float hmpp = owner_->hblk_mpp_; |
| 1283 | float d = owner_->_hblk_sample_cpu(x, z) - y; |
| 1250 | 1284 | d = MAX(d, (floor_y - y) * 2.0f); |
| 1251 | 1285 | d = MIN(d, (ceiling_y - y) * 2.0f); |
| 1252 | 1286 | return d; |
| … | … | @@ -1257,18 +1291,8 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 1257 | 1291 | // this on, the field is not reaching the GPU and this is what you are |
| 1258 | 1292 | // standing on instead. |
| 1259 | 1293 | if (owner_->heightfield_only_ && owner_->hblk_n_ > 0) { |
| 1260 | | const std::vector<float> &hbv = owner_->hblk_; |
| 1261 | | const int hn = owner_->hblk_n_; |
| 1262 | | const float hox = owner_->hblk_ox_, hoz = owner_->hblk_oz_, hmpp = owner_->hblk_mpp_; |
| 1263 | | float u = dcerosion::clamp((x - hox) / hmpp, 0.0f, (float)(hn - 1)); |
| 1264 | | float v = dcerosion::clamp((z - hoz) / hmpp, 0.0f, (float)(hn - 1)); |
| 1265 | | int i0 = (int)floorf(u), j0 = (int)floorf(v); |
| 1266 | | int i1 = MIN(i0 + 1, hn - 1), j1 = MIN(j0 + 1, hn - 1); |
| 1267 | | float fu = u - (float)i0, fv = v - (float)j0; |
| 1268 | | float h00 = hbv[(size_t)j0*hn + i0], h10 = hbv[(size_t)j0*hn + i1]; |
| 1269 | | float h01 = hbv[(size_t)j1*hn + i0], h11 = hbv[(size_t)j1*hn + i1]; |
| 1270 | | float a0 = h00 + (h10 - h00) * fu, b0 = h01 + (h11 - h01) * fu; |
| 1271 | | float d = (a0 + (b0 - a0) * fv) - y; |
| 1294 | const float hmpp = owner_->hblk_mpp_; |
| 1295 | float d = owner_->_hblk_sample_cpu(x, z) - y; |
| 1272 | 1296 | d = MAX(d, (floor_y - y) * 2.0f); |
| 1273 | 1297 | d = MIN(d, (ceiling_y - y) * 2.0f); |
| 1274 | 1298 | return d; |
| … | … | @@ -1313,20 +1337,9 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 1313 | 1337 | // The algebra is erosion_wrapper_glsl.h's erosion_heightmap_gn_cpu, sitting |
| 1314 | 1338 | // beside the GLSL it mirrors, so the two cannot drift apart quietly. |
| 1315 | 1339 | if (owner_->hblk_n_ > 0) { |
| 1316 | | const std::vector<float> &hb = owner_->hblk_; |
| 1317 | | const int hn = owner_->hblk_n_; |
| 1318 | | const float hox = owner_->hblk_ox_, hoz = owner_->hblk_oz_, hmpp = owner_->hblk_mpp_; |
| 1340 | const float hmpp = owner_->hblk_mpp_; |
| 1319 | 1341 | auto sample = [&](float sx, float sz) -> float { |
| 1320 | | float u = dcerosion::clamp((sx - hox) / hmpp, 0.0f, (float)(hn - 1)); |
| 1321 | | float v = dcerosion::clamp((sz - hoz) / hmpp, 0.0f, (float)(hn - 1)); |
| 1322 | | int i0 = (int)floorf(u), j0 = (int)floorf(v); |
| 1323 | | int i1 = MIN(i0 + 1, hn - 1), j1 = MIN(j0 + 1, hn - 1); |
| 1324 | | float fu = u - (float)i0, fv = v - (float)j0; |
| 1325 | | float h00 = hb[(size_t)j0*hn + i0], h10 = hb[(size_t)j0*hn + i1]; |
| 1326 | | float h01 = hb[(size_t)j1*hn + i0], h11 = hb[(size_t)j1*hn + i1]; |
| 1327 | | float a0 = h00 + (h10 - h00) * fu; |
| 1328 | | float b0 = h01 + (h11 - h01) * fu; |
| 1329 | | return a0 + (b0 - a0) * fv; |
| 1342 | return owner_->_hblk_sample_cpu(sx, sz); |
| 1330 | 1343 | }; |
| 1331 | 1344 | float oh, odx, odz; |
| 1332 | 1345 | erosion_heightmap_gn_cpu(x, z, floor_y, ceiling_y, terrain_height, |
| … | … | @@ -1339,22 +1352,9 @@ float DCTerrainGeneratorProcNodes::ProcNodesBridge::evaluate( |
| 1339 | 1352 | // divergence here is a player falling through ground that is visibly there. |
| 1340 | 1353 | // The algebra comes from erosion_wrapper_glsl.h, beside the GLSL twin. |
| 1341 | 1354 | if (owner_->hblk_n_ > 0) { |
| 1342 | | const std::vector<float> &hb = owner_->hblk_; |
| 1343 | | const int hn = owner_->hblk_n_; |
| 1344 | | const float hox = owner_->hblk_ox_, hoz = owner_->hblk_oz_, hmpp = owner_->hblk_mpp_; |
| 1355 | const float hmpp = owner_->hblk_mpp_; |
| 1345 | 1356 | auto sample = [&](float sx, float sz) -> float { |
| 1346 | | float u = (sx - hox) / hmpp; |
| 1347 | | float v = (sz - hoz) / hmpp; |
| 1348 | | u = dcerosion::clamp(u, 0.0f, (float)(hn - 1)); |
| 1349 | | v = dcerosion::clamp(v, 0.0f, (float)(hn - 1)); |
| 1350 | | int i0 = (int)floorf(u), j0 = (int)floorf(v); |
| 1351 | | int i1 = MIN(i0 + 1, hn - 1), j1 = MIN(j0 + 1, hn - 1); |
| 1352 | | float fu = u - (float)i0, fv = v - (float)j0; |
| 1353 | | float h00 = hb[(size_t)j0 * hn + i0], h10 = hb[(size_t)j0 * hn + i1]; |
| 1354 | | float h01 = hb[(size_t)j1 * hn + i0], h11 = hb[(size_t)j1 * hn + i1]; |
| 1355 | | float a = h00 + (h10 - h00) * fu; |
| 1356 | | float b = h01 + (h11 - h01) * fu; |
| 1357 | | return a + (b - a) * fv; |
| 1357 | return owner_->_hblk_sample_cpu(sx, sz); |
| 1358 | 1358 | }; |
| 1359 | 1359 | float oh, odx, odz; |
| 1360 | 1360 | erosion_heightmap_gn_cpu(x, z, floor_y, ceiling_y, terrain_height, |