summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2014-09-12 13:37:27 +0300
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2014-09-15 09:40:41 +0300
commit637fd9964133c4e60d9ffad32cf5307836397aad (patch)
tree00912c5ec78db287099fa8658ef0fc65159c726b /examples
parente5f6ab99b413ad9b8481ad923c5a4a5bc6513ff2 (diff)
Documentation for volumetric example
Change-Id: Ibf613607b55e5ed0b56354d5da426870624d79ad Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/datavisualization/volumetric/doc/src/volumetric.qdoc104
-rw-r--r--examples/datavisualization/volumetric/volumetric.cpp39
2 files changed, 135 insertions, 8 deletions
diff --git a/examples/datavisualization/volumetric/doc/src/volumetric.qdoc b/examples/datavisualization/volumetric/doc/src/volumetric.qdoc
index 48651cb1..39616670 100644
--- a/examples/datavisualization/volumetric/doc/src/volumetric.qdoc
+++ b/examples/datavisualization/volumetric/doc/src/volumetric.qdoc
@@ -21,7 +21,109 @@
\title Volumetric rendering Example
\ingroup qtdatavisualization_examples
\brief Rendering volumetric objects.
+ \since QtDataVisualization 1.2
+
+ This example shows how to use QCustom3DVolume items to display volumetric data.
+
+ \image volumetric-example.png
+
+ \section1 Initializing volume item
+
+ The QCustom3DVolume items are special custom items (see QCustom3DItem), which can be used
+ to display volumetric data. The volume items are only supported with orthographic projection,
+ so first we make sure the graph is using it:
+
+ \snippet volumetric/volumetric.cpp 6
+
+ The following code shows how to create a volumetric item tied to the data ranges of the axes:
+
+ \snippet volumetric/volumetric.cpp 0
+
+ By setting the QCustom3DItem::scalingAbsolute property to \c{false}, we indicate that the
+ scaling of the volume should follow the changes in the data ranges. Next we define the
+ internal contents of the volume:
+
+ \snippet volumetric/volumetric.cpp 1
+
+ We use eight bit indexed color for our texture, as it is compact and makes it easy to adjust the
+ colors without needing to reset the whole texture. For the texture data we use the data we
+ created earlier based on some height maps.
+ Typically the data for volume items comes pregenerated in a form of a stack of images, so we are
+ not going to explain the data generation in detail. Please refer to the example code if you
+ are interested in the actual data generation process.
+
+ Since we are using eight bit indexed colors, we need a color table to map the eight bit color
+ indexes to actual colors. We use one we populated on our own, but in a typical use case you
+ would get the color table from the source images:
+
+ \snippet volumetric/volumetric.cpp 2
+
+ We want to optionally show slice frames around the volume, so we initialize their properties.
+ Initially, the frames will be hidden:
+
+ \snippet volumetric/volumetric.cpp 5
+
+ Finally we add the volume as a custom item to the graph to display it:
+
+ \snippet volumetric/volumetric.cpp 3
+
+ \section1 Slicing into the volume
+
+ Unless the volume is largely transparent, you can only see the surface of it, which is often
+ not very helpful. One way to inspect the internal structure of the volume is to view the slices
+ of the volume. QCustom3DVolume provides two ways to display the slices. The first is to show
+ the selected slices in place of the volume. For example, to specify a slice perpendicular to
+ the X-axis, you can use the following method:
+
+ \snippet volumetric/volumetric.cpp 7
+
+ To actually draw the slice specified above, the QCustom3DVolume::drawSlices property must be
+ also set:
+
+ \snippet volumetric/volumetric.cpp 8
+
+ The second way to view slices is to use QCustom3DVolume::renderSlice() method, which produces
+ a QImage from the specified slice. This image can then be displayed on another widget, such
+ as a QLabel here:
+
+ \snippet volumetric/volumetric.cpp 9
+
+ \section1 Adjusting volume transparency
+
+ Sometimes viewing just the slices doesn't give you a good understanding of the volume's internal
+ structure. QCustom3DVolume provides two properties that can be used to adjust the volume
+ transparency:
+
+ \snippet volumetric/volumetric.cpp 11
+ \dots
+ \snippet volumetric/volumetric.cpp 10
+
+ The QCustom3DVolume::alphaMultiplier is a general multiplier that is applied to the alpha value
+ of each voxel of the volume. It makes it possible to add uniform transparency to the already
+ somewhat transparent portions of the volume to reveal internal opaque details. This multiplier
+ doesn't affect colors that are fully opaque, unless the QCustom3DVolume::preserveOpacity
+ property is set to \c{false}.
+
+ An alternative way to adjust the transparency of the volume is adjust the alpha values of the
+ voxels directly. For eight bit indexed textures, this is done simply by modifying and
+ resetting the color table:
+
+ \snippet volumetric/volumetric.cpp 12
+
+ \section1 High definition vs. low definition shader
+
+ By default the volume rendering uses the high definition shader. It accounts for each
+ voxel of the volume with correct weight when ray-tracing the volume contents,
+ providing an accurate representation of even the finer details of the volume.
+ However, this is computationally very expensive, so the frame rate suffers.
+ If rendering speed is more important than pixel-perfect
+ accuracy of the volume contents, you can take the much faster low definition shader into use
+ by setting \c{false} for QCustom3DVolume::useHighDefShader property. The low definition shader
+ achieves the speed by making compromises on the accuracy, so it doesn't guarantee each voxel
+ of the volume will be sampled. This can lead to flickering and/or other rendering artifacts
+ on the finer details of the volume.
+
+ \snippet volumetric/volumetric.cpp 13
- TODO
\section1 Example contents
*/
diff --git a/examples/datavisualization/volumetric/volumetric.cpp b/examples/datavisualization/volumetric/volumetric.cpp
index 80df4bd5..6672d964 100644
--- a/examples/datavisualization/volumetric/volumetric.cpp
+++ b/examples/datavisualization/volumetric/volumetric.cpp
@@ -81,7 +81,9 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_graph->activeTheme()->setType(Q3DTheme::ThemeQt);
m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
+ //! [6]
m_graph->setOrthoProjection(true);
+ //! [6]
m_graph->activeTheme()->setBackgroundEnabled(false);
toggleAreaAll(true);
@@ -100,6 +102,7 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
createVolume(lowDetailSize, 0, lowDetailSize, m_lowDetailData);
excavateMineShaft(lowDetailSize, 0, m_mineShaftArray.size(), m_lowDetailData);
+ //! [0]
m_volumeItem = new QCustom3DVolume;
// Adjust water level to zero with a minor tweak to y-coordinate position and scaling
m_volumeItem->setScaling(
@@ -112,11 +115,14 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
(m_graph->axisY()->max() + m_graph->axisY()->min()) / 2.0f,
(m_graph->axisZ()->max() + m_graph->axisZ()->min()) / 2.0f));
m_volumeItem->setScalingAbsolute(false);
+ //! [0]
+ //! [1]
m_volumeItem->setTextureWidth(lowDetailSize);
m_volumeItem->setTextureHeight(lowDetailSize / 2);
m_volumeItem->setTextureDepth(lowDetailSize);
m_volumeItem->setTextureFormat(QImage::Format_Indexed8);
m_volumeItem->setTextureData(new QVector<uchar>(*m_lowDetailData));
+ //! [1]
// Generate color tables.
m_colorTable1.resize(colorTableSize);
@@ -164,15 +170,21 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_colorTable2[airColorIndex] = qRgba(0, 0, 0, 0);
m_colorTable2[mineShaftColorIndex] = qRgba(255, 255, 0, 255);
+ //! [2]
m_volumeItem->setColorTable(m_colorTable1);
+ //! [2]
+ //! [5]
m_volumeItem->setSliceFrameGaps(QVector3D(0.01f, 0.02f, 0.01f));
m_volumeItem->setSliceFrameThicknesses(QVector3D(0.0025f, 0.005f, 0.0025f));
m_volumeItem->setSliceFrameWidths(QVector3D(0.0025f, 0.005f, 0.0025f));
m_volumeItem->setDrawSliceFrames(false);
+ //! [5]
handleSlicingChanges();
+ //! [3]
m_graph->addCustomItem(m_volumeItem);
+ //! [3]
m_timer.start(0);
#else
@@ -259,9 +271,13 @@ void VolumetricModifier::adjustSliceX(int value)
m_sliceIndexX--;
if (m_volumeItem) {
if (m_volumeItem->sliceIndexX() != -1)
+ //! [7]
m_volumeItem->setSliceIndexX(m_sliceIndexX);
- m_sliceLabelX->setPixmap(QPixmap::fromImage(
- m_volumeItem->renderSlice(Qt::XAxis, m_sliceIndexX)));
+ //! [7]
+ //! [9]
+ m_sliceLabelX->setPixmap(
+ QPixmap::fromImage(m_volumeItem->renderSlice(Qt::XAxis, m_sliceIndexX)));
+ //! [9]
}
}
@@ -273,8 +289,8 @@ void VolumetricModifier::adjustSliceY(int value)
if (m_volumeItem) {
if (m_volumeItem->sliceIndexY() != -1)
m_volumeItem->setSliceIndexY(m_sliceIndexY);
- m_sliceLabelY->setPixmap(QPixmap::fromImage(
- m_volumeItem->renderSlice(Qt::YAxis, m_sliceIndexY)));
+ m_sliceLabelY->setPixmap(
+ QPixmap::fromImage(m_volumeItem->renderSlice(Qt::YAxis, m_sliceIndexY)));
}
}
@@ -286,8 +302,8 @@ void VolumetricModifier::adjustSliceZ(int value)
if (m_volumeItem) {
if (m_volumeItem->sliceIndexZ() != -1)
m_volumeItem->setSliceIndexZ(m_sliceIndexZ);
- m_sliceLabelZ->setPixmap(QPixmap::fromImage(
- m_volumeItem->renderSlice(Qt::ZAxis, m_sliceIndexZ)));
+ m_sliceLabelZ->setPixmap(
+ QPixmap::fromImage(m_volumeItem->renderSlice(Qt::ZAxis, m_sliceIndexZ)));
}
}
@@ -406,7 +422,9 @@ void VolumetricModifier::changeColorTable(int enabled)
void VolumetricModifier::setPreserveOpacity(bool enabled)
{
+ //! [10]
m_volumeItem->setPreserveOpacity(enabled);
+ //! [10]
// Rerender image labels
adjustSliceX(m_sliceSliderX->value());
@@ -416,6 +434,7 @@ void VolumetricModifier::setPreserveOpacity(bool enabled)
void VolumetricModifier::setTransparentGround(bool enabled)
{
+ //! [12]
int newAlpha = enabled ? terrainTransparency : 255;
for (int i = aboveWaterGroundColorsMin; i < underWaterGroundColorsMax; i++) {
QRgb oldColor1 = m_colorTable1.at(i);
@@ -427,7 +446,7 @@ void VolumetricModifier::setTransparentGround(bool enabled)
m_volumeItem->setColorTable(m_colorTable1);
else
m_volumeItem->setColorTable(m_colorTable2);
-
+ //! [12]
adjustSliceX(m_sliceSliderX->value());
adjustSliceY(m_sliceSliderY->value());
adjustSliceZ(m_sliceSliderZ->value());
@@ -435,7 +454,9 @@ void VolumetricModifier::setTransparentGround(bool enabled)
void VolumetricModifier::setUseHighDefShader(bool enabled)
{
+ //! [13]
m_volumeItem->setUseHighDefShader(enabled);
+ //! [13]
}
void VolumetricModifier::adjustAlphaMultiplier(int value)
@@ -445,7 +466,9 @@ void VolumetricModifier::adjustAlphaMultiplier(int value)
mult = float(value - 99) / 2.0f;
else
mult = float(value) / float(500 - value * 4);
+ //! [11]
m_volumeItem->setAlphaMultiplier(mult);
+ //! [11]
QString labelFormat = QStringLiteral("Alpha multiplier: %1");
m_alphaMultiplierLabel->setText(labelFormat.arg(
QString::number(m_volumeItem->alphaMultiplier(), 'f', 3)));
@@ -628,7 +651,9 @@ void VolumetricModifier::handleSlicingChanges()
if (m_volumeItem) {
if (m_slicingX || m_slicingY || m_slicingZ) {
// Only show slices of selected dimensions
+ //! [8]
m_volumeItem->setDrawSlices(true);
+ //! [8]
m_volumeItem->setSliceIndexX(m_slicingX ? m_sliceIndexX : -1);
m_volumeItem->setSliceIndexY(m_slicingY ? m_sliceIndexY : -1);
m_volumeItem->setSliceIndexZ(m_slicingZ ? m_sliceIndexZ : -1);