From 169a4d638c6c1b6634ffcfd19c4fe3cb94cf27d5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 13 Aug 2014 15:09:36 +0300 Subject: Implement volume rendering support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New subclass of QCustom3DItem, QCustom3DVolume is provided. The documentation for the example will be done in a separate commit. Change-Id: Idb3fdb0654c6bec7606ca012b75852a5a8412397 Reviewed-by: Tomi Korpipää --- examples/datavisualization/datavisualization.pro | 3 +- .../volumetric/doc/src/volumetric.qdoc | 27 ++++ examples/datavisualization/volumetric/main.cpp | 105 ++++++++++++ .../datavisualization/volumetric/volumetric.cpp | 179 +++++++++++++++++++++ examples/datavisualization/volumetric/volumetric.h | 59 +++++++ .../datavisualization/volumetric/volumetric.pro | 15 ++ 6 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 examples/datavisualization/volumetric/doc/src/volumetric.qdoc create mode 100644 examples/datavisualization/volumetric/main.cpp create mode 100644 examples/datavisualization/volumetric/volumetric.cpp create mode 100644 examples/datavisualization/volumetric/volumetric.h create mode 100644 examples/datavisualization/volumetric/volumetric.pro (limited to 'examples') diff --git a/examples/datavisualization/datavisualization.pro b/examples/datavisualization/datavisualization.pro index cb861b81..eab15b6d 100644 --- a/examples/datavisualization/datavisualization.pro +++ b/examples/datavisualization/datavisualization.pro @@ -21,7 +21,8 @@ SUBDIRS += qmlbars \ rotations \ draggableaxes \ customitems \ - texturesurface + texturesurface \ + volumetric } qtHaveModule(multimedia):!android:!ios: SUBDIRS += audiolevels diff --git a/examples/datavisualization/volumetric/doc/src/volumetric.qdoc b/examples/datavisualization/volumetric/doc/src/volumetric.qdoc new file mode 100644 index 00000000..48651cb1 --- /dev/null +++ b/examples/datavisualization/volumetric/doc/src/volumetric.qdoc @@ -0,0 +1,27 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +/*! + \example volumetric + \title Volumetric rendering Example + \ingroup qtdatavisualization_examples + \brief Rendering volumetric objects. + + TODO + \section1 Example contents +*/ diff --git a/examples/datavisualization/volumetric/main.cpp b/examples/datavisualization/volumetric/main.cpp new file mode 100644 index 00000000..7e4c9973 --- /dev/null +++ b/examples/datavisualization/volumetric/main.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "volumetric.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + Q3DScatter *graph = new Q3DScatter(); + QWidget *container = QWidget::createWindowContainer(graph); + + QSize screenSize = graph->screen()->size(); + container->setMinimumSize(QSize(screenSize.width() / 2, screenSize.height() / 1.5)); + container->setMaximumSize(screenSize); + container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + container->setFocusPolicy(Qt::StrongFocus); + + QWidget *widget = new QWidget; + QHBoxLayout *hLayout = new QHBoxLayout(widget); + QVBoxLayout *vLayout = new QVBoxLayout(); + hLayout->addWidget(container, 1); + hLayout->addLayout(vLayout); + + widget->setWindowTitle(QStringLiteral("Volumetric Object Example")); + + QCheckBox *sliceXCheckBox = new QCheckBox(widget); + sliceXCheckBox->setText(QStringLiteral("Slice volume on X axis")); + sliceXCheckBox->setChecked(false); + QCheckBox *sliceYCheckBox = new QCheckBox(widget); + sliceYCheckBox->setText(QStringLiteral("Slice volume on Y axis")); + sliceYCheckBox->setChecked(false); + QCheckBox *sliceZCheckBox = new QCheckBox(widget); + sliceZCheckBox->setText(QStringLiteral("Slice volume on Z axis")); + sliceZCheckBox->setChecked(false); + + QSlider *sliceXSlider = new QSlider(Qt::Horizontal, widget); + sliceXSlider->setMinimum(0); + sliceXSlider->setMaximum(1024); + sliceXSlider->setValue(512); + sliceXSlider->setEnabled(true); + QSlider *sliceYSlider = new QSlider(Qt::Horizontal, widget); + sliceYSlider->setMinimum(0); + sliceYSlider->setMaximum(1024); + sliceYSlider->setValue(512); + sliceYSlider->setEnabled(true); + QSlider *sliceZSlider = new QSlider(Qt::Horizontal, widget); + sliceZSlider->setMinimum(0); + sliceZSlider->setMaximum(1024); + sliceZSlider->setValue(512); + sliceZSlider->setEnabled(true); + + QLabel *fpsLabel = new QLabel(QStringLiteral("Fps: "), widget); + + vLayout->addWidget(fpsLabel); + vLayout->addWidget(sliceXCheckBox); + vLayout->addWidget(sliceXSlider); + vLayout->addWidget(sliceYCheckBox); + vLayout->addWidget(sliceYSlider); + vLayout->addWidget(sliceZCheckBox); + vLayout->addWidget(sliceZSlider, 1, Qt::AlignTop); + + VolumetricModifier *modifier = new VolumetricModifier(graph); + modifier->setFpsLabel(fpsLabel); + + QObject::connect(sliceXCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::sliceX); + QObject::connect(sliceYCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::sliceY); + QObject::connect(sliceZCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::sliceZ); + QObject::connect(sliceXSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustSliceX); + QObject::connect(sliceYSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustSliceY); + QObject::connect(sliceZSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustSliceZ); + + widget->show(); + return app.exec(); +} diff --git a/examples/datavisualization/volumetric/volumetric.cpp b/examples/datavisualization/volumetric/volumetric.cpp new file mode 100644 index 00000000..a9233cab --- /dev/null +++ b/examples/datavisualization/volumetric/volumetric.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "volumetric.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace QtDataVisualization; + +const int textureSize = 256; + +VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) + : m_graph(scatter), + m_volumeItem(0), + m_sliceIndexX(textureSize / 2), + m_sliceIndexY(textureSize / 4), + m_sliceIndexZ(textureSize / 2) +{ + m_graph->activeTheme()->setType(Q3DTheme::ThemeQt); + m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone); + m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront); + m_graph->setOrthoProjection(true); + + createVolume(); + + m_graph->addCustomItem(m_volumeItem); + m_graph->setMeasureFps(true); + + QObject::connect(m_graph->scene()->activeCamera(), &Q3DCamera::zoomLevelChanged, this, + &VolumetricModifier::handleZoomLevelChange); + QObject::connect(m_graph, &QAbstract3DGraph::currentFpsChanged, this, + &VolumetricModifier::handleFpsChange); +} + +VolumetricModifier::~VolumetricModifier() +{ + delete m_graph; +} + +void VolumetricModifier::setFpsLabel(QLabel *fpsLabel) +{ + m_fpsLabel = fpsLabel; +} + +void VolumetricModifier::sliceX(int enabled) +{ + m_volumeItem->setSliceIndexX(enabled ? m_sliceIndexX : -1); +} + +void VolumetricModifier::sliceY(int enabled) +{ + m_volumeItem->setSliceIndexY(enabled ? m_sliceIndexY : -1); +} + +void VolumetricModifier::sliceZ(int enabled) +{ + m_volumeItem->setSliceIndexZ(enabled ? m_sliceIndexZ : -1); +} + +void VolumetricModifier::adjustSliceX(int value) +{ + m_sliceIndexX = value / (1024 / textureSize); + if (m_volumeItem->sliceIndexX() != -1) + m_volumeItem->setSliceIndexX(m_sliceIndexX); +} + +void VolumetricModifier::adjustSliceY(int value) +{ + m_sliceIndexY = value / (1024 / textureSize * 2); + if (m_volumeItem->sliceIndexY() != -1) + m_volumeItem->setSliceIndexY(m_sliceIndexY); +} + +void VolumetricModifier::adjustSliceZ(int value) +{ + m_sliceIndexZ = value / (1024 / textureSize); + if (m_volumeItem->sliceIndexZ() != -1) + m_volumeItem->setSliceIndexZ(m_sliceIndexZ); +} + +void VolumetricModifier::handleZoomLevelChange() +{ + // Zooming inside volumetric object causes ugly clipping issues, so restrict zoom level a bit + if (m_graph->scene()->activeCamera()->zoomLevel() > 220) + m_graph->scene()->activeCamera()->setZoomLevel(220); +} + +void VolumetricModifier::handleFpsChange(qreal fps) +{ + const QString fpsFormat = QStringLiteral("Fps: %1"); + int fps10 = int(fps * 10.0); + m_fpsLabel->setText(fpsFormat.arg(QString::number(qreal(fps10) / 10.0))); +} + +void VolumetricModifier::createVolume() +{ + m_volumeItem = new QCustom3DVolume; + m_volumeItem->setScaling(QVector3D(2.0f, 1.0f, 2.0f)); + m_volumeItem->setTextureWidth(textureSize); + m_volumeItem->setTextureHeight(textureSize / 2); + m_volumeItem->setTextureDepth(textureSize); + m_volumeItem->setTextureFormat(QImage::Format_Indexed8); + + // Generate color table. First color is fully transparent used to fill outer + // portions of the volume. The second, red layer, is somewhat transparent. + // Rest of to colors are opaque. + QVector colors; + colors.resize(256); + + colors[0] = qRgba(0, 0, 0, 0); + for (int i = 1; i < 256; i++) { + if (i < 60) { + colors[i] = qRgba((i * 2) + 120, 0, 0, 100); + } else if (i < 120) { + colors[i] = qRgba(0, ((i - 60) * 2) + 120, 0, 255); + } else if (i < 180) { + colors[i] = qRgba(0, 0, ((i - 120) * 2) + 120, 255); + } else { + colors[i] = qRgba(i, i, i, 255); + } + } + m_volumeItem->setColorTable(colors); + + // Generate texture data for an half-ellipsoid. + // This can take a while if the dimensions are large. + // Note that in real world cases, the texture data is usually be supplied + // as a stack of slice images. + + QVector *textureData = new QVector(textureSize * textureSize * textureSize / 2); + + QVector3D midPoint(float(textureSize) / 2.0f, + float(textureSize) / 2.0f, + float(textureSize) / 2.0f); + + int index = 0; + for (int i = 0; i < textureSize; i++) { + for (int j = 0; j < textureSize / 2; j++) { + for (int k = 0; k < textureSize; k++) { + int colorIndex = 0; + // Take a slice out of the ellipsoid + if (i >= textureSize / 2 || j >= textureSize / 4 || k >= textureSize / 2) { + QVector3D distVec = QVector3D(float(k), float(j * 2), float(i)) - midPoint; + float adjLen = qMin(255.0f, (distVec.length() * float(textureSize / 128))); + if (adjLen < 230) + colorIndex = 255 - int(adjLen); + else + colorIndex = 0; + } + + (*textureData)[index] = colorIndex; + index++; + } + } + } + + m_volumeItem->setTextureData(textureData); +} + diff --git a/examples/datavisualization/volumetric/volumetric.h b/examples/datavisualization/volumetric/volumetric.h new file mode 100644 index 00000000..722d4b48 --- /dev/null +++ b/examples/datavisualization/volumetric/volumetric.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef VOLUMETRICMODIFIER_H +#define VOLUMETRICMODIFIER_H + +#include +#include + +class QLabel; + +using namespace QtDataVisualization; + +class VolumetricModifier : public QObject +{ + Q_OBJECT +public: + explicit VolumetricModifier(Q3DScatter *scatter); + ~VolumetricModifier(); + + void setFpsLabel(QLabel *fpsLabel); + +public slots: + void sliceX(int enabled); + void sliceY(int enabled); + void sliceZ(int enabled); + void adjustSliceX(int value); + void adjustSliceY(int value); + void adjustSliceZ(int value); + void handleZoomLevelChange(); + void handleFpsChange(qreal fps); + +private: + void createVolume(); + + Q3DScatter *m_graph; + QCustom3DVolume *m_volumeItem; + int m_sliceIndexX; + int m_sliceIndexY; + int m_sliceIndexZ; + QLabel *m_fpsLabel; +}; + +#endif diff --git a/examples/datavisualization/volumetric/volumetric.pro b/examples/datavisualization/volumetric/volumetric.pro new file mode 100644 index 00000000..c5e31891 --- /dev/null +++ b/examples/datavisualization/volumetric/volumetric.pro @@ -0,0 +1,15 @@ +android|ios { + error( "This example is not supported for android or ios." ) +} + +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +SOURCES += main.cpp volumetric.cpp +HEADERS += volumetric.h + +QT += widgets + +OTHER_FILES += doc/src/* \ + doc/images/* -- cgit v1.2.3