summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2014-09-09 11:30:15 +0300
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2014-09-10 12:30:54 +0300
commitddb9be979d93b7e17f1067dc6056de54d9828b29 (patch)
treedf612c56e4a804481297ae55b29f0ee379c5f8ab
parentbb30ea555c71604de9a2bc5096fa35c9532b26bd (diff)
Limit volume to axis ranges
The volume object that would go partially outside axis ranges is scale and repositioned so that it only renders the portion that is inside the axis ranges. Change-Id: I792494e437998ba6276f58fab645767276c1476d Reviewed-by: Mika Salmela <mika.salmela@digia.com>
-rw-r--r--examples/datavisualization/volumetric/main.cpp35
-rw-r--r--examples/datavisualization/volumetric/volumetric.cpp53
-rw-r--r--examples/datavisualization/volumetric/volumetric.h3
-rw-r--r--src/datavisualization/data/customrenderitem_p.h26
-rw-r--r--src/datavisualization/data/qcustom3ditem.cpp10
-rw-r--r--src/datavisualization/data/qcustom3dvolume.cpp26
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization.qdoc1
-rw-r--r--src/datavisualization/engine/abstract3drenderer.cpp94
-rw-r--r--src/datavisualization/engine/abstract3drenderer_p.h3
-rw-r--r--src/datavisualization/engine/bars3drenderer.cpp52
-rw-r--r--src/datavisualization/engine/bars3drenderer_p.h1
-rw-r--r--src/datavisualization/engine/scatter3drenderer.cpp40
-rw-r--r--src/datavisualization/engine/scatter3drenderer_p.h1
-rw-r--r--src/datavisualization/engine/shaders/texture3d.frag64
-rw-r--r--src/datavisualization/engine/shaders/texture3d.vert26
-rw-r--r--src/datavisualization/engine/shaders/texture3dlowdef.frag64
-rw-r--r--src/datavisualization/engine/shaders/texture3dslice.frag97
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp40
-rw-r--r--src/datavisualization/engine/surface3drenderer_p.h1
-rw-r--r--src/datavisualization/global/datavisualizationglobal_p.h1
-rw-r--r--src/datavisualization/utils/shaderhelper.cpp16
-rw-r--r--src/datavisualization/utils/shaderhelper_p.h4
-rw-r--r--tests/volumetrictest/main.cpp5
-rw-r--r--tests/volumetrictest/volumetrictest.cpp90
-rw-r--r--tests/volumetrictest/volumetrictest.h11
25 files changed, 584 insertions, 180 deletions
diff --git a/examples/datavisualization/volumetric/main.cpp b/examples/datavisualization/volumetric/main.cpp
index 0acffe10..98330396 100644
--- a/examples/datavisualization/volumetric/main.cpp
+++ b/examples/datavisualization/volumetric/main.cpp
@@ -104,6 +104,26 @@ int main(int argc, char **argv)
textureDetailVBox->addWidget(highDetailRB);
textureDetailGroupBox->setLayout(textureDetailVBox);
+ QGroupBox *areaGroupBox = new QGroupBox(QStringLiteral("Show area"));
+
+ QRadioButton *areaAllRB = new QRadioButton(widget);
+ areaAllRB->setText(QStringLiteral("Whole region"));
+ areaAllRB->setChecked(true);
+
+ QRadioButton *areaMineRB = new QRadioButton(widget);
+ areaMineRB->setText(QStringLiteral("The mine"));
+ areaMineRB->setChecked(false);
+
+ QRadioButton *areaMountainRB = new QRadioButton(widget);
+ areaMountainRB->setText(QStringLiteral("The mountain"));
+ areaMountainRB->setChecked(false);
+
+ QVBoxLayout *areaVBox = new QVBoxLayout;
+ areaVBox->addWidget(areaAllRB);
+ areaVBox->addWidget(areaMineRB);
+ areaVBox->addWidget(areaMountainRB);
+ areaGroupBox->setLayout(areaVBox);
+
QCheckBox *colorTableCheckBox = new QCheckBox(widget);
colorTableCheckBox->setText(QStringLiteral("Alternate color table"));
colorTableCheckBox->setChecked(false);
@@ -143,6 +163,11 @@ int main(int argc, char **argv)
useHighDefShaderCheckBox->setText(QStringLiteral("Use HD shader"));
useHighDefShaderCheckBox->setChecked(true);
+ QLabel *performanceNoteLabel =
+ new QLabel(QStringLiteral(
+ "Note: A high end graphics card is\nrecommended with the HD shader\nwhen the volume contains a lot of\ntransparent areas."));
+ performanceNoteLabel->setFrameShape(QFrame::Box);
+
vLayout->addWidget(sliceXCheckBox);
vLayout->addWidget(sliceXSlider);
vLayout->addWidget(sliceImageXLabel);
@@ -155,12 +180,14 @@ int main(int argc, char **argv)
vLayout2->addWidget(fpsCheckBox);
vLayout2->addWidget(fpsLabel);
vLayout2->addWidget(textureDetailGroupBox);
+ vLayout2->addWidget(areaGroupBox);
vLayout2->addWidget(colorTableCheckBox);
vLayout2->addWidget(alphaMultiplierLabel);
vLayout2->addWidget(alphaMultiplierSlider);
vLayout2->addWidget(preserveOpacityCheckBox);
vLayout2->addWidget(transparentGroundCheckBox);
- vLayout2->addWidget(useHighDefShaderCheckBox, 1, Qt::AlignTop);
+ vLayout2->addWidget(useHighDefShaderCheckBox);
+ vLayout2->addWidget(performanceNoteLabel, 1, Qt::AlignTop);
VolumetricModifier *modifier = new VolumetricModifier(graph);
modifier->setFpsLabel(fpsLabel);
@@ -201,6 +228,12 @@ int main(int argc, char **argv)
&VolumetricModifier::setUseHighDefShader);
QObject::connect(alphaMultiplierSlider, &QSlider::valueChanged, modifier,
&VolumetricModifier::adjustAlphaMultiplier);
+ QObject::connect(areaAllRB, &QRadioButton::toggled, modifier,
+ &VolumetricModifier::toggleAreaAll);
+ QObject::connect(areaMineRB, &QRadioButton::toggled, modifier,
+ &VolumetricModifier::toggleAreaMine);
+ QObject::connect(areaMountainRB, &QRadioButton::toggled, modifier,
+ &VolumetricModifier::toggleAreaMountain);
widget->show();
return app.exec();
diff --git a/examples/datavisualization/volumetric/volumetric.cpp b/examples/datavisualization/volumetric/volumetric.cpp
index eb8f2188..54e930d2 100644
--- a/examples/datavisualization/volumetric/volumetric.cpp
+++ b/examples/datavisualization/volumetric/volumetric.cpp
@@ -80,6 +80,8 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
m_graph->setOrthoProjection(true);
+ toggleAreaAll(true);
+
#if !defined(QT_OPENGL_ES_2)
m_lowDetailData = new QVector<uchar>(lowDetailSize * lowDetailSize * lowDetailSize / 2);
m_mediumDetailData = new QVector<uchar>(mediumDetailSize * mediumDetailSize * mediumDetailSize / 2);
@@ -95,9 +97,16 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
excavateMineShaft(lowDetailSize, 0, m_mineShaftArray.size(), m_lowDetailData);
m_volumeItem = new QCustom3DVolume;
- m_volumeItem->setScaling(QVector3D(m_graph->axisX()->max() - m_graph->axisX()->min(),
- m_graph->axisY()->max() - m_graph->axisY()->min(),
- m_graph->axisZ()->max() - m_graph->axisZ()->min()));
+ // Adjust water level to zero with a minor tweak to y-coordinate position and scaling
+ m_volumeItem->setScaling(
+ QVector3D(m_graph->axisX()->max() - m_graph->axisX()->min(),
+ (m_graph->axisY()->max() - m_graph->axisY()->min()) * 0.91f,
+ m_graph->axisZ()->max() - m_graph->axisZ()->min()));
+ m_volumeItem->setPosition(
+ QVector3D((m_graph->axisX()->max() + m_graph->axisX()->min()) / 2.0f,
+ -0.045f * (m_graph->axisY()->max() - m_graph->axisY()->min()) +
+ (m_graph->axisY()->max() + m_graph->axisY()->min()) / 2.0f,
+ (m_graph->axisZ()->max() + m_graph->axisZ()->min()) / 2.0f));
m_volumeItem->setScalingAbsolute(false);
m_volumeItem->setTextureWidth(lowDetailSize);
m_volumeItem->setTextureHeight(lowDetailSize / 2);
@@ -437,6 +446,42 @@ void VolumetricModifier::adjustAlphaMultiplier(int value)
adjustSliceZ(m_sliceSliderZ->value());
}
+void VolumetricModifier::toggleAreaAll(bool enabled)
+{
+ if (enabled) {
+ m_graph->axisX()->setRange(0.0f, 1000.0f);
+ m_graph->axisY()->setRange(-600.0f, 600.0f);
+ m_graph->axisZ()->setRange(0.0f, 1000.0f);
+ m_graph->axisX()->setSegmentCount(5);
+ m_graph->axisY()->setSegmentCount(6);
+ m_graph->axisZ()->setSegmentCount(5);
+ }
+}
+
+void VolumetricModifier::toggleAreaMine(bool enabled)
+{
+ if (enabled) {
+ m_graph->axisX()->setRange(350.0f, 850.0f);
+ m_graph->axisY()->setRange(-500.0f, 100.0f);
+ m_graph->axisZ()->setRange(350.0f, 900.0f);
+ m_graph->axisX()->setSegmentCount(10);
+ m_graph->axisY()->setSegmentCount(6);
+ m_graph->axisZ()->setSegmentCount(11);
+ }
+}
+
+void VolumetricModifier::toggleAreaMountain(bool enabled)
+{
+ if (enabled) {
+ m_graph->axisX()->setRange(300.0f, 600.0f);
+ m_graph->axisY()->setRange(-100.0f, 400.0f);
+ m_graph->axisZ()->setRange(300.0f, 600.0f);
+ m_graph->axisX()->setSegmentCount(9);
+ m_graph->axisY()->setSegmentCount(5);
+ m_graph->axisZ()->setSegmentCount(9);
+ }
+}
+
void VolumetricModifier::initHeightMap(QString fileName, QVector<uchar> &layerData)
{
QImage heightImage(fileName);
@@ -485,7 +530,7 @@ int VolumetricModifier::createVolume(int textureSize, int startIndex, int count,
// Ground layer below water
colorIndex = int((float(waterHeights.at(k) - height) / heightToColorDiv)
* float(layerColorThickness)) + underWaterGroundColorsMin;
- } else if (height <= waterHeights.at(k)) {
+ } else if (height < waterHeights.at(k)) {
// Water layer where water goes over ground
colorIndex = int((float(height - magmaHeights.at(k)) / heightToColorDiv)
* float(layerColorThickness)) + waterColorsMin;
diff --git a/examples/datavisualization/volumetric/volumetric.h b/examples/datavisualization/volumetric/volumetric.h
index 27b053e2..180686fb 100644
--- a/examples/datavisualization/volumetric/volumetric.h
+++ b/examples/datavisualization/volumetric/volumetric.h
@@ -63,6 +63,9 @@ public slots:
void setTransparentGround(bool enabled);
void setUseHighDefShader(bool enabled);
void adjustAlphaMultiplier(int value);
+ void toggleAreaAll(bool enabled);
+ void toggleAreaMine(bool enabled);
+ void toggleAreaMountain(bool enabled);
private:
diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h
index 8ea8e894..84fc898a 100644
--- a/src/datavisualization/data/customrenderitem_p.h
+++ b/src/datavisualization/data/customrenderitem_p.h
@@ -55,6 +55,8 @@ public:
inline QVector3D origScaling() const { return m_origScaling; }
inline void setPosition(const QVector3D &position) { m_position = position; }
inline QVector3D position() const { return m_position; }
+ inline void setOrigPosition(const QVector3D &position) { m_origPosition = position; }
+ inline QVector3D origPosition() const { return m_origPosition; }
inline void setPositionAbsolute(bool absolute) { m_positionAbsolute = absolute; }
inline bool isPositionAbsolute() const { return m_positionAbsolute; }
inline void setScalingAbsolute(bool absolute) { m_scalingAbsolute = absolute; }
@@ -104,6 +106,25 @@ public:
inline bool preserveOpacity() const { return m_preserveOpacity; }
inline void setUseHighDefShader(bool enable) { m_useHighDefShader = enable; }
inline bool useHighDefShader() const {return m_useHighDefShader; }
+ inline void setMinBounds(const QVector3D &bounds) {
+ m_minBounds = bounds;
+ m_minBoundsNormal = m_minBounds;
+ m_minBoundsNormal.setY(-m_minBoundsNormal.y());
+ m_minBoundsNormal.setZ(-m_minBoundsNormal.z());
+ m_minBoundsNormal = 0.5f * (m_minBoundsNormal + oneVector);
+
+ }
+ inline QVector3D minBounds() const { return m_minBounds; }
+ inline void setMaxBounds(const QVector3D &bounds) {
+ m_maxBounds = bounds;
+ m_maxBoundsNormal = m_maxBounds;
+ m_maxBoundsNormal.setY(-m_maxBoundsNormal.y());
+ m_maxBoundsNormal.setZ(-m_maxBoundsNormal.z());
+ m_maxBoundsNormal = 0.5f * (m_maxBoundsNormal + oneVector);
+ }
+ inline QVector3D maxBounds() const { return m_maxBounds; }
+ inline QVector3D minBoundsNormal() const { return m_minBoundsNormal; }
+ inline QVector3D maxBoundsNormal() const { return m_maxBoundsNormal; }
private:
Q_DISABLE_COPY(CustomRenderItem)
@@ -112,6 +133,7 @@ private:
QVector3D m_scaling;
QVector3D m_origScaling;
QVector3D m_position;
+ QVector3D m_origPosition;
bool m_positionAbsolute;
bool m_scalingAbsolute;
ObjectHelper *m_object; // shared reference
@@ -138,6 +160,10 @@ private:
float m_alphaMultiplier;
bool m_preserveOpacity;
bool m_useHighDefShader;
+ QVector3D m_minBounds;
+ QVector3D m_maxBounds;
+ QVector3D m_minBoundsNormal;
+ QVector3D m_maxBoundsNormal;
};
typedef QHash<QCustom3DItem *, CustomRenderItem *> CustomRenderItemArray;
diff --git a/src/datavisualization/data/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp
index 64cb4531..4e82d47a 100644
--- a/src/datavisualization/data/qcustom3ditem.cpp
+++ b/src/datavisualization/data/qcustom3ditem.cpp
@@ -67,10 +67,10 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* within axis ranges.
*
* \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false},
- * unless the item is a Custom3DVolume that would be partially visible. In that case, the visible
- * portion of the volume will be rendered.
+ * unless the item is a Custom3DVolume that would be partially visible and scalingAbsolute is also
+ * \c{false}. In that case, the visible portion of the volume will be rendered.
*
- * \sa positionAbsolute
+ * \sa positionAbsolute, scalingAbsolute
*/
/*! \qmlproperty bool Custom3DItem::positionAbsolute
@@ -206,8 +206,8 @@ QString QCustom3DItem::meshFile() const
* within axis ranges.
*
* \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false},
- * unless the item is a QCustom3DVolume that would be partially visible. In that case, the visible
- * portion of the volume will be rendered.
+ * unless the item is a QCustom3DVolume that would be partially visible and scalingAbsolute is also
+ * \c{false}. In that case, the visible portion of the volume will be rendered.
*
* \sa positionAbsolute
*/
diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp
index d0e0c139..78c91802 100644
--- a/src/datavisualization/data/qcustom3dvolume.cpp
+++ b/src/datavisualization/data/qcustom3dvolume.cpp
@@ -31,9 +31,19 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* object is a box with a 3D texture. Three slice planes are supported for the volume, one along
* each main axis of the volume.
*
+ * Rendering volume objects is very performance intensive, especially when the volume is largely
+ * transparent, as the contents of the volume are ray-traced. The performance scales nearly linearly
+ * with the amount of pixels that the volume occupies on the screen, so showing the volume in a
+ * smaller view or limiting the zoom level of the graph are easy ways to improve performance.
+ * Similarly, the volume texture dimensions have a large impact on performance.
+ * If the frame rate is more important than pixel-perfect rendering of the volume contents, consider
+ * turning the high definition shader off by setting useHighDefShader property to \c{false}.
+ *
* \note Volumetric objects are only supported with orthographic projection.
*
- * \sa QAbstract3DGraph::addCustomItem(), QAbstract3DGraph::orthoProjection
+ * \note Volumetric objects utilize 3D textures, which are not supported in OpenGL ES2 environments.
+ *
+ * \sa QAbstract3DGraph::addCustomItem(), QAbstract3DGraph::orthoProjection, useHighDefShader
*/
/*!
@@ -48,13 +58,23 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* object is a box with a 3D texture. Three slice planes are supported for the volume, one along
* each main axis of the volume.
*
+ * Rendering volume objects is very performance intensive, especially when the volume is largely
+ * transparent, as the contents of the volume are ray-traced. The performance scales nearly linearly
+ * with the amount of pixels that the volume occupies on the screen, so showing the volume in a
+ * smaller view or limiting the zoom level of the graph are easy ways to improve performance.
+ * Similarly, the volume texture dimensions have a large impact on performance.
+ * If the frame rate is more important than pixel-perfect rendering of the volume contents, consider
+ * turning the high definition shader off by setting useHighDefShader property to \c{false}.
+ *
* \note: Filling in the volume data would not typically be efficient or practical from pure QML,
* so properties directly related to that are not fully supported from QML.
- * Make a hybrid QML/C++ application if you want to use volume objects with QML ui.
+ * Make a hybrid QML/C++ application if you want to use volume objects with a QML UI.
*
* \note Volumetric objects are only supported with orthographic projection.
*
- * \sa AbstractGraph3D::orthoProjection
+ * \note Volumetric objects utilize 3D textures, which are not supported in OpenGL ES2 environments.
+ *
+ * \sa AbstractGraph3D::orthoProjection, useHighDefShader
*/
/*! \qmlproperty int Custom3DVolume::textureWidth
diff --git a/src/datavisualization/doc/src/qtdatavisualization.qdoc b/src/datavisualization/doc/src/qtdatavisualization.qdoc
index a4718887..d3fb4856 100644
--- a/src/datavisualization/doc/src/qtdatavisualization.qdoc
+++ b/src/datavisualization/doc/src/qtdatavisualization.qdoc
@@ -327,6 +327,7 @@
so only the Qt Quick 2 graphs are available in practice for those platforms.
\li Shadows are not supported with OpenGL ES2 (including Angle builds in Windows).
\li Anti-aliasing doesn't work with OpenGL ES2 (including Angle builds in Windows).
+ \li QCustom3DVolume items are not supported with OpenGL ES2 (including Angle builds in Windows).
\li Surfaces with non-straight rows and columns do not always render properly.
\li Q3DLight class (and Light3D QML item) are currently not usable for anything.
\li Changing any of Q3DScene properties affecting subviewports currently has no effect.
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp
index 18384872..305d3df0 100644
--- a/src/datavisualization/engine/abstract3drenderer.cpp
+++ b/src/datavisualization/engine/abstract3drenderer.cpp
@@ -960,7 +960,7 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
newItem->setRenderer(this);
newItem->setItemPointer(item); // Store pointer for render item updates
newItem->setMesh(item->meshFile());
- newItem->setPosition(item->position());
+ newItem->setOrigPosition(item->position());
newItem->setOrigScaling(item->scaling());
newItem->setScalingAbsolute(item->isScalingAbsolute());
newItem->setPositionAbsolute(item->isPositionAbsolute());
@@ -1013,7 +1013,7 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
newItem->setUseHighDefShader(volumeItem->useHighDefShader());
#endif
}
- recalculateCustomItemScaling(newItem);
+ recalculateCustomItemScalingAndPos(newItem);
newItem->setRotation(item->rotation());
#if !defined(QT_OPENGL_ES_2)
// In OpenGL ES we simply draw volumes as regular custom item placeholders.
@@ -1025,9 +1025,6 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
}
newItem->setTexture(texture);
item->d_ptr->clearTextureImage();
- QVector3D translation = convertPositionToTranslation(newItem->position(),
- newItem->isPositionAbsolute());
- newItem->setTranslation(translation);
newItem->setVisible(item->isVisible());
newItem->setShadowCasting(item->isShadowCasting());
newItem->setFacingCamera(facingCamera);
@@ -1035,25 +1032,71 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
return newItem;
}
-void Abstract3DRenderer::recalculateCustomItemScaling(CustomRenderItem *item)
+void Abstract3DRenderer::recalculateCustomItemScalingAndPos(CustomRenderItem *item)
{
if (!m_polarGraph && !item->isLabel() && !item->isScalingAbsolute()
&& !item->isPositionAbsolute()) {
QVector3D scale = item->origScaling() / 2.0f;
- QVector3D pos = item->position();
+ QVector3D pos = item->origPosition();
QVector3D minBounds(pos.x() - scale.x(),
pos.y() - scale.y(),
- pos.z() - scale.z());
+ pos.z() + scale.z());
QVector3D maxBounds(pos.x() + scale.x(),
pos.y() + scale.y(),
- pos.z() + scale.z());
- QVector3D min = convertPositionToTranslation(minBounds, false);
- QVector3D max = convertPositionToTranslation(maxBounds, false);
- item->setScaling(QVector3D(qAbs(max.x() - min.x()), qAbs(max.y() - min.y()),
- qAbs(max.z() - min.z())) / 2.0f);
+ pos.z() - scale.z());
+ QVector3D minCorner = convertPositionToTranslation(minBounds, false);
+ QVector3D maxCorner = convertPositionToTranslation(maxBounds, false);
+ scale = QVector3D(qAbs(maxCorner.x() - minCorner.x()),
+ qAbs(maxCorner.y() - minCorner.y()),
+ qAbs(maxCorner.z() - minCorner.z())) / 2.0f;
+ if (item->isVolume()) {
+ // Only volume items need to scale and reposition according to bounds
+ QVector3D minBoundsNormal = minCorner;
+ QVector3D maxBoundsNormal = maxCorner;
+ // getVisibleItemBounds returns bounds normalized for fragment shader [-1,1]
+ // Y and Z are also flipped.
+ getVisibleItemBounds(minBoundsNormal, maxBoundsNormal);
+ item->setMinBounds(minBoundsNormal);
+ item->setMaxBounds(maxBoundsNormal);
+ // For scaling calculations, we want [0,1] normalized values
+ minBoundsNormal = item->minBoundsNormal();
+ maxBoundsNormal = item->maxBoundsNormal();
+
+ // Rescale and reposition the item so that it doesn't go over the edges
+ QVector3D adjScaling =
+ QVector3D(scale.x() * (maxBoundsNormal.x() - minBoundsNormal.x()),
+ scale.y() * (maxBoundsNormal.y() - minBoundsNormal.y()),
+ scale.z() * (maxBoundsNormal.z() - minBoundsNormal.z()));
+
+ item->setScaling(adjScaling);
+
+ QVector3D adjPos = item->origPosition();
+ QVector3D dataExtents = QVector3D(maxBounds.x() - minBounds.x(),
+ maxBounds.y() - minBounds.y(),
+ maxBounds.z() - minBounds.z()) / 2.0f;
+ adjPos.setX(adjPos.x() + (dataExtents.x() * minBoundsNormal.x())
+ - (dataExtents.x() * (1.0f - maxBoundsNormal.x())));
+ adjPos.setY(adjPos.y() + (dataExtents.y() * minBoundsNormal.y())
+ - (dataExtents.y() * (1.0f - maxBoundsNormal.y())));
+ adjPos.setZ(adjPos.z() + (dataExtents.z() * minBoundsNormal.z())
+ - (dataExtents.z() * (1.0f - maxBoundsNormal.z())));
+ item->setPosition(adjPos);
+ } else {
+ // Only scale for non-volume items, and do not readjust position
+ item->setScaling(scale);
+ item->setPosition(item->origPosition());
+ }
} else {
item->setScaling(item->origScaling());
+ item->setPosition(item->origPosition());
+ if (item->isVolume()) {
+ item->setMinBounds(-1.0f * zeroVector);
+ item->setMaxBounds(oneVector);
+ }
}
+ QVector3D translation = convertPositionToTranslation(item->position(),
+ item->isPositionAbsolute());
+ item->setTranslation(translation);
}
void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
@@ -1064,11 +1107,10 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
item->d_ptr->m_dirtyBits.meshDirty = false;
}
if (item->d_ptr->m_dirtyBits.positionDirty) {
- renderItem->setPosition(item->position());
+ renderItem->setOrigPosition(item->position());
renderItem->setPositionAbsolute(item->isPositionAbsolute());
- QVector3D translation = convertPositionToTranslation(renderItem->position(),
- renderItem->isPositionAbsolute());
- renderItem->setTranslation(translation);
+ if (!item->d_ptr->m_dirtyBits.scalingDirty)
+ recalculateCustomItemScalingAndPos(renderItem);
item->d_ptr->m_dirtyBits.positionDirty = false;
}
if (item->d_ptr->m_dirtyBits.scalingDirty) {
@@ -1099,7 +1141,7 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
item->d_ptr->clearTextureImage();
renderItem->setOrigScaling(scaling);
}
- recalculateCustomItemScaling(renderItem);
+ recalculateCustomItemScalingAndPos(renderItem);
item->d_ptr->m_dirtyBits.scalingDirty = false;
}
if (item->d_ptr->m_dirtyBits.rotationDirty) {
@@ -1195,10 +1237,7 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
void Abstract3DRenderer::updateCustomItemPositions()
{
foreach (CustomRenderItem *renderItem, m_customRenderCache) {
- recalculateCustomItemScaling(renderItem);
- QVector3D translation = convertPositionToTranslation(renderItem->position(),
- renderItem->isPositionAbsolute());
- renderItem->setTranslation(translation);
+ recalculateCustomItemScalingAndPos(renderItem);
}
}
@@ -1243,7 +1282,7 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
continue;
}
- // Check if the render item is in data coordinates and not within axis ranges, and skip drawing if it is
+ // If the render item is in data coordinates and not within axis ranges, skip it
if (!item->isPositionAbsolute()
&& (item->position().x() < m_axisCacheX.min()
|| item->position().x() > m_axisCacheX.max()
@@ -1353,9 +1392,12 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
// Set shadowless shader bindings
#if !defined(QT_OPENGL_ES_2)
if (item->isVolume()) {
- // Volume shaders repurpose light position for camera position relative to item
QVector3D cameraPos = m_cachedScene->activeCamera()->position();
cameraPos = MVPMatrix.inverted().map(cameraPos);
+ // Adjust camera position according to min/max bounds
+ cameraPos = cameraPos
+ + ((oneVector - cameraPos) * item->minBoundsNormal())
+ - ((oneVector + cameraPos) * (oneVector - item->maxBoundsNormal()));
shader->setUniformValue(shader->cameraPositionRelativeToModel(), -cameraPos);
GLint color8Bit = (item->textureFormat() == QImage::Format_Indexed8) ? 1 : 0;
if (color8Bit) {
@@ -1366,6 +1408,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
shader->setUniformValue(shader->alphaMultiplier(), item->alphaMultiplier());
shader->setUniformValue(shader->preserveOpacity(),
item->preserveOpacity() ? 1 : 0);
+
+ shader->setUniformValue(shader->minBounds(), item->minBounds());
+ shader->setUniformValue(shader->maxBounds(), item->maxBounds());
+
if (shader == m_volumeTextureSliceShader) {
QVector3D slices((float(item->sliceIndexX()) + 0.5f)
/ float(item->textureWidth()) * 2.0 - 1.0,
diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h
index 8152e0c9..c8bfa7af 100644
--- a/src/datavisualization/engine/abstract3drenderer_p.h
+++ b/src/datavisualization/engine/abstract3drenderer_p.h
@@ -205,7 +205,8 @@ protected:
virtual void fixCameraTarget(QVector3D &target) = 0;
void updateCameraViewport();
- void recalculateCustomItemScaling(CustomRenderItem *item);
+ void recalculateCustomItemScalingAndPos(CustomRenderItem *item);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds) = 0;
bool m_hasNegativeValues;
Q3DTheme *m_cachedTheme;
diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp
index 1614b563..3e83a830 100644
--- a/src/datavisualization/engine/bars3drenderer.cpp
+++ b/src/datavisualization/engine/bars3drenderer.cpp
@@ -138,6 +138,46 @@ void Bars3DRenderer::fixCameraTarget(QVector3D &target)
target.setZ(target.z() * -m_zScaleFactor);
}
+void Bars3DRenderer::getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds)
+{
+ // The inputs are the item bounds in OpenGL coordinates.
+ // The outputs limit these bounds to visible ranges, normalized to range [-1, 1]
+ // Volume shader flips the Y and Z axes, so we need to set negatives of actual values to those
+ float itemRangeX = (maxBounds.x() - minBounds.x());
+ float itemRangeY = (maxBounds.y() - minBounds.y());
+ float itemRangeZ = (maxBounds.z() - minBounds.z());
+
+ if (minBounds.x() < -m_xScaleFactor)
+ minBounds.setX(-1.0f + (2.0f * qAbs(minBounds.x() + m_xScaleFactor) / itemRangeX));
+ else
+ minBounds.setX(-1.0f);
+
+ if (minBounds.y() < -1.0f + m_backgroundAdjustment)
+ minBounds.setY(-(-1.0f + (2.0f * qAbs(minBounds.y() + 1.0f - m_backgroundAdjustment) / itemRangeY)));
+ else
+ minBounds.setY(1.0f);
+
+ if (minBounds.z() < -m_zScaleFactor)
+ minBounds.setZ(-(-1.0f + (2.0f * qAbs(minBounds.z() + m_zScaleFactor) / itemRangeZ)));
+ else
+ minBounds.setZ(1.0f);
+
+ if (maxBounds.x() > m_xScaleFactor)
+ maxBounds.setX(1.0f - (2.0f * qAbs(maxBounds.x() - m_xScaleFactor) / itemRangeX));
+ else
+ maxBounds.setX(1.0f);
+
+ if (maxBounds.y() > 1.0f + m_backgroundAdjustment)
+ maxBounds.setY(-(1.0f - (2.0f * qAbs(maxBounds.y() - 1.0f - m_backgroundAdjustment) / itemRangeY)));
+ else
+ maxBounds.setY(-1.0f);
+
+ if (maxBounds.z() > m_zScaleFactor)
+ maxBounds.setZ(-(1.0f - (2.0f * qAbs(maxBounds.z() - m_zScaleFactor) / itemRangeZ)));
+ else
+ maxBounds.setZ(-1.0f);
+}
+
void Bars3DRenderer::updateData()
{
int minRow = m_axisCacheZ.min();
@@ -1042,7 +1082,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
}
if (m_reflectionEnabled && ((m_yFlipped && item.height() > 0.0)
- || (!m_yFlipped && item.height() < 0.0))) {
+ || (!m_yFlipped && item.height() < 0.0))) {
continue;
}
@@ -1564,7 +1604,7 @@ bool Bars3DRenderer::drawBars(BarRenderItem **selectedBar,
&& (reflection == 1.0f
|| (reflection != 1.0f
&& ((m_yFlipped && item.height() < 0.0)
- || (!m_yFlipped && item.height() > 0.0)))))
+ || (!m_yFlipped && item.height() > 0.0)))))
|| !m_reflectionEnabled) {
// Skip drawing of 0-height bars and reflections of bars on the "wrong side"
// Set shader bindings
@@ -2775,10 +2815,10 @@ QVector3D Bars3DRenderer::convertPositionToTranslation(const QVector3D &position
float zTrans = 0.0f;
if (!isAbsolute) {
// Convert row and column to translation on graph
- xTrans = (((position.x() + 0.5f) * m_cachedBarSpacing.width()) - m_rowWidth)
- / m_scaleFactor;
- zTrans = (m_columnDepth - ((position.z() + 0.5f) * m_cachedBarSpacing.height()))
- / m_scaleFactor;
+ xTrans = (((position.x() - m_axisCacheX.min() + 0.5f) * m_cachedBarSpacing.width())
+ - m_rowWidth) / m_scaleFactor;
+ zTrans = (m_columnDepth - ((position.z() - m_axisCacheZ.min() + 0.5f)
+ * m_cachedBarSpacing.height())) / m_scaleFactor;
yTrans = m_axisCacheY.positionAt(position.y());
} else {
xTrans = position.x() * m_xScaleFactor;
diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h
index 44837ba2..7f1e83bb 100644
--- a/src/datavisualization/engine/bars3drenderer_p.h
+++ b/src/datavisualization/engine/bars3drenderer_p.h
@@ -120,6 +120,7 @@ public:
protected:
virtual void initializeOpenGL();
virtual void fixCameraTarget(QVector3D &target);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds);
public slots:
void updateMultiSeriesScaling(bool uniform);
diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp
index ba1019ad..34386ca6 100644
--- a/src/datavisualization/engine/scatter3drenderer.cpp
+++ b/src/datavisualization/engine/scatter3drenderer.cpp
@@ -141,6 +141,46 @@ void Scatter3DRenderer::fixCameraTarget(QVector3D &target)
target.setZ(target.z() * -m_scaleZ);
}
+void Scatter3DRenderer::getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds)
+{
+ // The inputs are the item bounds in OpenGL coordinates.
+ // The outputs limit these bounds to visible ranges, normalized to range [-1, 1]
+ // Volume shader flips the Y and Z axes, so we need to set negatives of actual values to those
+ float itemRangeX = (maxBounds.x() - minBounds.x());
+ float itemRangeY = (maxBounds.y() - minBounds.y());
+ float itemRangeZ = (maxBounds.z() - minBounds.z());
+
+ if (minBounds.x() < -m_scaleX)
+ minBounds.setX(-1.0f + (2.0f * qAbs(minBounds.x() + m_scaleX) / itemRangeX));
+ else
+ minBounds.setX(-1.0f);
+
+ if (minBounds.y() < -m_scaleY)
+ minBounds.setY(-(-1.0f + (2.0f * qAbs(minBounds.y() + m_scaleY) / itemRangeY)));
+ else
+ minBounds.setY(1.0f);
+
+ if (minBounds.z() < -m_scaleZ)
+ minBounds.setZ(-(-1.0f + (2.0f * qAbs(minBounds.z() + m_scaleZ) / itemRangeZ)));
+ else
+ minBounds.setZ(1.0f);
+
+ if (maxBounds.x() > m_scaleX)
+ maxBounds.setX(1.0f - (2.0f * qAbs(maxBounds.x() - m_scaleX) / itemRangeX));
+ else
+ maxBounds.setX(1.0f);
+
+ if (maxBounds.y() > m_scaleY)
+ maxBounds.setY(-(1.0f - (2.0f * qAbs(maxBounds.y() - m_scaleY) / itemRangeY)));
+ else
+ maxBounds.setY(-1.0f);
+
+ if (maxBounds.z() > m_scaleZ)
+ maxBounds.setZ(-(1.0f - (2.0f * qAbs(maxBounds.z() - m_scaleZ) / itemRangeZ)));
+ else
+ maxBounds.setZ(-1.0f);
+}
+
void Scatter3DRenderer::updateData()
{
calculateSceneScalingFactors();
diff --git a/src/datavisualization/engine/scatter3drenderer_p.h b/src/datavisualization/engine/scatter3drenderer_p.h
index 3fc517d0..0852f262 100644
--- a/src/datavisualization/engine/scatter3drenderer_p.h
+++ b/src/datavisualization/engine/scatter3drenderer_p.h
@@ -114,6 +114,7 @@ public slots:
protected:
virtual void initializeOpenGL();
virtual void fixCameraTarget(QVector3D &target);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds);
private:
virtual void initShaders(const QString &vertexShader, const QString &fragmentShader);
diff --git a/src/datavisualization/engine/shaders/texture3d.frag b/src/datavisualization/engine/shaders/texture3d.frag
index 460cbcc6..3f9c42ff 100644
--- a/src/datavisualization/engine/shaders/texture3d.frag
+++ b/src/datavisualization/engine/shaders/texture3d.frag
@@ -1,15 +1,17 @@
#version 120
varying highp vec3 pos;
+varying highp vec3 rayDir;
uniform highp sampler3D textureSampler;
-uniform highp vec3 cameraPositionRelativeToModel;
uniform highp vec4 colorIndex[256];
uniform highp int color8Bit;
uniform highp vec3 textureDimensions;
uniform highp int sampleCount; // This is the maximum sample count
uniform highp float alphaMultiplier;
uniform highp int preserveOpacity;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
// Ray traveling straight through a single 'alpha thickness' applies 100% of the encountered alpha.
// Rays traveling shorter distances apply a fraction. This is used to normalize the alpha over
@@ -17,51 +19,38 @@ uniform highp int preserveOpacity;
const highp float alphaThicknesses = 32.0;
void main() {
- highp vec3 rayDir = -(cameraPositionRelativeToModel - pos);
vec3 rayStart = pos;
- // Flip Y and Z so QImage bits work directly for texture and first image is in the front
- rayDir.yz = -rayDir.yz;
- rayStart.yz = -rayStart.yz;
- // Calculate ray intersection endpoint
- vec3 rayStop;
- if (rayDir.x == 0.0) {
- rayStop.yz = rayStart.yz;
- rayStop.x = -rayStart.x;
- } else if (rayDir.y == 0.0) {
- rayStop.xz = rayStart.xz;
- rayStop.y = -rayStart.y;
- } else if (rayDir.z == 0.0) {
- rayStop.xy = rayStart.xy;
- rayStop.z = -rayStart.z;
- } else {
- highp vec3 boxBounds = vec3(1.0, 1.0, 1.0);
- highp vec3 invRayDir = 1.0 / rayDir;
- if (rayDir.x < 0)
- boxBounds.x = -1.0;
- if (rayDir.y < 0)
- boxBounds.y = -1.0;
- if (rayDir.z < 0)
- boxBounds.z = -1.0;
- highp vec3 t = (boxBounds - rayStart) * invRayDir;
- highp float minT = min(t.x, min(t.y, t.z));
- rayStop = rayStart + minT * rayDir;
+ highp vec3 startBounds = minBounds;
+ highp vec3 endBounds = maxBounds;
+ if (rayDir.x < 0.0) {
+ startBounds.x = maxBounds.x;
+ endBounds.x = minBounds.x;
+ }
+ if (rayDir.y > 0.0) {
+ startBounds.y = maxBounds.y;
+ endBounds.y = minBounds.y;
+ }
+ if (rayDir.z > 0.0) {
+ startBounds.z = maxBounds.z;
+ endBounds.z = minBounds.z;
}
+ // Calculate ray intersection endpoint
+ highp vec3 rayStop;
+ highp vec3 invRayDir = 1.0 / rayDir;
+ highp vec3 t = (endBounds - rayStart) * invRayDir;
+ highp float endT = min(t.x, min(t.y, t.z));
+ rayStop = rayStart + endT * rayDir;
+ if (endT <= 0.0)
+ discard;
+
// Convert intersections to texture coords
rayStart = 0.5 * (rayStart + 1.0);
rayStop = 0.5 * (rayStop + 1.0);
highp vec3 ray = rayStop - rayStart;
- // Avoid artifacts from divisions by zero
- if (ray.x == 0)
- ray.x = 0.000000001;
- if (ray.y == 0)
- ray.y = 0.000000001;
- if (ray.z == 0)
- ray.z = 0.000000001;
-
highp vec3 absRay = abs(ray);
highp vec3 invAbsRay = 1.0 / absRay;
highp float fullDist = length(ray);
@@ -154,6 +143,9 @@ void main() {
break;
}
+ if (totalOpacity == 1.0)
+ discard;
+
// Brighten up the final color if there is some transparency left
if (totalOpacity >= 0.0 && totalOpacity < 1.0)
destColor *= (1.0 - (totalOpacity * 0.5)) / (1.0 - totalOpacity);
diff --git a/src/datavisualization/engine/shaders/texture3d.vert b/src/datavisualization/engine/shaders/texture3d.vert
index cad1ce06..ef3f1b25 100644
--- a/src/datavisualization/engine/shaders/texture3d.vert
+++ b/src/datavisualization/engine/shaders/texture3d.vert
@@ -1,12 +1,36 @@
uniform highp mat4 MVP;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
+uniform highp vec3 cameraPositionRelativeToModel;
attribute highp vec3 vertexPosition_mdl;
attribute highp vec2 vertexUV;
attribute highp vec3 vertexNormal_mdl;
varying highp vec3 pos;
+varying highp vec3 rayDir;
void main() {
gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
- pos = vertexPosition_mdl;
+
+ highp vec3 minBoundsNorm = minBounds;
+ highp vec3 maxBoundsNorm = maxBounds;
+
+ // Y and Z are flipped in bounds to be directly usable in texture calculations,
+ // so flip them back to normal for position calculations
+ minBoundsNorm.yz = -minBoundsNorm.yz;
+ maxBoundsNorm.yz = -maxBoundsNorm.yz;
+
+ minBoundsNorm = 0.5 * (minBoundsNorm + 1.0);
+ maxBoundsNorm = 0.5 * (maxBoundsNorm + 1.0);
+
+ pos = vertexPosition_mdl
+ + ((1.0 - vertexPosition_mdl) * minBoundsNorm)
+ - ((1.0 + vertexPosition_mdl) * (1.0 - maxBoundsNorm));
+
+ rayDir = -(cameraPositionRelativeToModel - pos);
+
+ // Flip Y and Z so QImage bits work directly for texture and first image is in the front
+ rayDir.yz = -rayDir.yz;
+ pos.yz = -pos.yz;
}
diff --git a/src/datavisualization/engine/shaders/texture3dlowdef.frag b/src/datavisualization/engine/shaders/texture3dlowdef.frag
index 72b959fc..ed0d41ce 100644
--- a/src/datavisualization/engine/shaders/texture3dlowdef.frag
+++ b/src/datavisualization/engine/shaders/texture3dlowdef.frag
@@ -1,15 +1,17 @@
#version 120
varying highp vec3 pos;
+varying highp vec3 rayDir;
uniform highp sampler3D textureSampler;
-uniform highp vec3 cameraPositionRelativeToModel;
uniform highp vec4 colorIndex[256];
uniform highp int color8Bit;
uniform highp vec3 textureDimensions;
uniform highp int sampleCount; // This is the maximum sample count
uniform highp float alphaMultiplier;
uniform highp int preserveOpacity;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
// Ray traveling straight through a single 'alpha thickness' applies 100% of the encountered alpha.
// Rays traveling shorter distances apply a fraction. This is used to normalize the alpha over
@@ -18,36 +20,30 @@ const highp float alphaThicknesses = 32.0;
const highp float SQRT3 = 1.73205081;
void main() {
- highp vec3 rayDir = -(cameraPositionRelativeToModel - pos);
vec3 rayStart = pos;
- // Flip Y and Z so QImage bits work directly for texture and first image is in the front
- rayDir.yz = -rayDir.yz;
- rayStart.yz = -rayStart.yz;
+ highp vec3 startBounds = minBounds;
+ highp vec3 endBounds = maxBounds;
+ if (rayDir.x < 0.0) {
+ startBounds.x = maxBounds.x;
+ endBounds.x = minBounds.x;
+ }
+ if (rayDir.y > 0.0) {
+ startBounds.y = maxBounds.y;
+ endBounds.y = minBounds.y;
+ }
+ if (rayDir.z > 0.0) {
+ startBounds.z = maxBounds.z;
+ endBounds.z = minBounds.z;
+ }
// Calculate ray intersection endpoint
- vec3 rayStop;
- if (rayDir.x == 0.0) {
- rayStop.yz = rayStart.yz;
- rayStop.x = -rayStart.x;
- } else if (rayDir.y == 0.0) {
- rayStop.xz = rayStart.xz;
- rayStop.y = -rayStart.y;
- } else if (rayDir.z == 0.0) {
- rayStop.xy = rayStart.xy;
- rayStop.z = -rayStart.z;
- } else {
- highp vec3 boxBounds = vec3(1.0, 1.0, 1.0);
- highp vec3 invRayDir = 1.0 / rayDir;
- if (rayDir.x < 0)
- boxBounds.x = -1.0;
- if (rayDir.y < 0)
- boxBounds.y = -1.0;
- if (rayDir.z < 0)
- boxBounds.z = -1.0;
- highp vec3 t = (boxBounds - rayStart) * invRayDir;
- highp float minT = min(t.x, min(t.y, t.z));
- rayStop = rayStart + minT * rayDir;
- }
+ highp vec3 rayStop;
+ highp vec3 invRayDir = 1.0 / rayDir;
+ highp vec3 t = (endBounds - rayStart) * invRayDir;
+ highp float endT = min(t.x, min(t.y, t.z));
+ if (endT <= 0.0)
+ discard;
+ rayStop = rayStart + endT * rayDir;
// Convert intersections to texture coords
rayStart = 0.5 * (rayStart + 1.0);
@@ -55,15 +51,6 @@ void main() {
highp vec3 ray = rayStop - rayStart;
- // Avoid artifacts from divisions by zero
- if (ray.x == 0)
- ray.x = 0.000000001;
- if (ray.y == 0)
- ray.y = 0.000000001;
- if (ray.z == 0)
- ray.z = 0.000000001;
-
-
highp float fullDist = length(ray);
highp float stepSize = SQRT3 / sampleCount;
highp vec3 step = (SQRT3 * normalize(ray)) / sampleCount;
@@ -110,6 +97,9 @@ void main() {
break;
}
+ if (totalOpacity == 1.0)
+ discard;
+
// Brighten up the final color if there is some transparency left
if (totalOpacity >= 0.0 && totalOpacity < 1.0)
destColor *= (1.0 - (totalOpacity * 0.5)) / (1.0 - totalOpacity);
diff --git a/src/datavisualization/engine/shaders/texture3dslice.frag b/src/datavisualization/engine/shaders/texture3dslice.frag
index 00584744..c555af98 100644
--- a/src/datavisualization/engine/shaders/texture3dslice.frag
+++ b/src/datavisualization/engine/shaders/texture3dslice.frag
@@ -1,14 +1,16 @@
#version 120
varying highp vec3 pos;
+varying highp vec3 rayDir;
uniform highp sampler3D textureSampler;
-uniform highp vec3 cameraPositionRelativeToModel;
uniform highp vec3 volumeSliceIndices;
uniform highp vec4 colorIndex[256];
uniform highp int color8Bit;
uniform highp float alphaMultiplier;
uniform highp int preserveOpacity;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
const highp vec3 xPlaneNormal = vec3(1.0, 0, 0);
const highp vec3 yPlaneNormal = vec3(0, 1.0, 0);
@@ -16,21 +18,17 @@ const highp vec3 zPlaneNormal = vec3(0, 0, 1.0);
void main() {
// Find out where ray intersects the slice planes
- highp vec3 rayDir = -(cameraPositionRelativeToModel - pos);
- rayDir = normalize(rayDir);
+ vec3 normRayDir = normalize(rayDir);
highp vec3 rayStart = pos;
- // Flip Y and Z so QImage bits work directly for texture and first image is in the front
- rayStart.yz = -rayStart.yz;
- rayDir.yz = -rayDir.yz;
highp float minT = 2.0f;
- if (rayDir.x != 0.0 && rayDir.y != 0.0 && rayDir.z != 0.0) {
+ if (normRayDir.x != 0.0 && normRayDir.y != 0.0 && normRayDir.z != 0.0) {
highp vec3 boxBounds = vec3(1.0, 1.0, 1.0);
- highp vec3 invRayDir = 1.0 / rayDir;
- if (rayDir.x < 0)
+ highp vec3 invRayDir = 1.0 / normRayDir;
+ if (normRayDir.x < 0)
boxBounds.x = -1.0;
- if (rayDir.y < 0)
+ if (normRayDir.y < 0)
boxBounds.y = -1.0;
- if (rayDir.z < 0)
+ if (normRayDir.z < 0)
boxBounds.z = -1.0;
highp vec3 t = (boxBounds - rayStart) * invRayDir;
minT = min(t.x, min(t.y, t.z));
@@ -43,12 +41,12 @@ void main() {
highp float secondD = firstD;
highp float thirdD = firstD;
if (volumeSliceIndices.x >= -1.0) {
- highp float dx = dot(xPoint - rayStart, xPlaneNormal) / dot(rayDir, xPlaneNormal);
+ highp float dx = dot(xPoint - rayStart, xPlaneNormal) / dot(normRayDir, xPlaneNormal);
if (dx >= 0.0 && dx <= minT)
firstD = min(dx, firstD);
}
if (volumeSliceIndices.y >= -1.0) {
- highp float dy = dot(yPoint - rayStart, yPlaneNormal) / dot(rayDir, yPlaneNormal);
+ highp float dy = dot(yPoint - rayStart, yPlaneNormal) / dot(normRayDir, yPlaneNormal);
if (dy >= 0.0 && dy <= minT) {
if (dy < firstD) {
secondD = firstD;
@@ -59,7 +57,7 @@ void main() {
}
}
if (volumeSliceIndices.z >= -1.0) {
- highp float dz = dot(zPoint - rayStart, zPlaneNormal) / dot(rayDir, zPlaneNormal);
+ highp float dz = dot(zPoint - rayStart, zPlaneNormal) / dot(normRayDir, zPlaneNormal);
if (dz >= 0.0) {
if (dz < firstD && dz <= minT) {
thirdD = secondD;
@@ -83,43 +81,35 @@ void main() {
// Convert intersection to texture coords
if (firstD <= minT) {
- highp vec3 firstTex = rayStart + rayDir * firstD;
- firstTex = 0.5 * (firstTex + 1.0);
- curColor = texture3D(textureSampler, firstTex);
- if (color8Bit != 0)
- curColor = colorIndex[int(curColor.r * 255.0)];
-
- if (curColor.a > 0.0) {
- curAlpha = curColor.a;
- if (curColor.a == 1.0 && preserveOpacity != 0)
- curAlpha = 1.0;
- else
- curAlpha = clamp(curColor.a * alphaMultiplier, 0.0, 1.0);
- destColor.rgb = curColor.rgb * curAlpha;
- totalAlpha = curAlpha;
- }
- if (secondD <= minT && totalAlpha < 1.0) {
- highp vec3 secondTex = rayStart + rayDir * secondD;
- secondTex = 0.5 * (secondTex + 1.0);
- curColor = texture3D(textureSampler, secondTex);
+ highp vec3 texelVec = rayStart + normRayDir * firstD;
+ if (clamp(texelVec.x, minBounds.x, maxBounds.x) == texelVec.x
+ && clamp(texelVec.y, maxBounds.y, minBounds.y) == texelVec.y
+ && clamp(texelVec.z, maxBounds.z, minBounds.z) == texelVec.z) {
+ texelVec = 0.5 * (texelVec + 1.0);
+ curColor = texture3D(textureSampler, texelVec);
if (color8Bit != 0)
curColor = colorIndex[int(curColor.r * 255.0)];
+
if (curColor.a > 0.0) {
+ curAlpha = curColor.a;
if (curColor.a == 1.0 && preserveOpacity != 0)
curAlpha = 1.0;
else
curAlpha = clamp(curColor.a * alphaMultiplier, 0.0, 1.0);
- curRgb = curColor.rgb * curAlpha * (1.0 - totalAlpha);
- destColor.rgb += curRgb;
- totalAlpha += curAlpha;
+ destColor.rgb = curColor.rgb * curAlpha;
+ totalAlpha = curAlpha;
}
- if (thirdD <= minT && totalAlpha < 1.0) {
- highp vec3 thirdTex = rayStart + rayDir * thirdD;
- thirdTex = 0.5 * (thirdTex + 1.0);
- curColor = texture3D(textureSampler, thirdTex);
+ }
+ if (secondD <= minT && totalAlpha < 1.0) {
+ texelVec = rayStart + normRayDir * secondD;
+ if (clamp(texelVec.x, minBounds.x, maxBounds.x) == texelVec.x
+ && clamp(texelVec.y, maxBounds.y, minBounds.y) == texelVec.y
+ && clamp(texelVec.z, maxBounds.z, minBounds.z) == texelVec.z) {
+ texelVec = 0.5 * (texelVec + 1.0);
+ curColor = texture3D(textureSampler, texelVec);
+ if (color8Bit != 0)
+ curColor = colorIndex[int(curColor.r * 255.0)];
if (curColor.a > 0.0) {
- if (color8Bit != 0)
- curColor = colorIndex[int(curColor.r * 255.0)];
if (curColor.a == 1.0 && preserveOpacity != 0)
curAlpha = 1.0;
else
@@ -129,9 +119,32 @@ void main() {
totalAlpha += curAlpha;
}
}
+ if (thirdD <= minT && totalAlpha < 1.0) {
+ texelVec = rayStart + normRayDir * thirdD;
+ if (clamp(texelVec.x, minBounds.x, maxBounds.x) == texelVec.x
+ && clamp(texelVec.y, maxBounds.y, minBounds.y) == texelVec.y
+ && clamp(texelVec.z, maxBounds.z, minBounds.z) == texelVec.z) {
+ texelVec = 0.5 * (texelVec + 1.0);
+ curColor = texture3D(textureSampler, texelVec);
+ if (curColor.a > 0.0) {
+ if (color8Bit != 0)
+ curColor = colorIndex[int(curColor.r * 255.0)];
+ if (curColor.a == 1.0 && preserveOpacity != 0)
+ curAlpha = 1.0;
+ else
+ curAlpha = clamp(curColor.a * alphaMultiplier, 0.0, 1.0);
+ curRgb = curColor.rgb * curAlpha * (1.0 - totalAlpha);
+ destColor.rgb += curRgb;
+ totalAlpha += curAlpha;
+ }
+ }
+ }
}
}
+ if (totalAlpha == 0.0)
+ discard;
+
// Brighten up the final color if there is some transparency left
if (totalAlpha > 0.0 && totalAlpha < 1.0)
destColor *= 1.0 / totalAlpha;
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
index ced4c789..fb7322cc 100644
--- a/src/datavisualization/engine/surface3drenderer.cpp
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -158,6 +158,46 @@ void Surface3DRenderer::fixCameraTarget(QVector3D &target)
target.setZ(target.z() * -m_scaleZ);
}
+void Surface3DRenderer::getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds)
+{
+ // The inputs are the item bounds in OpenGL coordinates.
+ // The outputs limit these bounds to visible ranges, normalized to range [-1, 1]
+ // Volume shader flips the Y and Z axes, so we need to set negatives of actual values to those
+ float itemRangeX = (maxBounds.x() - minBounds.x());
+ float itemRangeY = (maxBounds.y() - minBounds.y());
+ float itemRangeZ = (maxBounds.z() - minBounds.z());
+
+ if (minBounds.x() < -m_scaleX)
+ minBounds.setX(-1.0f + (2.0f * qAbs(minBounds.x() + m_scaleX) / itemRangeX));
+ else
+ minBounds.setX(-1.0f);
+
+ if (minBounds.y() < -m_scaleY)
+ minBounds.setY(-(-1.0f + (2.0f * qAbs(minBounds.y() + m_scaleY) / itemRangeY)));
+ else
+ minBounds.setY(1.0f);
+
+ if (minBounds.z() < -m_scaleZ)
+ minBounds.setZ(-(-1.0f + (2.0f * qAbs(minBounds.z() + m_scaleZ) / itemRangeZ)));
+ else
+ minBounds.setZ(1.0f);
+
+ if (maxBounds.x() > m_scaleX)
+ maxBounds.setX(1.0f - (2.0f * qAbs(maxBounds.x() - m_scaleX) / itemRangeX));
+ else
+ maxBounds.setX(1.0f);
+
+ if (maxBounds.y() > m_scaleY)
+ maxBounds.setY(-(1.0f - (2.0f * qAbs(maxBounds.y() - m_scaleY) / itemRangeY)));
+ else
+ maxBounds.setY(-1.0f);
+
+ if (maxBounds.z() > m_scaleZ)
+ maxBounds.setZ(-(1.0f - (2.0f * qAbs(maxBounds.z() - m_scaleZ) / itemRangeZ)));
+ else
+ maxBounds.setZ(-1.0f);
+}
+
void Surface3DRenderer::updateData()
{
calculateSceneScalingFactors();
diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h
index 9c53757d..623951d4 100644
--- a/src/datavisualization/engine/surface3drenderer_p.h
+++ b/src/datavisualization/engine/surface3drenderer_p.h
@@ -111,6 +111,7 @@ public:
protected:
void initializeOpenGL();
virtual void fixCameraTarget(QVector3D &target);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds);
signals:
void flatShadingSupportedChanged(bool supported);
diff --git a/src/datavisualization/global/datavisualizationglobal_p.h b/src/datavisualization/global/datavisualizationglobal_p.h
index f1f51309..16bf7c6d 100644
--- a/src/datavisualization/global/datavisualizationglobal_p.h
+++ b/src/datavisualization/global/datavisualizationglobal_p.h
@@ -52,6 +52,7 @@ static const float gridLineOffset = 0.0035f; // Offset for lifting grid lines of
// y position is added to the minimum height (or can be thought to be that much above or below the camera)
static const QVector3D defaultLightPos = QVector3D(0.0f, 0.5f, 0.0f);
static const QVector3D zeroVector = QVector3D(0.0f, 0.0f, 0.0f);
+static const QVector3D oneVector = QVector3D(1.0f, 1.0f, 1.0f);
static const QVector3D upVector = QVector3D(0.0f, 1.0f, 0.0f);
static const QVector3D cameraDistanceVector = QVector3D(0.0f, 0.0f, cameraDistance);
static const QQuaternion identityQuaternion;
diff --git a/src/datavisualization/utils/shaderhelper.cpp b/src/datavisualization/utils/shaderhelper.cpp
index 9d1ad0d9..b6dc1621 100644
--- a/src/datavisualization/utils/shaderhelper.cpp
+++ b/src/datavisualization/utils/shaderhelper.cpp
@@ -101,6 +101,8 @@ void ShaderHelper::initialize()
m_sampleCountUniform = m_program->uniformLocation("sampleCount");
m_alphaMultiplierUniform = m_program->uniformLocation("alphaMultiplier");
m_preserveOpacityUniform = m_program->uniformLocation("preserveOpacity");
+ m_minBoundsUniform = m_program->uniformLocation("minBounds");
+ m_maxBoundsUniform = m_program->uniformLocation("maxBounds");
m_initialized = true;
}
@@ -324,6 +326,20 @@ GLuint ShaderHelper::preserveOpacity()
return m_preserveOpacityUniform;
}
+GLuint ShaderHelper::maxBounds()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_maxBoundsUniform;
+}
+
+GLuint ShaderHelper::minBounds()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_minBoundsUniform;
+}
+
GLuint ShaderHelper::posAtt()
{
if (!m_initialized)
diff --git a/src/datavisualization/utils/shaderhelper_p.h b/src/datavisualization/utils/shaderhelper_p.h
index ac815447..853fcc8f 100644
--- a/src/datavisualization/utils/shaderhelper_p.h
+++ b/src/datavisualization/utils/shaderhelper_p.h
@@ -82,6 +82,8 @@ class ShaderHelper
GLuint sampleCount();
GLuint alphaMultiplier();
GLuint preserveOpacity();
+ GLuint maxBounds();
+ GLuint minBounds();
GLuint posAtt();
GLuint uvAtt();
@@ -124,6 +126,8 @@ class ShaderHelper
GLuint m_sampleCountUniform;
GLuint m_alphaMultiplierUniform;
GLuint m_preserveOpacityUniform;
+ GLuint m_minBoundsUniform;
+ GLuint m_maxBoundsUniform;
GLboolean m_initialized;
};
diff --git a/tests/volumetrictest/main.cpp b/tests/volumetrictest/main.cpp
index 02f67d6c..7b18ceab 100644
--- a/tests/volumetrictest/main.cpp
+++ b/tests/volumetrictest/main.cpp
@@ -17,7 +17,6 @@
****************************************************************************/
#include "volumetrictest.h"
-
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QHBoxLayout>
@@ -32,7 +31,9 @@
int main(int argc, char **argv)
{
QApplication app(argc, argv);
- Q3DScatter *graph = new Q3DScatter();
+ //Q3DScatter *graph = new Q3DScatter();
+ //Q3DSurface *graph = new Q3DSurface();
+ Q3DBars *graph = new Q3DBars();
QWidget *container = QWidget::createWindowContainer(graph);
QSize screenSize = graph->screen()->size();
diff --git a/tests/volumetrictest/volumetrictest.cpp b/tests/volumetrictest/volumetrictest.cpp
index 6d7da021..a277c8b0 100644
--- a/tests/volumetrictest/volumetrictest.cpp
+++ b/tests/volumetrictest/volumetrictest.cpp
@@ -17,6 +17,7 @@
****************************************************************************/
#include "volumetrictest.h"
+#include <QtDataVisualization/qbar3dseries.h>
#include <QtDataVisualization/qvalue3daxis.h>
#include <QtDataVisualization/q3dscene.h>
#include <QtDataVisualization/q3dcamera.h>
@@ -31,14 +32,14 @@
using namespace QtDataVisualization;
const int imageCount = 512;
-const float xMiddle = 10.0f;
-const float yMiddle = 12.5f;
-const float zMiddle = -40.0f;
+const float xMiddle = 100.0f;
+const float yMiddle = 2.5f;
+const float zMiddle = 100.0f;
const float xRange = 40.0f;
const float yRange = 7.5f;
const float zRange = 20.0f;
-VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
+VolumetricModifier::VolumetricModifier(QAbstract3DGraph *scatter)
: m_graph(scatter),
m_volumeItem(0),
m_volumeItem2(0),
@@ -52,13 +53,55 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
m_graph->setOrthoProjection(true);
- //m_graph->scene()->activeCamera()->setTarget(QVector3D(0.5f, 0.5f, 0.5f));
- m_graph->axisX()->setRange(xMiddle - xRange, xMiddle + xRange);
- m_graph->axisX()->setSegmentCount(8);
- m_graph->axisY()->setRange(yMiddle - yRange, yMiddle + yRange);
- m_graph->axisY()->setSegmentCount(3);
- m_graph->axisZ()->setRange(zMiddle - zRange, zMiddle + zRange);
- m_graph->axisZ()->setSegmentCount(8);
+ //m_graph->scene()->activeCamera()->setTarget(QVector3D(-2.0f, 1.0f, 2.0f));
+ m_scatterGraph = qobject_cast<Q3DScatter *>(m_graph);
+ m_surfaceGraph = qobject_cast<Q3DSurface *>(m_graph);
+ m_barGraph = qobject_cast<Q3DBars *>(m_graph);
+ if (m_scatterGraph) {
+ m_scatterGraph->axisX()->setRange(xMiddle - xRange, xMiddle + xRange);
+ m_scatterGraph->axisX()->setSegmentCount(8);
+ m_scatterGraph->axisY()->setRange(yMiddle - yRange, yMiddle + yRange);
+ m_scatterGraph->axisY()->setSegmentCount(3);
+ m_scatterGraph->axisZ()->setRange(zMiddle - zRange, zMiddle + zRange);
+ m_scatterGraph->axisZ()->setSegmentCount(8);
+ } else if (m_surfaceGraph) {
+ m_surfaceGraph->axisX()->setRange(xMiddle - xRange, xMiddle + xRange);
+ m_surfaceGraph->axisX()->setSegmentCount(8);
+ m_surfaceGraph->axisY()->setRange(yMiddle - yRange, yMiddle + yRange);
+ m_surfaceGraph->axisY()->setSegmentCount(3);
+ m_surfaceGraph->axisZ()->setRange(zMiddle - zRange, zMiddle + zRange);
+ m_surfaceGraph->axisZ()->setSegmentCount(8);
+ } else if (m_barGraph) {
+ QStringList rowLabels;
+ QStringList columnLabels;
+ for (int i = 0; i < xMiddle + xRange; i++) {
+ if (i % 5 == 0)
+ columnLabels << QString::number(i);
+ else
+ columnLabels << QString();
+ }
+ for (int i = 0; i < zMiddle + zRange; i++) {
+ if (i % 5 == 0)
+ rowLabels << QString::number(i);
+ else
+ rowLabels << QString();
+ }
+
+ QBar3DSeries *series = new QBar3DSeries;
+ QBarDataArray *array = new QBarDataArray();
+ array->reserve(zRange * 2 + 1);
+ for (int i = 0; i < zRange * 2 + 1; i++)
+ array->append(new QBarDataRow(xRange * 2 + 1));
+
+ series->dataProxy()->resetArray(array, rowLabels, columnLabels);
+ m_barGraph->addSeries(series);
+
+ m_barGraph->columnAxis()->setRange(xMiddle - xRange, xMiddle + xRange);
+ m_barGraph->valueAxis()->setRange(yMiddle - yRange, yMiddle + yRange);
+ m_barGraph->rowAxis()->setRange(zMiddle - zRange, zMiddle + zRange);
+ //m_barGraph->setReflection(true);
+ }
+ m_graph->activeTheme()->setBackgroundEnabled(false);
createVolume();
createAnotherVolume();
@@ -67,6 +110,7 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
// m_volumeItem->setUseHighDefShader(false);
// m_volumeItem2->setUseHighDefShader(false);
// m_volumeItem3->setUseHighDefShader(false);
+
m_volumeItem->setScalingAbsolute(false);
m_volumeItem2->setScalingAbsolute(false);
m_volumeItem3->setScalingAbsolute(false);
@@ -81,7 +125,7 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_plainItem->setMeshFile(QStringLiteral(":/mesh"));
m_plainItem->setTextureImage(texture);
m_plainItem->setRotation(m_volumeItem->rotation());
- m_plainItem->setPosition(QVector3D(30.0f, 17.5f, -30.0f));
+ m_plainItem->setPosition(QVector3D(xMiddle + xRange / 2.0f, yMiddle + yRange / 2.0f, zMiddle));
m_plainItem->setScaling(QVector3D(20.0f, 5.0f, 10.0f));
m_plainItem->setScalingAbsolute(false);
@@ -243,19 +287,34 @@ void VolumetricModifier::testSubtextureSetting()
void VolumetricModifier::adjustRangeX(int value)
{
float adjustment = float(value - 512) / 10.0f;
- m_graph->axisX()->setRange(xMiddle + adjustment - xRange, xMiddle + adjustment + xRange);
+ if (m_scatterGraph)
+ m_scatterGraph->axisX()->setRange(xMiddle + adjustment - xRange, xMiddle + adjustment + xRange);
+ if (m_surfaceGraph)
+ m_surfaceGraph->axisX()->setRange(xMiddle + adjustment - xRange, xMiddle + adjustment + xRange);
+ if (m_barGraph)
+ m_barGraph->columnAxis()->setRange(xMiddle + adjustment - xRange, xMiddle + adjustment + xRange);
}
void VolumetricModifier::adjustRangeY(int value)
{
float adjustment = float(value - 512) / 10.0f;
- m_graph->axisY()->setRange(yMiddle + adjustment - yRange, yMiddle + adjustment + yRange);
+ if (m_scatterGraph)
+ m_scatterGraph->axisY()->setRange(yMiddle + adjustment - yRange, yMiddle + adjustment + yRange);
+ if (m_surfaceGraph)
+ m_surfaceGraph->axisY()->setRange(yMiddle + adjustment - yRange, yMiddle + adjustment + yRange);
+ if (m_barGraph)
+ m_barGraph->valueAxis()->setRange(yMiddle + adjustment - yRange, yMiddle + adjustment + yRange);
}
void VolumetricModifier::adjustRangeZ(int value)
{
float adjustment = float(value - 512) / 10.0f;
- m_graph->axisZ()->setRange(zMiddle + adjustment - zRange, zMiddle + adjustment + zRange);
+ if (m_scatterGraph)
+ m_scatterGraph->axisZ()->setRange(zMiddle + adjustment - zRange, zMiddle + adjustment + zRange);
+ if (m_surfaceGraph)
+ m_surfaceGraph->axisZ()->setRange(zMiddle + adjustment - zRange, zMiddle + adjustment + zRange);
+ if (m_barGraph)
+ m_barGraph->rowAxis()->setRange(zMiddle + adjustment - zRange, zMiddle + adjustment + zRange);
}
void VolumetricModifier::testBoundsSetting()
@@ -303,6 +362,7 @@ void VolumetricModifier::createVolume()
m_volumeItem->setTextureFormat(QImage::Format_ARGB32);
// m_volumeItem->setRotation(QQuaternion::fromAxisAndAngle(1.0f, 1.0f, 0.0f, 10.0f));
m_volumeItem->setPosition(QVector3D(xMiddle - (xRange / 2.0f), yMiddle + (yRange / 2.0f), zMiddle));
+ //m_volumeItem->setPosition(QVector3D(xMiddle, yMiddle, zMiddle));
QImage logo;
logo.load(QStringLiteral(":/logo_no_padding.png"));
diff --git a/tests/volumetrictest/volumetrictest.h b/tests/volumetrictest/volumetrictest.h
index 48c805d4..9029f7b9 100644
--- a/tests/volumetrictest/volumetrictest.h
+++ b/tests/volumetrictest/volumetrictest.h
@@ -19,9 +19,11 @@
#ifndef VOLUMETRICMODIFIER_H
#define VOLUMETRICMODIFIER_H
-#include <QtDataVisualization/q3dscatter.h>
#include <QtDataVisualization/qcustom3dvolume.h>
#include <QtDataVisualization/qcustom3ditem.h>
+#include <QtDataVisualization/q3dscatter.h>
+#include <QtDataVisualization/q3dsurface.h>
+#include <QtDataVisualization/q3dbars.h>
class QLabel;
@@ -31,7 +33,7 @@ class VolumetricModifier : public QObject
{
Q_OBJECT
public:
- explicit VolumetricModifier(Q3DScatter *scatter);
+ explicit VolumetricModifier(QAbstract3DGraph *scatter);
~VolumetricModifier();
void setFpsLabel(QLabel *fpsLabel);
@@ -58,7 +60,10 @@ private:
void checkRenderCase(int id, Qt::Axis axis, int index, const QVector<uchar> &dataBefore,
QCustom3DVolume *volumeItem);
- Q3DScatter *m_graph;
+ QAbstract3DGraph *m_graph;
+ Q3DScatter *m_scatterGraph;
+ Q3DSurface *m_surfaceGraph;
+ Q3DBars *m_barGraph;
QCustom3DVolume *m_volumeItem;
QCustom3DVolume *m_volumeItem2;
QCustom3DVolume *m_volumeItem3;