From 637fd9964133c4e60d9ffad32cf5307836397aad Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 12 Sep 2014 13:37:27 +0300 Subject: Documentation for volumetric example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ibf613607b55e5ed0b56354d5da426870624d79ad Reviewed-by: Tomi Korpipää --- .../volumetric/doc/src/volumetric.qdoc | 104 ++++++++++++++++++++- .../datavisualization/volumetric/volumetric.cpp | 39 ++++++-- 2 files changed, 135 insertions(+), 8 deletions(-) (limited to 'examples/datavisualization/volumetric') 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(*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); -- cgit v1.2.3