From e5f6ab99b413ad9b8481ad923c5a4a5bc6513ff2 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 12 Sep 2014 11:27:24 +0300 Subject: Implement volume slice frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I409f3c95892b26ca6097dd4509109fc9978b9900 Reviewed-by: Tomi Korpipää --- .../engine/abstract3drenderer.cpp | 179 ++++++++++++++++++--- .../engine/abstract3drenderer_p.h | 7 +- src/datavisualization/engine/engine.qrc | 2 + .../engine/shaders/3dsliceframes.frag | 15 ++ .../engine/shaders/colorandposition.vert | 10 ++ 5 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 src/datavisualization/engine/shaders/3dsliceframes.frag create mode 100644 src/datavisualization/engine/shaders/colorandposition.vert (limited to 'src/datavisualization/engine') diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index 305d3df0..4dd58490 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -62,6 +62,7 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller) m_volumeTextureShader(0), m_volumeTextureLowDefShader(0), m_volumeTextureSliceShader(0), + m_volumeSliceFrameShader(0), m_useOrthoProjection(false), m_xFlipped(false), m_yFlipped(false), @@ -105,6 +106,7 @@ Abstract3DRenderer::~Abstract3DRenderer() delete m_customItemShader; delete m_volumeTextureShader; delete m_volumeTextureLowDefShader; + delete m_volumeSliceFrameShader; delete m_volumeTextureSliceShader; foreach (SeriesRenderCache *cache, m_renderCacheList) { @@ -208,7 +210,9 @@ void Abstract3DRenderer::initCustomItemShaders(const QString &vertexShader, void Abstract3DRenderer::initVolumeTextureShaders(const QString &vertexShader, const QString &fragmentShader, const QString &fragmentLowDefShader, - const QString &sliceShader) + const QString &sliceShader, + const QString &sliceFrameVertexShader, + const QString &sliceFrameShader) { delete m_volumeTextureShader; @@ -216,13 +220,16 @@ void Abstract3DRenderer::initVolumeTextureShaders(const QString &vertexShader, m_volumeTextureShader->initialize(); delete m_volumeTextureLowDefShader; - m_volumeTextureLowDefShader = new ShaderHelper(this, vertexShader, - fragmentLowDefShader); + m_volumeTextureLowDefShader = new ShaderHelper(this, vertexShader, fragmentLowDefShader); m_volumeTextureLowDefShader->initialize(); delete m_volumeTextureSliceShader; m_volumeTextureSliceShader = new ShaderHelper(this, vertexShader, sliceShader); m_volumeTextureSliceShader->initialize(); + + delete m_volumeSliceFrameShader; + m_volumeSliceFrameShader = new ShaderHelper(this, sliceFrameVertexShader, sliceFrameShader); + m_volumeSliceFrameShader->initialize(); } void Abstract3DRenderer::updateTheme(Q3DTheme *theme) @@ -327,7 +334,9 @@ void Abstract3DRenderer::reInitShaders() initVolumeTextureShaders(QStringLiteral(":/shaders/vertexTexture3D"), QStringLiteral(":/shaders/fragmentTexture3D"), QStringLiteral(":/shaders/fragmentTexture3DLowDef"), - QStringLiteral(":/shaders/fragmentTexture3DSlice")); + QStringLiteral(":/shaders/fragmentTexture3DSlice"), + QStringLiteral(":/shaders/colorAndPosition"), + QStringLiteral(":/shaders/fragment3DSliceFrames")); #else if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic) && qobject_cast(this)) { @@ -1011,6 +1020,13 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) newItem->setAlphaMultiplier(volumeItem->alphaMultiplier()); newItem->setPreserveOpacity(volumeItem->preserveOpacity()); newItem->setUseHighDefShader(volumeItem->useHighDefShader()); + + newItem->setDrawSlices(volumeItem->drawSlices()); + newItem->setDrawSliceFrames(volumeItem->drawSliceFrames()); + newItem->setSliceFrameColor(volumeItem->sliceFrameColor()); + newItem->setSliceFrameWidths(volumeItem->sliceFrameWidths()); + newItem->setSliceFrameGaps(volumeItem->sliceFrameGaps()); + newItem->setSliceFrameThicknesses(volumeItem->sliceFrameThicknesses()); #endif } recalculateCustomItemScalingAndPos(newItem); @@ -1215,11 +1231,17 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) volumeItem->dptr()->m_dirtyBitsVolume.textureDataDirty = false; volumeItem->dptr()->m_dirtyBitsVolume.textureFormatDirty = false; } - if (volumeItem->dptr()->m_dirtyBitsVolume.sliceIndicesDirty) { + if (volumeItem->dptr()->m_dirtyBitsVolume.slicesDirty) { + renderItem->setDrawSlices(volumeItem->drawSlices()); + renderItem->setDrawSliceFrames(volumeItem->drawSliceFrames()); + renderItem->setSliceFrameColor(volumeItem->sliceFrameColor()); + renderItem->setSliceFrameWidths(volumeItem->sliceFrameWidths()); + renderItem->setSliceFrameGaps(volumeItem->sliceFrameGaps()); + renderItem->setSliceFrameThicknesses(volumeItem->sliceFrameThicknesses()); renderItem->setSliceIndexX(volumeItem->sliceIndexX()); renderItem->setSliceIndexY(volumeItem->sliceIndexY()); renderItem->setSliceIndexZ(volumeItem->sliceIndexZ()); - volumeItem->dptr()->m_dirtyBitsVolume.sliceIndicesDirty = false; + volumeItem->dptr()->m_dirtyBitsVolume.slicesDirty = false; } if (volumeItem->dptr()->m_dirtyBitsVolume.alphaDirty) { renderItem->setAlphaMultiplier(volumeItem->alphaMultiplier()); @@ -1236,9 +1258,8 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) void Abstract3DRenderer::updateCustomItemPositions() { - foreach (CustomRenderItem *renderItem, m_customRenderCache) { + foreach (CustomRenderItem *renderItem, m_customRenderCache) recalculateCustomItemScalingAndPos(renderItem); - } } void Abstract3DRenderer::drawCustomItems(RenderingState state, @@ -1345,9 +1366,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, #if !defined(QT_OPENGL_ES_2) ShaderHelper *prevShader = shader; if (item->isVolume()) { - if (item->sliceIndexX() >= 0 - || item->sliceIndexY() >= 0 - || item->sliceIndexZ() >= 0) { + if (item->drawSlices() && + (item->sliceIndexX() >= 0 + || item->sliceIndexY() >= 0 + || item->sliceIndexZ() >= 0)) { shader = m_volumeTextureSliceShader; } else if (item->useHighDefShader()) { shader = m_volumeTextureShader; @@ -1395,10 +1417,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, 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); + 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) { shader->setUniformValueArray(shader->colorIndex(), @@ -1412,14 +1434,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, shader->setUniformValue(shader->minBounds(), item->minBounds()); shader->setUniformValue(shader->maxBounds(), item->maxBounds()); + QVector3D slices; if (shader == m_volumeTextureSliceShader) { - QVector3D slices((float(item->sliceIndexX()) + 0.5f) - / float(item->textureWidth()) * 2.0 - 1.0, - (float(item->sliceIndexY()) + 0.5f) - / float(item->textureHeight()) * 2.0 - 1.0, - (float(item->sliceIndexZ()) + 0.5f) - / float(item->textureDepth()) * 2.0 - 1.0); - shader->setUniformValue(shader->volumeSliceIndices(), slices); + shader->setUniformValue(shader->volumeSliceIndices(), + item->sliceFractions()); } else { // Precalculate texture dimensions so we can optimize // ray stepping to hit every texture layer. @@ -1443,6 +1461,24 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, shader->setUniformValue(shader->textureDimensions(), textureDimensions); shader->setUniformValue(shader->sampleCount(), sampleCount); } + if (item->drawSliceFrames()) { + // Set up the slice frame shader + glDisable(GL_CULL_FACE); + m_volumeSliceFrameShader->bind(); + m_volumeSliceFrameShader->setUniformValue( + m_volumeSliceFrameShader->color(), item->sliceFrameColor()); + + // Draw individual slice frames. + if (item->sliceIndexX() >= 0) + drawVolumeSliceFrame(item, Qt::XAxis, projectionViewMatrix); + if (item->sliceIndexY() >= 0) + drawVolumeSliceFrame(item, Qt::YAxis, projectionViewMatrix); + if (item->sliceIndexZ() >= 0) + drawVolumeSliceFrame(item, Qt::ZAxis, projectionViewMatrix); + + glEnable(GL_CULL_FACE); + shader->bind(); + } m_drawer->drawObject(shader, item->mesh(), 0, 0, item->texture()); } else #endif @@ -1476,6 +1512,105 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, } } +void Abstract3DRenderer::drawVolumeSliceFrame(const CustomRenderItem *item, Qt::Axis axis, + const QMatrix4x4 &projectionViewMatrix) +{ + QVector2D frameWidth; + QVector3D frameScaling; + QVector3D translation = item->translation(); + QQuaternion rotation = item->rotation(); + float fracTrans; + bool needRotate = !rotation.isIdentity(); + QMatrix4x4 rotationMatrix; + if (needRotate) + rotationMatrix.rotate(rotation); + + if (axis == Qt::XAxis) { + fracTrans = item->sliceFractions().x(); + float range = item->maxBoundsNormal().x() - item->minBoundsNormal().x(); + float minMult = item->minBoundsNormal().x() / range; + float maxMult = (1.0f - item->maxBoundsNormal().x()) / range; + fracTrans = fracTrans - ((1.0f - fracTrans) * minMult) + ((1.0f + fracTrans) * maxMult); + if (needRotate) + translation -= rotationMatrix.map(QVector3D(fracTrans * item->scaling().x(), 0.0f, 0.0f)); + else + translation.setX(translation.x() + fracTrans * item->scaling().x()); + frameScaling = QVector3D(item->scaling().z() + + (item->scaling().z() * item->sliceFrameGaps().z()) + + (item->scaling().z() * item->sliceFrameWidths().z()), + item->scaling().y() + + (item->scaling().y() * item->sliceFrameGaps().y()) + + (item->scaling().y() * item->sliceFrameWidths().y()), + item->scaling().x() * item->sliceFrameThicknesses().x()); + frameWidth = QVector2D(item->scaling().z() * item->sliceFrameWidths().z(), + item->scaling().y() * item->sliceFrameWidths().y()); + rotation *= m_yRightAngleRotation; + } else if (axis == Qt::YAxis) { + fracTrans = item->sliceFractions().y(); + float range = item->maxBoundsNormal().y() - item->minBoundsNormal().y(); + // Y axis is logically flipped, so we need to swam min and max bounds + float minMult = (1.0f - item->maxBoundsNormal().y()) / range; + float maxMult = item->minBoundsNormal().y() / range; + fracTrans = fracTrans - ((1.0f - fracTrans) * minMult) + ((1.0f + fracTrans) * maxMult); + if (needRotate) + translation -= rotationMatrix.map(QVector3D(0.0f, fracTrans * item->scaling().y(), 0.0f)); + else + translation.setY(translation.y() - fracTrans * item->scaling().y()); + frameScaling = QVector3D(item->scaling().x() + + (item->scaling().x() * item->sliceFrameGaps().x()) + + (item->scaling().x() * item->sliceFrameWidths().x()), + item->scaling().z() + + (item->scaling().z() * item->sliceFrameGaps().z()) + + (item->scaling().z() * item->sliceFrameWidths().z()), + item->scaling().y() * item->sliceFrameThicknesses().y()); + frameWidth = QVector2D(item->scaling().x() * item->sliceFrameWidths().x(), + item->scaling().z() * item->sliceFrameWidths().z()); + rotation *= m_xRightAngleRotation; + } else { // Z axis + fracTrans = item->sliceFractions().z(); + float range = item->maxBoundsNormal().z() - item->minBoundsNormal().z(); + // Z axis is logically flipped, so we need to swam min and max bounds + float minMult = (1.0f - item->maxBoundsNormal().z()) / range; + float maxMult = item->minBoundsNormal().z() / range; + fracTrans = fracTrans - ((1.0f - fracTrans) * minMult) + ((1.0f + fracTrans) * maxMult); + if (needRotate) + translation -= rotationMatrix.map(QVector3D(0.0f, 0.0f, fracTrans * item->scaling().z())); + else + translation.setZ(translation.z() - fracTrans * item->scaling().z()); + frameScaling = QVector3D(item->scaling().x() + + (item->scaling().x() * item->sliceFrameGaps().x()) + + (item->scaling().x() * item->sliceFrameWidths().x()), + item->scaling().y() + + (item->scaling().y() * item->sliceFrameGaps().y()) + + (item->scaling().y() * item->sliceFrameWidths().y()), + item->scaling().z() * item->sliceFrameThicknesses().z()); + frameWidth = QVector2D(item->scaling().x() * item->sliceFrameWidths().x(), + item->scaling().y() * item->sliceFrameWidths().y()); + } + + // If the slice is outside the shown area, don't show the frame + if (fracTrans < -1.0 || fracTrans > 1.0) + return; + + // Shader needs the width of clear space in the middle. + frameWidth.setX(1.0f - (frameWidth.x() / frameScaling.x())); + frameWidth.setY(1.0f - (frameWidth.y() / frameScaling.y())); + + QMatrix4x4 modelMatrix; + QMatrix4x4 mvpMatrix; + + modelMatrix.translate(translation); + modelMatrix.rotate(rotation); + modelMatrix.scale(frameScaling); + mvpMatrix = projectionViewMatrix * modelMatrix; + m_volumeSliceFrameShader->setUniformValue(m_volumeSliceFrameShader->MVP(), mvpMatrix); + m_volumeSliceFrameShader->setUniformValue(m_volumeSliceFrameShader->sliceFrameWidth(), + frameWidth); + + m_drawer->drawObject(m_volumeSliceFrameShader, item->mesh()); + +} + void Abstract3DRenderer::calculatePolarXZ(const QVector3D &dataPos, float &x, float &z) const { // x is angular, z is radial diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h index c8bfa7af..b31cfbd3 100644 --- a/src/datavisualization/engine/abstract3drenderer_p.h +++ b/src/datavisualization/engine/abstract3drenderer_p.h @@ -95,7 +95,9 @@ public: virtual void initVolumeTextureShaders(const QString &vertexShader, const QString &fragmentShader, const QString &fragmentLowDefShader, - const QString &sliceShader); + const QString &sliceShader, + const QString &sliceFrameVertexShader, + const QString &sliceFrameShader); virtual void updateAxisType(QAbstract3DAxis::AxisOrientation orientation, QAbstract3DAxis::AxisType type); virtual void updateAxisTitle(QAbstract3DAxis::AxisOrientation orientation, @@ -207,6 +209,8 @@ protected: void recalculateCustomItemScalingAndPos(CustomRenderItem *item); virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds) = 0; + void drawVolumeSliceFrame(const CustomRenderItem *item, Qt::Axis axis, + const QMatrix4x4 &projectionViewMatrix); bool m_hasNegativeValues; Q3DTheme *m_cachedTheme; @@ -248,6 +252,7 @@ protected: ShaderHelper *m_volumeTextureShader; ShaderHelper *m_volumeTextureLowDefShader; ShaderHelper *m_volumeTextureSliceShader; + ShaderHelper *m_volumeSliceFrameShader; bool m_useOrthoProjection; bool m_xFlipped; diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc index eeddf92e..af759ba3 100644 --- a/src/datavisualization/engine/engine.qrc +++ b/src/datavisualization/engine/engine.qrc @@ -66,5 +66,7 @@ shaders/defaultNoMatrices.vert shaders/texture3dlowdef.frag shaders/point_ES2_UV.vert + shaders/3dsliceframes.frag + shaders/colorandposition.vert diff --git a/src/datavisualization/engine/shaders/3dsliceframes.frag b/src/datavisualization/engine/shaders/3dsliceframes.frag new file mode 100644 index 00000000..44c080dc --- /dev/null +++ b/src/datavisualization/engine/shaders/3dsliceframes.frag @@ -0,0 +1,15 @@ +#version 120 + +uniform highp vec4 color_mdl; +uniform highp vec2 sliceFrameWidth; + +varying highp vec3 pos; + +void main() { + highp vec2 absPos = min(vec2(1.0, 1.0), abs(pos.xy)); + if (absPos.x > sliceFrameWidth.x || absPos.y > sliceFrameWidth.y) + gl_FragColor = color_mdl; + else + discard; +} + diff --git a/src/datavisualization/engine/shaders/colorandposition.vert b/src/datavisualization/engine/shaders/colorandposition.vert new file mode 100644 index 00000000..34849eae --- /dev/null +++ b/src/datavisualization/engine/shaders/colorandposition.vert @@ -0,0 +1,10 @@ +uniform highp mat4 MVP; + +attribute highp vec3 vertexPosition_mdl; + +varying highp vec3 pos; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + pos = vertexPosition_mdl; +} -- cgit v1.2.3