From 3c2d0623c74cc51d0c3b73e0b56b5f5052676ee4 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 1 Sep 2014 14:45:05 +0300 Subject: Add option to use low definition volume shader. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Low definition volume shader samples the texture at even intervals, so it will sometimes skip texels, causing flickering. Change-Id: Iee6cb0e8893498b89ce1a40f34701a53d100283e Reviewed-by: Tomi Korpipää --- src/datavisualization/data/customrenderitem.cpp | 3 +- src/datavisualization/data/customrenderitem_p.h | 3 + src/datavisualization/data/qcustom3dvolume.cpp | 58 +++++++++- src/datavisualization/data/qcustom3dvolume.h | 5 + src/datavisualization/data/qcustom3dvolume_p.h | 5 +- .../engine/abstract3drenderer.cpp | 67 ++++++++---- .../engine/abstract3drenderer_p.h | 3 +- src/datavisualization/engine/bars3drenderer.cpp | 8 +- src/datavisualization/engine/engine.qrc | 1 + src/datavisualization/engine/scatter3drenderer.cpp | 7 +- .../engine/shaders/texture3d.frag | 8 +- .../engine/shaders/texture3dlowdef.frag | 119 +++++++++++++++++++++ src/datavisualization/engine/surface3drenderer.cpp | 10 +- 13 files changed, 247 insertions(+), 50 deletions(-) create mode 100644 src/datavisualization/engine/shaders/texture3dlowdef.frag (limited to 'src/datavisualization') diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp index c316fd38..555f48b7 100644 --- a/src/datavisualization/data/customrenderitem.cpp +++ b/src/datavisualization/data/customrenderitem.cpp @@ -42,7 +42,8 @@ CustomRenderItem::CustomRenderItem() m_sliceIndexY(-1), m_sliceIndexZ(-1), m_alphaMultiplier(1.0f), - m_preserveOpacity(true) + m_preserveOpacity(true), + m_useHighDefShader(true) { } diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h index 5428ce43..5024270a 100644 --- a/src/datavisualization/data/customrenderitem_p.h +++ b/src/datavisualization/data/customrenderitem_p.h @@ -96,6 +96,8 @@ public: inline float alphaMultiplier() const { return m_alphaMultiplier; } inline void setPreserveOpacity(bool enable) { m_preserveOpacity = enable; } inline bool preserveOpacity() const { return m_preserveOpacity; } + inline void setUseHighDefShader(bool enable) { m_useHighDefShader = enable; } + inline bool useHighDefShader() const {return m_useHighDefShader; } private: Q_DISABLE_COPY(CustomRenderItem) @@ -126,6 +128,7 @@ private: int m_sliceIndexZ; float m_alphaMultiplier; bool m_preserveOpacity; + bool m_useHighDefShader; }; typedef QHash CustomRenderItemArray; diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp index 503d324d..789b7718 100644 --- a/src/datavisualization/data/qcustom3dvolume.cpp +++ b/src/datavisualization/data/qcustom3dvolume.cpp @@ -135,6 +135,24 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \sa alphaMultiplier */ +/*! + * \qmlproperty bool Custom3DVolume::useHighDefShader + * + * If this property value is \c{true}, a high definition shader is used to render the volume. + * If it is \c{false}, a low definition shader is used. + * + * The high definition shader guarantees that every visible texel of the volume texture is sampled + * when the volume is rendered. + * The low definition shader renders only a rough approximation of the volume contents, + * but at much higher frame rate. The low definition shader doesn't guarantee every texel of the + * volume texture is sampled, so there may be flickering if the volume contains distinct thin + * features. + * + * \note This value doesn't affect the level of detail when rendering the slices of the volume. + * + * Defaults to \c{true}. + */ + /*! * Constructs QCustom3DVolume with given \a parent. */ @@ -672,6 +690,40 @@ bool QCustom3DVolume::preserveOpacity() const return dptrc()->m_preserveOpacity; } +/*! + * \property QCustom3DVolume::useHighDefShader + * + * If this property value is \c{true}, a high definition shader is used to render the volume. + * If it is \c{false}, a low definition shader is used. + * + * The high definition shader guarantees that every visible texel of the volume texture is sampled + * when the volume is rendered. + * The low definition shader renders only a rough approximation of the volume contents, + * but at much higher frame rate. The low definition shader doesn't guarantee every texel of the + * volume texture is sampled, so there may be flickering if the volume contains distinct thin + * features. + * + * \note This value doesn't affect the level of detail when rendering the slices of the volume. + * + * Defaults to \c{true}. + * + * \sa renderSlice() + */ +void QCustom3DVolume::setUseHighDefShader(bool enable) +{ + if (dptr()->m_useHighDefShader != enable) { + dptr()->m_useHighDefShader = enable; + dptr()->m_dirtyBitsVolume.shaderDirty = true; + emit useHighDefShaderChanged(enable); + emit dptr()->needUpdate(); + } +} + +bool QCustom3DVolume::useHighDefShader() const +{ + return dptrc()->m_useHighDefShader; +} + /*! * Renders the slice specified by \a index along \a axis into an image. * The texture format of this object is used. @@ -712,7 +764,8 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q) : m_textureFormat(QImage::Format_ARGB32), m_textureData(0), m_alphaMultiplier(1.0f), - m_preserveOpacity(true) + m_preserveOpacity(true), + m_useHighDefShader(true) { m_isVolumeItem = true; m_meshFile = QStringLiteral(":/defaultMeshes/barFull"); @@ -736,7 +789,8 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q, const QVector m_colorTable(colorTable), m_textureData(textureData), m_alphaMultiplier(1.0f), - m_preserveOpacity(true) + m_preserveOpacity(true), + m_useHighDefShader(true) { m_isVolumeItem = true; m_shadowCasting = false; diff --git a/src/datavisualization/data/qcustom3dvolume.h b/src/datavisualization/data/qcustom3dvolume.h index 8627eb71..23ae07d9 100644 --- a/src/datavisualization/data/qcustom3dvolume.h +++ b/src/datavisualization/data/qcustom3dvolume.h @@ -41,6 +41,7 @@ class QT_DATAVISUALIZATION_EXPORT QCustom3DVolume : public QCustom3DItem Q_PROPERTY(QVector *textureData READ textureData WRITE setTextureData NOTIFY textureDataChanged) Q_PROPERTY(float alphaMultiplier READ alphaMultiplier WRITE setAlphaMultiplier NOTIFY alphaMultiplierChanged) Q_PROPERTY(bool preserveOpacity READ preserveOpacity WRITE setPreserveOpacity NOTIFY preserveOpacityChanged) + Q_PROPERTY(bool useHighDefShader READ useHighDefShader WRITE setUseHighDefShader NOTIFY useHighDefShaderChanged) public: @@ -86,6 +87,9 @@ public: void setPreserveOpacity(bool enable); bool preserveOpacity() const; + void setUseHighDefShader(bool enable); + bool useHighDefShader() const; + QImage renderSlice(Qt::Axis axis, int index); signals: @@ -100,6 +104,7 @@ signals: void textureFormatChanged(QImage::Format format); void alphaMultiplierChanged(float mult); void preserveOpacityChanged(bool enabled); + void useHighDefShaderChanged(bool enabled); protected: QCustom3DVolumePrivate *dptr(); diff --git a/src/datavisualization/data/qcustom3dvolume_p.h b/src/datavisualization/data/qcustom3dvolume_p.h index b83e27fb..8b0b439e 100644 --- a/src/datavisualization/data/qcustom3dvolume_p.h +++ b/src/datavisualization/data/qcustom3dvolume_p.h @@ -41,6 +41,7 @@ struct QCustomVolumeDirtyBitField { bool textureDataDirty : 1; bool textureFormatDirty : 1; bool alphaDirty : 1; + bool shaderDirty : 1; QCustomVolumeDirtyBitField() : textureDimensionsDirty(false), @@ -48,7 +49,8 @@ struct QCustomVolumeDirtyBitField { colorTableDirty(false), textureDataDirty(false), textureFormatDirty(false), - alphaDirty(false) + alphaDirty(false), + shaderDirty(false) { } }; @@ -84,6 +86,7 @@ public: float m_alphaMultiplier; bool m_preserveOpacity; + bool m_useHighDefShader; QCustomVolumeDirtyBitField m_dirtyBitsVolume; diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index 78f4b600..f031a34c 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -60,6 +60,7 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller) m_visibleSeriesCount(0), m_customItemShader(0), m_volumeTextureShader(0), + m_volumeTextureLowDefShader(0), m_volumeTextureSliceShader(0), m_useOrthoProjection(false), m_xFlipped(false), @@ -103,6 +104,7 @@ Abstract3DRenderer::~Abstract3DRenderer() delete m_selectionLabelItem; delete m_customItemShader; delete m_volumeTextureShader; + delete m_volumeTextureLowDefShader; delete m_volumeTextureSliceShader; foreach (SeriesRenderCache *cache, m_renderCacheList) { @@ -198,22 +200,27 @@ void Abstract3DRenderer::initGradientShaders(const QString &vertexShader, void Abstract3DRenderer::initCustomItemShaders(const QString &vertexShader, const QString &fragmentShader) { - if (m_customItemShader) - delete m_customItemShader; + delete m_customItemShader; m_customItemShader = new ShaderHelper(this, vertexShader, fragmentShader); m_customItemShader->initialize(); } void Abstract3DRenderer::initVolumeTextureShaders(const QString &vertexShader, const QString &fragmentShader, + const QString &fragmentLowDefShader, const QString &sliceShader) { - if (m_volumeTextureShader) - delete m_volumeTextureShader; + + delete m_volumeTextureShader; m_volumeTextureShader = new ShaderHelper(this, vertexShader, fragmentShader); m_volumeTextureShader->initialize(); - if (m_volumeTextureSliceShader) - delete m_volumeTextureSliceShader; + + delete m_volumeTextureLowDefShader; + m_volumeTextureLowDefShader = new ShaderHelper(this, vertexShader, + fragmentLowDefShader); + m_volumeTextureLowDefShader->initialize(); + + delete m_volumeTextureSliceShader; m_volumeTextureSliceShader = new ShaderHelper(this, vertexShader, sliceShader); m_volumeTextureSliceShader->initialize(); } @@ -319,6 +326,7 @@ void Abstract3DRenderer::reInitShaders() } initVolumeTextureShaders(QStringLiteral(":/shaders/vertexTexture3D"), QStringLiteral(":/shaders/fragmentTexture3D"), + QStringLiteral(":/shaders/fragmentTexture3DLowDef"), QStringLiteral(":/shaders/fragmentTexture3DSlice")); #else initGradientShaders(QStringLiteral(":/shaders/vertex"), @@ -988,6 +996,7 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) newItem->setSliceIndexZ(volumeItem->sliceIndexZ()); newItem->setAlphaMultiplier(volumeItem->alphaMultiplier()); newItem->setPreserveOpacity(volumeItem->preserveOpacity()); + newItem->setUseHighDefShader(volumeItem->useHighDefShader()); #endif } newItem->setScaling(scaling); @@ -1068,15 +1077,15 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) } } else #if !defined(QT_OPENGL_ES_2) - if (!item->d_ptr->m_isVolumeItem) + if (!item->d_ptr->m_isVolumeItem) #endif - { - renderItem->setBlendNeeded(textureImage.hasAlphaChannel()); - GLuint oldTexture = renderItem->texture(); - m_textureHelper->deleteTexture(&oldTexture); - GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true); - renderItem->setTexture(texture); - } + { + renderItem->setBlendNeeded(textureImage.hasAlphaChannel()); + GLuint oldTexture = renderItem->texture(); + m_textureHelper->deleteTexture(&oldTexture); + GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true); + renderItem->setTexture(texture); + } item->d_ptr->clearTextureImage(); item->d_ptr->m_dirtyBits.textureDirty = false; } @@ -1140,6 +1149,10 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) renderItem->setPreserveOpacity(volumeItem->preserveOpacity()); volumeItem->dptr()->m_dirtyBitsVolume.alphaDirty = false; } + if (volumeItem->dptr()->m_dirtyBitsVolume.shaderDirty) { + renderItem->setUseHighDefShader(volumeItem->useHighDefShader()); + volumeItem->dptr()->m_dirtyBitsVolume.shaderDirty = false; + } #endif } } @@ -1155,8 +1168,6 @@ void Abstract3DRenderer::updateCustomItemPositions() void Abstract3DRenderer::drawCustomItems(RenderingState state, ShaderHelper *regularShader, - ShaderHelper *volumeShader, - ShaderHelper *volumeSliceShader, const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionViewMatrix, const QMatrix4x4 &depthProjectionViewMatrix, @@ -1254,9 +1265,11 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, if (item->sliceIndexX() >= 0 || item->sliceIndexY() >= 0 || item->sliceIndexZ() >= 0) { - shader = volumeSliceShader; + shader = m_volumeTextureSliceShader; + } else if (item->useHighDefShader()) { + shader = m_volumeTextureShader; } else { - shader = volumeShader; + shader = m_volumeTextureLowDefShader; } } else { shader = regularShader; @@ -1309,7 +1322,7 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, shader->setUniformValue(shader->alphaMultiplier(), item->alphaMultiplier()); shader->setUniformValue(shader->preserveOpacity(), item->preserveOpacity() ? 1 : 0); - if (shader == volumeSliceShader) { + if (shader == m_volumeTextureSliceShader) { QVector3D slices((float(item->sliceIndexX()) + 0.5f) / float(item->textureWidth()) * 2.0 - 1.0, (float(item->sliceIndexY()) + 0.5f) @@ -1323,11 +1336,21 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, QVector3D textureDimensions(1.0f / float(item->textureWidth()), 1.0f / float(item->textureHeight()), 1.0f / float(item->textureDepth())); - shader->setUniformValue(shader->textureDimensions(), textureDimensions); // Worst case scenario sample count - int sampleCount = item->textureWidth() + item->textureHeight() - + item->textureDepth(); + int sampleCount; + if (shader == m_volumeTextureLowDefShader) { + sampleCount = qMax(item->textureWidth(), + qMax(item->textureDepth(), item->textureHeight())); + // Further improve speed with big textures by simply dropping every + // other sample: + if (sampleCount > 256) + sampleCount /= 2; + } else { + sampleCount = item->textureWidth() + item->textureHeight() + + item->textureDepth(); + } + shader->setUniformValue(shader->textureDimensions(), textureDimensions); shader->setUniformValue(shader->sampleCount(), sampleCount); } m_drawer->drawObject(shader, item->mesh(), 0, 0, item->texture()); diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h index 1e815463..83b4e1c7 100644 --- a/src/datavisualization/engine/abstract3drenderer_p.h +++ b/src/datavisualization/engine/abstract3drenderer_p.h @@ -94,6 +94,7 @@ public: const QString &fragmentShader); virtual void initVolumeTextureShaders(const QString &vertexShader, const QString &fragmentShader, + const QString &fragmentLowDefShader, const QString &sliceShader); virtual void updateAxisType(QAbstract3DAxis::AxisOrientation orientation, QAbstract3DAxis::AxisType type); @@ -146,7 +147,6 @@ public: QString &selectionLabel(); void drawCustomItems(RenderingState state, ShaderHelper *regularShader, - ShaderHelper *volumeShader, ShaderHelper *volumeSliceShader, const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionViewMatrix, const QMatrix4x4 &depthProjectionViewMatrix, @@ -243,6 +243,7 @@ protected: ShaderHelper *m_customItemShader; ShaderHelper *m_volumeTextureShader; + ShaderHelper *m_volumeTextureLowDefShader; ShaderHelper *m_volumeTextureSliceShader; bool m_useOrthoProjection; diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp index 22bf6b87..1614b563 100644 --- a/src/datavisualization/engine/bars3drenderer.cpp +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -1090,8 +1090,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) } } - Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader, - m_volumeTextureSliceShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); @@ -1179,7 +1178,6 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) } glCullFace(GL_BACK); Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader, - m_volumeTextureShader, m_volumeTextureSliceShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); @@ -1234,7 +1232,6 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) startBar, stopBar, stepBar, -1.0f); Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, - m_volumeTextureShader, m_volumeTextureSliceShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader, -1.0f); @@ -1272,8 +1269,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) drawGridLines(depthProjectionViewMatrix, projectionViewMatrix, viewMatrix); // Draw custom items - Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, m_volumeTextureShader, - m_volumeTextureSliceShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc index 88440bec..0936bc16 100644 --- a/src/datavisualization/engine/engine.qrc +++ b/src/datavisualization/engine/engine.qrc @@ -64,5 +64,6 @@ shaders/texture3dslice.frag shaders/shadowNoMatrices.vert shaders/defaultNoMatrices.vert + shaders/texture3dlowdef.frag diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp index ca983dac..8c4644c6 100644 --- a/src/datavisualization/engine/scatter3drenderer.cpp +++ b/src/datavisualization/engine/scatter3drenderer.cpp @@ -575,8 +575,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) } } - Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader, - m_volumeTextureSliceShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); @@ -681,7 +680,6 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) } Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader, - m_volumeTextureShader, m_volumeTextureSliceShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); @@ -1455,8 +1453,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) } } - Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, m_volumeTextureShader, - m_volumeTextureSliceShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); diff --git a/src/datavisualization/engine/shaders/texture3d.frag b/src/datavisualization/engine/shaders/texture3d.frag index 6dd7f78c..460cbcc6 100644 --- a/src/datavisualization/engine/shaders/texture3d.frag +++ b/src/datavisualization/engine/shaders/texture3d.frag @@ -74,9 +74,8 @@ void main() { highp vec4 destColor = vec4(0, 0, 0, 0); highp float totalOpacity = 1.0; - highp float nextOpacity = 1.0; - highp float extraAlphaMultiplier = fullDist * alphaThicknesses; + highp float extraAlphaMultiplier = fullDist * alphaThicknesses * alphaMultiplier; // nextEdges vector indicates the next edges of the texel boundaries along each axis that // the ray is about to cross. The first edges are offset by a fraction of a texel to @@ -134,11 +133,10 @@ void main() { curLen += stepSize; if (curColor.a >= 0.0) { - curAlpha = alphaMultiplier * curColor.a; - if (curAlpha >= 1.0 || (curColor.a == 1.0 && preserveOpacity == 1)) + if (curColor.a == 1.0 && (preserveOpacity == 1 || alphaMultiplier >= 1.0)) curAlpha = 1.0; else - curAlpha = curAlpha * extraAlphaMultiplier * stepSize; + curAlpha = curColor.a * extraAlphaMultiplier * stepSize; highp float nextOpacity = totalOpacity - curAlpha; // If opacity goes beyond full opacity, we need to adjust current alpha according // to the fraction of the distance the material is visible, so that we don't get diff --git a/src/datavisualization/engine/shaders/texture3dlowdef.frag b/src/datavisualization/engine/shaders/texture3dlowdef.frag new file mode 100644 index 00000000..72b959fc --- /dev/null +++ b/src/datavisualization/engine/shaders/texture3dlowdef.frag @@ -0,0 +1,119 @@ +#version 120 + +varying highp vec3 pos; + +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; + +// 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 +// entire volume, regardless of texture dimensions +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; + + // 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; + } + + // 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 float fullDist = length(ray); + highp float stepSize = SQRT3 / sampleCount; + highp vec3 step = (SQRT3 * normalize(ray)) / sampleCount; + + rayStart += (step * 0.001); + + highp vec3 curPos = rayStart; + highp float curLen = 0.0; + highp vec4 curColor = vec4(0, 0, 0, 0); + highp float curAlpha = 0.0; + highp vec3 curRgb = vec3(0, 0, 0); + highp vec4 destColor = vec4(0, 0, 0, 0); + highp float totalOpacity = 1.0; + + highp float extraAlphaMultiplier = stepSize * alphaThicknesses * alphaMultiplier; + + // Raytrace into volume, need to sample pixels along the eye ray until we hit opacity 1 + for (int i = 0; i < sampleCount; i++) { + curColor = texture3D(textureSampler, curPos); + if (color8Bit != 0) + curColor = colorIndex[int(curColor.r * 255.0)]; + + if (curColor.a >= 0.0) { + if (curColor.a == 1.0 && (preserveOpacity == 1 || alphaMultiplier >= 1.0)) + curAlpha = 1.0; + else + curAlpha = curColor.a * extraAlphaMultiplier; + highp float nextOpacity = totalOpacity - curAlpha; + // If opacity goes beyond full opacity, we need to adjust current alpha according + // to the fraction of the distance the material is visible, so that we don't get + // box artifacts around texels. + if (nextOpacity < 0.0) { + curAlpha *= totalOpacity / curAlpha; + nextOpacity = 0.0; + } + + curRgb = curColor.rgb * curAlpha * (totalOpacity + nextOpacity); + destColor.rgb += curRgb; + totalOpacity = nextOpacity; + } + curPos += step; + curLen += stepSize; + if (curLen >= fullDist || totalOpacity <= 0.0) + break; + } + + // 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); + + destColor.a = (1.0 - totalOpacity); + gl_FragColor = clamp(destColor, 0.0, 1.0); +} diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index 58f97b0a..ced4c789 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -1196,8 +1196,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); - Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader, - m_volumeTextureSliceShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); @@ -1234,8 +1233,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) glDisableVertexAttribArray(m_depthShader->posAtt()); - Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader, - m_volumeTextureSliceShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); @@ -1292,7 +1290,6 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) } m_surfaceGridShader->bind(); Abstract3DRenderer::drawCustomItems(RenderingSelection, m_surfaceGridShader, - m_volumeTextureShader, m_volumeTextureSliceShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); @@ -1864,8 +1861,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) } } - Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, m_volumeTextureShader, - m_volumeTextureSliceShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); -- cgit v1.2.3