Add line rendering to surface3D

Task-number: QTBUG-134716
Change-Id: I71d704087cae6dcb9ec2d989803d553f00d6eda3
Reviewed-by: Sami Varanka <sami.varanka@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
This commit is contained in:
Sakaria Pouke 2025-05-14 13:08:06 +03:00
parent 3ce7bc6c26
commit e1ccf0406a
7 changed files with 231 additions and 12 deletions

View File

@ -45,12 +45,16 @@ void MAIN()
// keep sides flat shaded always
if (flatShading || sides || overhigh > 0) {
vec3 dpdx = dFdx(VAR_WORLD_POSITION);
vec3 dpdy = dFdy(VAR_WORLD_POSITION);
vec3 n = normalize(cross(dpdy,dpdx));
if (NEAR_CLIP_VALUE < 0.0) //effectively: if openGL
n = normalize(cross(dpdx,dpdy));
NORMAL = n;
if (lineData && !sides) {
NORMAL = -CAMERA_DIRECTION;
} else {
vec3 dpdx = dFdx(VAR_WORLD_POSITION);
vec3 dpdy = dFdy(VAR_WORLD_POSITION);
vec3 n = normalize(cross(dpdy,dpdx));
if (NEAR_CLIP_VALUE < 0.0) //effectively: if openGL
n = normalize(cross(dpdx,dpdy));
NORMAL = n;
}
}
diffuse = vec4(color);
BASE_COLOR = diffuse;

View File

@ -4,6 +4,7 @@
#include <QtCore/QMutexLocker>
#include "private/qquick3drepeater_p.h"
#include "q3dscene.h"
#include "qabstractdataproxy.h"
#include "qquickgraphssurface_p.h"
#include "qcategory3daxis_p.h"
@ -1274,7 +1275,7 @@ QRect QQuickGraphsSurface::calculateSampleSpace(SurfaceModel *model)
QRect sampleSpace;
const QSurfaceDataArray &array = model->series->dataArray();
if (array.size() > 0) {
if (array.size() >= 2 && array.at(0).size() >= 2) {
if (array.size() >= 1 && array.at(0).size() >= 1) {
const qsizetype maxRow = array.size() - 1;
const qsizetype maxColumn = array.at(0).size() - 1;
@ -1350,6 +1351,8 @@ void QQuickGraphsSurface::updateModel(SurfaceModel *model)
columnCount = qMin(maxSize, columnCount);
rowCount = qMin(maxSize, rowCount);
bool lineData = (rowCount == 1 || columnCount == 1);
if (model->rowCount != rowCount) {
model->rowCount = rowCount;
setIndexDirty(true);
@ -1425,6 +1428,7 @@ void QQuickGraphsSurface::updateModel(SurfaceModel *model)
if (dimensionsChanged)
heightMapData->setSize(QSize(sampleSpace.width(), sampleSpace.height()));
}
if (heightMapData->size().width() < 1 || heightMapData->size().height() < 1) {
heightMapData->setTextureData(QByteArray());
heightMap->setTextureData(heightMapData);
@ -1443,6 +1447,7 @@ void QQuickGraphsSurface::updateModel(SurfaceModel *model)
material->setProperty("flipU", !model->ascendingX);
material->setProperty("flipV", !model->ascendingZ);
material->setProperty("fill", model->series->drawMode().testFlag(QSurface3DSeries::DrawFilledSurface));
material->setProperty("lineData", lineData);
for (int i = 0; i < m_seriesList.size(); i++) {
if (m_seriesList.at(i) == model->series)
material->setProperty("order", i);
@ -1505,7 +1510,15 @@ void QQuickGraphsSurface::updateModel(SurfaceModel *model)
vertices.push_back(vertex);
}
}
createIndices(model, columnCount, rowCount);
if (lineData) {
createLineIndices(model, rowCount);
model->model->geometry()->setPrimitiveType(QQuick3DGeometry::PrimitiveType::LineStrip);
} else {
createIndices(model, columnCount, rowCount);
model->model->geometry()->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
}
auto geometry = model->model->geometry();
geometry->vertexData().clear();
QByteArray vertexBuffer(reinterpret_cast<char *>(vertices.data()),
@ -1543,8 +1556,12 @@ void QQuickGraphsSurface::updateModel(SurfaceModel *model)
gridMaterial->setProperty("fill", model->series->drawMode().testFlag(QSurface3DSeries::DrawFilledSurface));
m_proxyDirty = true;
if (lineData)
updateLineFill(model);
else
updateFill(model);
}
updateFill(model);
updateMaterial(model);
updateSelectedPoint();
}
@ -1658,6 +1675,81 @@ void QQuickGraphsSurface::updateFill(SurfaceModel *model)
model->series->drawMode().testFlag(QSurface3DSeries::DrawFilledSurface) && surfaceVisible);
}
void QQuickGraphsSurface::updateLineFill(SurfaceModel *model)
{
bool fillVisible = model->series->drawMode().testFlag(QSurface3DSeries::DrawFilledSurface);
if (m_fillDirty[model] && fillVisible) {
qsizetype rowCount = model->rowCount;
qsizetype colCount = model->columnCount;
bool oneRow = rowCount == 1;
float uvX = 1.0f / qMax(float(colCount - 1), 1.0f);
float uvY = 1.0f / qMax(float(rowCount - 1), 1.0f);
QVector<SurfaceVertex> vertices;
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < colCount; j++) {
SurfaceVertex vertex;
QVector3D pos = QVector3D(0, 0, 0);
vertex.position = pos;
vertex.uv = QVector2D(j * uvX, i * uvY);
vertex.coord = QPoint(j, i);
float base = -scaleWithBackground().y();
QVector2D uvOffset;
if (oneRow)
uvOffset = QVector2D(0.0f, -0.1f);
else
uvOffset = QVector2D(-0.1f, 0.0f);
vertex.uv += uvOffset * 0.1f;
SurfaceVertex botVert = vertex;
botVert.position.setY(base);
botVert.uv += uvOffset;
vertices.push_back(vertex);
vertices.push_back(botVert);
}
}
QVector<quint32> indices;
int totVerts = oneRow? colCount : rowCount;
int idxCount = 6 * (totVerts);
indices.reserve(idxCount);
for (int i = 0; i < totVerts - 1; i++) {
quint32 start = i * 2 ;
indices.push_back(start + 2);
indices.push_back(start);
indices.push_back(start + 1);
indices.push_back(start + 2);
indices.push_back(start + 1);
indices.push_back(start + 3);
}
QByteArray indexBuffer(reinterpret_cast<char *>(indices.data()),
indices.size() * sizeof(quint32));
auto sideGeom = model->fillModel->geometry();
QByteArray fillVertBuffer(reinterpret_cast<char *>(vertices.data()),
vertices.size() * sizeof(SurfaceVertex));
sideGeom->setVertexData(fillVertBuffer);
sideGeom->setBounds(model->boundsMin, model->boundsMax);
sideGeom->setIndexData(indexBuffer);
sideGeom->update();
m_fillDirty[model] = false;
}
bool surfaceVisible = model->series->drawMode().testFlag(QSurface3DSeries::DrawSurface)
&& model->series->isVisible();
model->fillModel->setVisible(
model->series->drawMode().testFlag(QSurface3DSeries::DrawFilledSurface) && surfaceVisible);
}
void QQuickGraphsSurface::updateProxyModel(SurfaceModel *model)
{
if (!model->proxyModel)
@ -2166,6 +2258,15 @@ void QQuickGraphsSurface::createIndices(SurfaceModel *model, qsizetype columnCou
}
}
}
void QQuickGraphsSurface::createLineIndices(SurfaceModel *model, qsizetype pointCount)
{
model->indices.clear();
model->gridIndices.reserve(pointCount);
for (int i = 0; i < pointCount; i++)
model->indices.push_back(i);
}
void QQuickGraphsSurface::createGridlineIndices(SurfaceModel *model, qsizetype x, qsizetype y, qsizetype endX, qsizetype endY)
{
qsizetype columnCount = model->columnCount;

View File

@ -233,10 +233,12 @@ private:
QPointF mapCoordsToWorldSpace(SurfaceModel *model, QPointF coords);
QPoint mapCoordsToSampleSpace(SurfaceModel *model, QPointF coords);
void createIndices(SurfaceModel *model, qsizetype columnCount, qsizetype rowCount);
void createLineIndices(SurfaceModel *model, qsizetype pointCount);
void createGridlineIndices(SurfaceModel *model, qsizetype x, qsizetype y, qsizetype endX, qsizetype endY);
void handleChangedSeries();
void updateModel(SurfaceModel *model);
void updateFill(SurfaceModel *model);
void updateLineFill(SurfaceModel *model);
void createProxyModel(SurfaceModel *parentModel);
void updateProxyModel(SurfaceModel *model);
void updateMaterial(SurfaceModel *model);

View File

@ -24,6 +24,7 @@ CustomMaterial {
property bool flatShading: false
property int colorStyle: 0
property bool fill: false
property bool lineData: false
property bool flipU: false
property bool flipV: false

View File

@ -25,6 +25,7 @@ GraphModifier::GraphModifier(Q3DSurfaceWidgetItem *graph)
m_series2(new QSurface3DSeries),
m_series3(new QSurface3DSeries),
m_series4(new QSurface3DSeries),
m_lineSeries(new QSurface3DSeries),
m_gridSliderX(0),
m_gridSliderZ(0),
m_axisRangeSliderX(0),
@ -36,7 +37,7 @@ GraphModifier::GraphModifier(Q3DSurfaceWidgetItem *graph)
m_activeSample(0),
m_fontSize(40),
m_rangeX(34.0),
m_rangeY(16.0),
m_rangeY(20.0),
m_rangeZ(34.0),
m_minX(-17.0),
m_minY(-8.0),
@ -50,6 +51,7 @@ GraphModifier::GraphModifier(Q3DSurfaceWidgetItem *graph)
m_drawMode2(QSurface3DSeries::DrawSurfaceAndWireframe),
m_drawMode3(QSurface3DSeries::DrawSurfaceAndWireframe),
m_drawMode4(QSurface3DSeries::DrawSurfaceAndWireframe),
m_drawMode5(QSurface3DSeries::DrawSurface),
m_offset(4.0f),
m_ascendingX(true),
m_ascendingZ(true)
@ -97,6 +99,8 @@ GraphModifier::GraphModifier(Q3DSurfaceWidgetItem *graph)
fillSeries();
changeStyle();
m_lineSeries->setDrawMode(m_drawMode5);
m_theSeries->setItemLabelFormat(QStringLiteral("@seriesName: (@xLabel, @zLabel): @yLabel"));
connect(&m_timer, &QTimer::timeout, this, &GraphModifier::timeout);
@ -163,6 +167,27 @@ void GraphModifier::fillSeries()
m_multiseries[1]->dataProxy()->resetArray(dataArray2);
m_multiseries[2]->dataProxy()->resetArray(dataArray3);
m_multiseries[3]->dataProxy()->resetArray(dataArray4);
QSurfaceDataArray lineDataArray;
lineDataArray.reserve(m_zCount);
for (int i = 0; i < m_zCount; i++) {
QSurfaceDataRow row;
float zAdjust = 0.0f;
float z = float(i) - m_limitZ + 0.5f + m_multiSampleOffsetZ[3] + zAdjust;
int j = m_xCount / 2;
float xAdjust = 0.0f;
if (j == 4)
xAdjust = 0.7f;
float x = float(j) - m_limitX + 0.5f + m_multiSampleOffsetX[3] + xAdjust;
float angle = (z * x) / full * 1.57f;
float y = (qSin(angle * float(qPow(1.3f, 4))) + 1.1f * 4) * 3.0f - 5.0f + xAdjust + zAdjust;
row.append(QSurfaceDataItem(x,y,z));
lineDataArray << row;
}
m_lineSeries->dataProxy()->resetArray(lineDataArray);
}
void GraphModifier::toggleSeries1(int enabled)
@ -209,6 +234,15 @@ void GraphModifier::toggleSeries4(int enabled)
}
}
void GraphModifier::toggleLineSeries(int enabled)
{
qDebug() << __FUNCTION__ << " enabled = " << enabled;
if (enabled)
m_graph->addSeries(m_lineSeries);
else
m_graph->removeSeries(m_lineSeries);
}
void GraphModifier::toggleSmooth(int visible)
{
qDebug() << "GraphModifier::toggleSmooth " << visible;
@ -412,6 +446,18 @@ void GraphModifier::toggleSurfaceS4(int enable)
m_multiseries[3]->setDrawMode(m_drawMode4);
}
void GraphModifier::toggleLineSurfaceGrid(int enable)
{
qDebug() << __FUNCTION__ << enable;
if (enable)
m_drawMode5 |= QSurface3DSeries::DrawWireframe;
else
m_drawMode5 &= ~QSurface3DSeries::DrawWireframe;
m_lineSeries->setDrawMode(m_drawMode5);
}
void GraphModifier::toggleSeries4Visible(int enable)
{
qDebug() << __FUNCTION__ << enable;
@ -432,6 +478,17 @@ void GraphModifier::toggleFillS4(int enable)
#endif
}
void GraphModifier::toggleFillLine(int enable)
{
qDebug() << "GraphModifier::toggleFill" << enable;
if (enable)
m_drawMode5 |= QSurface3DSeries::DrawFilledSurface;
else
m_drawMode5 &= ~QSurface3DSeries::DrawFilledSurface;
m_lineSeries->setDrawMode(m_drawMode5);
}
void GraphModifier::toggleSqrtSin(int enable)
{
if (enable) {

View File

@ -31,6 +31,7 @@ public:
void toggleSeries2(int enabled);
void toggleSeries3(int enabled);
void toggleSeries4(int enabled);
void toggleLineSeries(int enabled);
void toggleSmooth(int enabled);
void toggleSurfaceGrid(int enable);
void toggleSurface(int enable);
@ -51,6 +52,9 @@ public:
void toggleSurfaceS4(int enable);
void toggleSeries4Visible(int enable);
void toggleFillS4(int enable);
void toggleLineSurfaceGrid(int enable);
void toggleLineSurface(int enable);
void toggleFillLine(int enable);
void toggleSqrtSin(int enable);
void togglePlane(int enable);
@ -154,6 +158,7 @@ private:
QSurface3DSeries *m_series2;
QSurface3DSeries *m_series3;
QSurface3DSeries *m_series4;
QSurface3DSeries *m_lineSeries;
QSlider *m_gridSliderX;
QSlider *m_gridSliderZ;
QSlider *m_axisRangeSliderX;
@ -164,6 +169,7 @@ private:
QCheckBox *m_series2CB;
QCheckBox *m_series3CB;
QCheckBox *m_series4CB;
QCheckBox *m_lineSeriesCB;
bool m_gridSlidersLocked;
int m_xCount;
int m_zCount;
@ -186,6 +192,7 @@ private:
QSurface3DSeries::DrawFlags m_drawMode2;
QSurface3DSeries::DrawFlags m_drawMode3;
QSurface3DSeries::DrawFlags m_drawMode4;
QSurface3DSeries::DrawFlags m_drawMode5;
float m_limitX;
float m_limitZ;
float m_offset;

View File

@ -157,6 +157,22 @@ int main(int argc, char *argv[])
QCheckBox *series4CB = new QCheckBox(widget);
series4CB->setText(QStringLiteral("Series 4"));
QCheckBox *lineSeriesCB = new QCheckBox(widget);
lineSeriesCB->setText(QStringLiteral("Line Series"));
QCheckBox *surfaceGridLineCB = new QCheckBox(widget);
surfaceGridLineCB->setText(QStringLiteral("Line Surface Grid"));
surfaceGridLineCB->setChecked(false);
QCheckBox *lineSeriesVisibleCB = new QCheckBox(widget);
lineSeriesVisibleCB->setText(QStringLiteral("Line Series Visible"));
lineSeriesVisibleCB->setChecked(true);
QCheckBox *fillLineCB = new QCheckBox(widget);
fillLineCB->setText(QStringLiteral("Line Series Fill"));
fillLineCB->setChecked(false);
#else
//QCheckBox *sqrtSinCB = new QCheckBox(widget);
QRadioButton *sqrtSinCB = new QRadioButton(widget);
@ -198,7 +214,7 @@ int main(int argc, char *argv[])
QSlider *axisRangeSliderY = new QSlider(Qt::Horizontal, widget);
axisRangeSliderY->setTickInterval(1);
axisRangeSliderY->setMinimum(1);
axisRangeSliderY->setValue(16);
axisRangeSliderY->setValue(20);
axisRangeSliderY->setMaximum(100);
axisRangeSliderY->setEnabled(true);
QSlider *axisRangeSliderZ = new QSlider(Qt::Horizontal, widget);
@ -400,6 +416,10 @@ int main(int argc, char *argv[])
line3->setFrameShape(QFrame::HLine);
line3->setFrameShadow(QFrame::Sunken);
QFrame* line4 = new QFrame();
line4->setFrameShape(QFrame::HLine);
line4->setFrameShadow(QFrame::Sunken);
QCheckBox *axisTitlesVisibleCB = new QCheckBox(widget);
axisTitlesVisibleCB->setText(QStringLiteral("Axis titles visible"));
axisTitlesVisibleCB->setChecked(false);
@ -526,7 +546,12 @@ int main(int argc, char *argv[])
vLayout->addWidget(surfaceS4CB);
vLayout->addWidget(series4VisibleCB);
vLayout->addWidget(fillS4CB);
vLayout->addWidget(surfaceTextureCB, 1, Qt::AlignTop);
vLayout->addWidget(surfaceTextureCB);
vLayout->addWidget(line4);
vLayout->addWidget(lineSeriesCB);
vLayout->addWidget(lineSeriesVisibleCB);
vLayout->addWidget(surfaceGridLineCB);
vLayout->addWidget(fillLineCB, 1, Qt::AlignTop);
#endif
#ifndef MULTI_SERIES
vLayout->addWidget(new QLabel(QStringLiteral("Select surface sample")));
@ -666,6 +691,14 @@ int main(int argc, char *argv[])
QObject::connect(fillS4CB, &QCheckBox::checkStateChanged,
modifier, &GraphModifier::toggleFillS4);
QObject::connect(lineSeriesVisibleCB, &QCheckBox::checkStateChanged,
modifier, &GraphModifier::toggleLineSeries);
QObject::connect(surfaceGridLineCB, &QCheckBox::checkStateChanged,
modifier, &GraphModifier::toggleLineSurfaceGrid);
QObject::connect(fillLineCB, &QCheckBox::checkStateChanged,
modifier, &GraphModifier::toggleFillLine);
CheckBoxWrapper *series1SmoothCBWrapper = new CheckBoxWrapper(smoothCB);
CheckBoxWrapper *series1SurfaceGridCBWrapper = new CheckBoxWrapper(surfaceGridCB);
CheckBoxWrapper *series1surfaceCBWrapper = new CheckBoxWrapper(surfaceCB);
@ -726,6 +759,19 @@ int main(int argc, char *argv[])
series4surfaceCBWrapper, &CheckBoxWrapper::setEnabled);
QObject::connect(series4CB, &QCheckBox::checkStateChanged,
series4VisibleCBWrapper, &CheckBoxWrapper::setEnabled);
CheckBoxWrapper *lineSeriesSurfaceGridCBWrapper = new CheckBoxWrapper(surfaceGridLineCB);
CheckBoxWrapper *lineSeriessurfaceCBWrapper = new CheckBoxWrapper(lineSeriesCB);
CheckBoxWrapper *lineSeriesVisibleCBWrapper = new CheckBoxWrapper(lineSeriesVisibleCB);
CheckBoxWrapper *lineSeriesFillCBWrapper = new CheckBoxWrapper(fillLineCB);
QObject::connect(lineSeriesCB, &QCheckBox::checkStateChanged,
modifier, &GraphModifier::toggleLineSeries);
QObject::connect(lineSeriesCB, &QCheckBox::checkStateChanged,
lineSeriesSurfaceGridCBWrapper, &CheckBoxWrapper::setEnabled);
QObject::connect(lineSeriesCB, &QCheckBox::checkStateChanged,
lineSeriesVisibleCBWrapper, &CheckBoxWrapper::setEnabled);
QObject::connect(lineSeriesCB, &QCheckBox::checkStateChanged,
lineSeriesFillCBWrapper, &CheckBoxWrapper::setEnabled);
#else
QObject::connect(sqrtSinCB, &QRadioButton::toggled,
modifier, &GraphModifier::toggleSqrtSin);
@ -890,6 +936,7 @@ int main(int argc, char *argv[])
series2CB->setChecked(true);
series3CB->setChecked(true);
series4CB->setChecked(true);
lineSeriesCB->setChecked(true);
#endif
modifier->setAxisRangeSliderX(axisRangeSliderX);
modifier->setAxisRangeSliderZ(axisRangeSliderZ);