perf(vtk): 撤销防抖定时器,改合并渲染(requestRender:同事件循环多次请求只渲一帧)治滚轮卡顿-根因是逐瓦片重复Render

This commit is contained in:
gaozheng 2026-06-17 15:09:00 +08:00
parent 69a81b2eac
commit fd43051d8d
2 changed files with 24 additions and 17 deletions

View File

@ -8,7 +8,6 @@
#include <QDebug>
#include <QImage>
#include <QNetworkReply>
#include <QTimer>
#include <QNetworkRequest>
#include <QString>
#include <QUrl>
@ -108,10 +107,19 @@ long long TileBasemap::tileKey(int z, int x, int y) {
TileBasemap::TileBasemap(geopro::render::Scene& scene, vtkRenderWindow* rw,
std::shared_ptr<geopro::core::GeoLocalFrame> frame, QObject* parent)
: QObject(parent), scene_(scene), rw_(rw), frame_(std::move(frame)) {
refreshTimer_ = new QTimer(this);
refreshTimer_->setSingleShot(true);
connect(refreshTimer_, &QTimer::timeout, this, [this]() { refresh(); });
: QObject(parent), scene_(scene), rw_(rw), frame_(std::move(frame)) {}
void TileBasemap::requestRender() {
// 合并渲染:同一事件循环轮次内的多次请求只渲染一帧(标准做法,避免逐瓦片重复 Render 卡顿)。
if (renderPending_) return;
renderPending_ = true;
QMetaObject::invokeMethod(
this,
[this]() {
renderPending_ = false;
if (rw_) rw_->Render();
},
Qt::QueuedConnection);
}
TileBasemap::~TileBasemap() {
@ -133,8 +141,7 @@ void TileBasemap::ensureObserver() {
}
void TileBasemap::onInteractionEnd(vtkObject*, unsigned long, void* clientData, void*) {
// 防抖:交互(滚轮/旋转/平移)停止 ~140ms 后才刷新四叉树,避免每格事件都重算卡顿。
if (auto* self = static_cast<TileBasemap*>(clientData)) self->refreshTimer_->start(140);
if (auto* self = static_cast<TileBasemap*>(clientData)) self->refresh();
}
void TileBasemap::enqueueGet(const QString& url, std::function<void(QNetworkReply*)> onDone) {
@ -172,7 +179,7 @@ void TileBasemap::show(Kind kind) {
terrainProbed_ = false;
kind_ = kind;
if (kind == Hidden) {
if (rw_) rw_->Render();
requestRender();
return;
}
refresh(); // 四叉树覆盖:近细远粗一次铺满(含远处粗块,无需单独粗底层)
@ -266,7 +273,7 @@ void TileBasemap::refresh() {
purgeStale();
ren->ResetCameraClippingRange(); // 交互后扩裁剪面以含新载入的底图瓦片(防被"蒙版"切)
if (rw_) rw_->Render();
requestRender();
refreshing_ = false;
}
@ -284,7 +291,7 @@ void TileBasemap::purgeStale() {
++it;
}
}
if (removed && rw_) rw_->Render();
if (removed) requestRender();
}
void TileBasemap::fetchTile(int z, int x, int y, long long key) {
@ -299,7 +306,7 @@ void TileBasemap::fetchTile(int z, int x, int y, long long key) {
placeActor(key, buildFlat(z, x, y, tex));
inFlight_.erase(key);
purgeStale();
if (rw_) rw_->Render();
requestRender();
}
return;
}
@ -331,7 +338,7 @@ void TileBasemap::fetchTile(int z, int x, int y, long long key) {
if (!ok) {
inFlight_.erase(key);
purgeStale();
if (rw_) rw_->Render();
requestRender();
return;
}
auto tex = makeTexture(img);
@ -343,7 +350,7 @@ void TileBasemap::fetchTile(int z, int x, int y, long long key) {
placeActor(key, buildFlat(z, x, y, tex)); // 街道图无地形 → 直接平面
inFlight_.erase(key);
purgeStale();
if (rw_) rw_->Render();
requestRender();
}
});
}
@ -410,7 +417,7 @@ void TileBasemap::fetchTerrain(int z, int x, int y, long long key, vtkSmartPoint
}
inFlight_.erase(key);
purgeStale();
if (rw_) rw_->Render();
requestRender();
};
// 命中缓存:同一祖先 DEM 块的多个瓦片瞬间起伏,免重复网络。
@ -439,7 +446,7 @@ void TileBasemap::fetchTerrain(int z, int x, int y, long long key, vtkSmartPoint
desired_.find(key) == desired_.end() || placed_.count(key)) {
inFlight_.erase(key); // 过期/移出视野 → 不落地
purgeStale();
if (rw_) rw_->Render();
requestRender();
return;
}
QImage dem;

View File

@ -20,7 +20,6 @@ class vtkRenderWindow;
class vtkInteractorObserver;
class vtkCallbackCommand;
class QNetworkReply;
class QTimer;
namespace geopro::render { class Scene; }
namespace geopro::core { class GeoLocalFrame; }
@ -43,6 +42,7 @@ public:
private:
static long long tileKey(int z, int x, int y);
void ensureObserver(); // 首次显示时挂到交互样式的 EndInteractionEvent
void requestRender(); // 合并渲染:同一事件循环轮次多次请求只渲染一帧
void purgeStale(); // 本轮请求全部落地后再删旧层瓦片,避免缩放空白闪烁
// 四叉树细分:按瓦片投影屏幕尺寸递归(近细远粗),收集叶瓦片到 out。
void refineTile(int z, int x, int y, std::set<long long>& out, int& count);
@ -85,7 +85,7 @@ private:
bool terrainProbed_ = false; // 首次 fetchTerrain 打一行诊断日志
vtkSmartPointer<vtkInteractorObserver> styleObs_; // 持引用保证回调期有效
vtkSmartPointer<vtkCallbackCommand> observer_;
QTimer* refreshTimer_ = nullptr; // 交互防抖:滚轮/旋转停止后才刷新四叉树(避免每格卡)
bool renderPending_ = false; // 合并渲染:同轮多次请求只渲染一帧
bool refreshing_ = false;
};