Q3DSurface仅绘制数据范围一半的问题排查求助
问题根源与修复方案
核心问题分析
渲染范围仅显示0到50的核心原因是每次调用generateWaterfallData时重复执行m_surfaceGraph->addSeries(m_sqrtSinSeries),同一个系列被多次添加到图表中,干扰了Q3DSurface的渲染逻辑,最终导致仅显示部分数据。
此外还有两个次要问题:
- 每次生成数据时重复设置轴的标题、格式、旋转等属性,造成不必要的性能浪费
timerEvent中传递的t值过大(QTime::currentTime().msecsSinceStartOfDay()返回当天毫秒数,最大可达~8.6e7),导致std::sin(k_x * x + omega * t)的参数超出有效计算范围,动画效果异常
修复步骤
1. 仅初始化一次系列与轴属性
将添加系列、设置轴标题/格式/旋转等初始化操作移到initialize函数中,避免重复执行:
bool Waterfall3dChart::initialize() { if (!m_surfaceGraph->hasContext()) return false; m_surfaceWidget = new QWidget; auto* hLayout = new QHBoxLayout(m_surfaceWidget); m_container = QWidget::createWindowContainer(m_surfaceGraph, m_surfaceWidget); m_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_container->setFocusPolicy(Qt::StrongFocus); hLayout->addWidget(m_container, 1); auto* vLayout = new QVBoxLayout(); hLayout->addLayout(vLayout); vLayout->setAlignment(Qt::AlignTop); m_surfaceGraph->scene()->activeCamera()->setZoomLevel(85.f); m_surfaceGraph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricRight); m_surfaceGraph->activeTheme()->setType(Q3DTheme::ThemeRetro); m_surfaceGraph->setAxisX(new QValue3DAxis); m_surfaceGraph->setAxisY(new QValue3DAxis); m_surfaceGraph->setAxisZ(new QValue3DAxis); // 初始化轴属性(仅执行一次) m_surfaceGraph->axisX()->setLabelFormat("%.2f"); m_surfaceGraph->axisZ()->setLabelFormat("%.2f"); m_surfaceGraph->axisX()->setRange(0, 100); m_surfaceGraph->axisY()->setRange(sampleMin, sampleMax); m_surfaceGraph->axisZ()->setRange(0, 100); m_surfaceGraph->axisX()->setLabelAutoRotation(30.f); m_surfaceGraph->axisY()->setLabelAutoRotation(90.f); m_surfaceGraph->axisZ()->setLabelAutoRotation(30.f); m_surfaceGraph->axisX()->setTitleVisible(true); m_surfaceGraph->axisY()->setTitleVisible(true); m_surfaceGraph->axisZ()->setTitleVisible(true); m_surfaceGraph->axisX()->setTitle("X"); m_surfaceGraph->axisY()->setTitle("Y"); m_surfaceGraph->axisZ()->setTitle("Z"); m_sqrtSinProxy = new QSurfaceDataProxy(); m_sqrtSinSeries = new QSurface3DSeries(m_sqrtSinProxy); setGradient(); m_sqrtSinSeries->setDrawMode(QSurface3DSeries::DrawFlag::DrawSurfaceAndWireframe); m_sqrtSinSeries->setFlatShadingEnabled(true); // 仅添加一次系列 m_surfaceGraph->addSeries(m_sqrtSinSeries); return true; }
2. 简化generateWaterfallData函数
移除重复的初始化代码,只保留数据生成和必要的轴范围调整:
void Waterfall3dChart::generateWaterfallData(float t) { const int SIZE = 100; // Define the size of the grid const double A = 0.7; // Amplitude const double k_x = 0.1; // Wave number in x direction const double k_y = 0.1; // Wave number in y direction const double omega = 1; // Angular frequency (Increase it to increase animation speed) float z; auto* dataArray = new QSurfaceDataArray; dataArray->reserve(SIZE); for (int x = 0; x < SIZE; ++x) { auto* newRow = new QSurfaceDataRow; newRow->reserve(SIZE); for (int y = 0; y < SIZE; ++y) { // Combine sine and Gaussian functions z = A * std::sin(k_x * x + omega * t) + std::cos(k_y * y); newRow->append(QSurfaceDataItem({(float)x, z, (float)y})); } dataArray->append(newRow); } // 仅在SIZE动态变化时调整轴范围,否则可移除 m_surfaceGraph->axisX()->setRange(0, SIZE); m_surfaceGraph->axisZ()->setRange(0, SIZE); m_sqrtSinProxy->resetArray(dataArray); }
3. 修复时间参数t的溢出问题
添加成员变量记录累计时间,避免过大的参数值:
在Waterfall3DChart.h的private区域添加:
private: // ... 现有成员 ... float m_elapsedTime = 0.f;
修改timerEvent函数:
void Waterfall3dChart::timerEvent(QTimerEvent* event) { // 按定时器间隔累加时间,保证动画平滑 m_elapsedTime += 0.1f; generateWaterfallData(m_elapsedTime); }
验证修复
完成上述修改后,Q3DSurface会正确渲染0到100范围的完整曲面,动画效果也会恢复正常。
内容的提问来源于stack exchange,提问作者Soroush Shariaty
相关产品推荐
相关产品推荐

