diff --git a/src/app/TileBasemap.cpp b/src/app/TileBasemap.cpp index 636c15b..181bee5 100644 --- a/src/app/TileBasemap.cpp +++ b/src/app/TileBasemap.cpp @@ -180,6 +180,17 @@ void TileBasemap::refineTile(int z, int x, int y, std::set& out, int& const geopro::render::LonLatBox b = geopro::render::tileBounds(z, x, y); const auto sw = frame_->toLocal(b.south, b.west); const auto ne = frame_->toLocal(b.north, b.east); + + // 视锥剔除:瓦片 AABB 全在某视锥面外侧 → 不在视野内,直接丢弃(否则会在屏幕外乱细分耗尽预算)。 + const double zmin = -1000.0, zmax = 1000.0; // 地形起伏远小于瓦片尺度,给宽松 z 带 + for (int p = 0; p < 6; ++p) { + const double* pl = &frustum_[p * 4]; // 内法向:内侧 a·x+b·y+c·z+d ≥ 0 + const double vx = pl[0] >= 0 ? ne.x : sw.x; // 取最朝法向的角点(p-vertex) + const double vy = pl[1] >= 0 ? ne.y : sw.y; + const double vz = pl[2] >= 0 ? zmax : zmin; + if (pl[0] * vx + pl[1] * vy + pl[2] * vz + pl[3] < 0.0) return; // 全在外 → 剔除 + } + const double cx = (sw.x + ne.x) * 0.5, cy = (sw.y + ne.y) * 0.5; // 瓦片中心(局部米) const double g = std::max(std::abs(ne.x - sw.x), std::abs(ne.y - sw.y)); // 瓦片地面尺寸(米) @@ -219,6 +230,16 @@ void TileBasemap::refresh() { projParallel_ = cam->GetParallelProjection(); projK_ = projParallel_ ? H / (2.0 * std::max(1.0, cam->GetParallelScale())) : H / (2.0 * std::tan(cam->GetViewAngle() * 0.5 * kPi / 180.0)); + const double aspect = (sz && sz[1] > 0) ? double(sz[0]) / double(sz[1]) : 1.0; + cam->GetFrustumPlanes(aspect, frustum_); // 6 视锥面(供 refineTile 剔除屏幕外瓦片) + // 用焦点(必在视锥内)统一各面方向为"内侧≥0",规避 VTK 法向内/外约定差异(否则可能全剔成黑屏)。 + double fp[3]; + cam->GetFocalPoint(fp); + for (int p = 0; p < 6; ++p) { + double* pl = &frustum_[p * 4]; + if (pl[0] * fp[0] + pl[1] * fp[1] + pl[2] * fp[2] + pl[3] < 0.0) + for (int k = 0; k < 4; ++k) pl[k] = -pl[k]; + } // 四叉树:从数据中心一圈粗根块出发,按屏幕误差细分 → 近细远粗、铺满视野,无单层级盲区。 desired_.clear(); diff --git a/src/app/TileBasemap.hpp b/src/app/TileBasemap.hpp index 05862d7..971c534 100644 --- a/src/app/TileBasemap.hpp +++ b/src/app/TileBasemap.hpp @@ -71,10 +71,11 @@ private: std::set inFlight_; // 在途瓦片(续到起伏/平面最终落地) std::map demCache_; // DEM 块缓存(key=DEMz/x/y),跨隐藏/重选复用 std::map> texCache_; // 影像纹理缓存,重选/缩放回看免重拉 - // 四叉树当前帧相机参数(refresh 写, refineTile 读):相机位置 + 投影系数。 + // 四叉树当前帧相机参数(refresh 写, refineTile 读):相机位置 + 投影系数 + 视锥 6 面。 double camX_ = 0, camY_ = 0, camZ_ = 0; double projK_ = 1.0; bool projParallel_ = false; + double frustum_[24] = {0}; // 6 个视锥平面(内法向),AABB 全在某面外则剔除 struct PendingGet { QString url; std::function cb; }; std::deque netQueue_; // 限并发请求队列(防瓦片暴发饱和卡死) int netInFlight_ = 0;