diff options
author | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-08-25 13:16:04 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-08-25 15:01:10 +0300 |
commit | 5a51d06ec8f0210f51e65abfde9f868ab7bfa8ef (patch) | |
tree | 2319880f2d66e5610d9d1040d886f52cada82ad8 /src/datavisualization | |
parent | f9bb71fd11cce59d74e78202a1117c8abb3a2e44 (diff) |
Add alpha multiplier to QCustom3DVolume api
Change-Id: I856c4166513f6d6f7b73fd52bc46d52ab1b8fdff
Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Reviewed-by: Mika Salmela <mika.salmela@digia.com>
Diffstat (limited to 'src/datavisualization')
-rw-r--r-- | src/datavisualization/data/customrenderitem.cpp | 8 | ||||
-rw-r--r-- | src/datavisualization/data/customrenderitem_p.h | 12 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3dvolume.cpp | 251 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3dvolume.h | 10 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3dvolume_p.h | 10 | ||||
-rw-r--r-- | src/datavisualization/engine/abstract3drenderer.cpp | 10 | ||||
-rw-r--r-- | src/datavisualization/engine/shaders/texture3d.frag | 14 | ||||
-rw-r--r-- | src/datavisualization/engine/shaders/texture3dslice.frag | 54 | ||||
-rw-r--r-- | src/datavisualization/utils/shaderhelper.cpp | 16 | ||||
-rw-r--r-- | src/datavisualization/utils/shaderhelper_p.h | 4 |
10 files changed, 295 insertions, 94 deletions
diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp index 3eb68845..c316fd38 100644 --- a/src/datavisualization/data/customrenderitem.cpp +++ b/src/datavisualization/data/customrenderitem.cpp @@ -36,7 +36,13 @@ CustomRenderItem::CustomRenderItem() m_textureWidth(0), m_textureHeight(0), m_textureDepth(0), - m_isVolume(false) + m_isVolume(false), + m_textureFormat(QImage::Format_ARGB32), + m_sliceIndexX(-1), + m_sliceIndexY(-1), + m_sliceIndexZ(-1), + m_alphaMultiplier(1.0f), + m_preserveOpacity(true) { } diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h index e21b6f39..5428ce43 100644 --- a/src/datavisualization/data/customrenderitem_p.h +++ b/src/datavisualization/data/customrenderitem_p.h @@ -89,9 +89,13 @@ public: inline void setSliceIndexX(int index) { m_sliceIndexX = index; } inline void setSliceIndexY(int index) { m_sliceIndexY = index; } inline void setSliceIndexZ(int index) { m_sliceIndexZ = index; } - int sliceIndexX() const { return m_sliceIndexX; } - int sliceIndexY() const { return m_sliceIndexY; } - int sliceIndexZ() const { return m_sliceIndexZ; } + inline int sliceIndexX() const { return m_sliceIndexX; } + inline int sliceIndexY() const { return m_sliceIndexY; } + inline int sliceIndexZ() const { return m_sliceIndexZ; } + inline void setAlphaMultiplier(float mult) { m_alphaMultiplier = mult; } + inline float alphaMultiplier() const { return m_alphaMultiplier; } + inline void setPreserveOpacity(bool enable) { m_preserveOpacity = enable; } + inline bool preserveOpacity() const { return m_preserveOpacity; } private: Q_DISABLE_COPY(CustomRenderItem) @@ -120,6 +124,8 @@ private: int m_sliceIndexX; int m_sliceIndexY; int m_sliceIndexZ; + float m_alphaMultiplier; + bool m_preserveOpacity; }; typedef QHash<QCustom3DItem *, CustomRenderItem *> CustomRenderItemArray; diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp index cab79ac0..c1a77dba 100644 --- a/src/datavisualization/data/qcustom3dvolume.cpp +++ b/src/datavisualization/data/qcustom3dvolume.cpp @@ -112,6 +112,30 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ /*! + * \qmlproperty real Custom3DVolume::alphaMultiplier + * + * The alpha value of every texel of the volume texture is multiplied with this value at + * the render time. This can be used to introduce uniform transparency to the volume. + * If preserveOpacity is \c{true}, only texels with at least some transparency to begin with are + * affected, and fully opaque texels are not affected. + * The value must not be negative. + * Defaults to \c{1.0}. + * + * \sa preserveOpacity + */ + +/*! + * \qmlproperty bool Custom3DVolume::preserveOpacity + * + * If this property value is \c{true}, alphaMultiplier is only applied to texels that already have + * some transparency. If it is \c{false}, the multiplier is applied to the alpha value of all + * texels. + * Defaults to \c{true}. + * + * \sa alphaMultiplier + */ + +/*! * Constructs QCustom3DVolume with given \a parent. */ QCustom3DVolume::QCustom3DVolume(QObject *parent) : @@ -578,84 +602,72 @@ QImage::Format QCustom3DVolume::textureFormat() const } /*! - * Renders the slice specified by \a index along \a axis into an image. - * The texture format of this object is used. + * \property QCustom3DVolume::alphaMultiplier * - * \return the rendered image of the slice, or a null image if invalid index is specified. + * The alpha value of every texel of the volume texture is multiplied with this value at + * the render time. This can be used to introduce uniform transparency to the volume. + * If preserveOpacity is \c{true}, only texels with at least some transparency to begin with are + * affected, and fully opaque texels are not affected. + * The value must not be negative. + * Defaults to \c{1.0f}. * - * \sa textureFormat + * \sa preserveOpacity, textureData */ -QImage QCustom3DVolume::renderSlice(Qt::Axis axis, int index) +void QCustom3DVolume::setAlphaMultiplier(float mult) { - if (index < 0) - return QImage(); - - int x; - int y; - if (axis == Qt::XAxis) { - if (index >= textureWidth()) - return QImage(); - x = textureDepth(); - y = textureHeight(); - } else if (axis == Qt::YAxis) { - if (index >= textureHeight()) - return QImage(); - x = textureWidth(); - y = textureDepth(); + if (mult >= 0.0f) { + if (dptr()->m_alphaMultiplier != mult) { + dptr()->m_alphaMultiplier = mult; + dptr()->m_dirtyBitsVolume.alphaDirty = true; + emit alphaMultiplierChanged(mult); + emit dptr()->needUpdate(); + } } else { - if (index >= textureDepth()) - return QImage(); - x = textureWidth(); - y = textureHeight(); + qWarning() << __FUNCTION__ << "Attempted to set negative multiplier."; } +} - int padding = 0; - int pixelWidth = 4; - if (textureFormat() == QImage::Format_Indexed8) { - padding = x % 4; - pixelWidth = 1; - } - QVector<uchar> data((x + padding) * y * pixelWidth); - int frameSize = textureDataWidth() * textureHeight(); +float QCustom3DVolume::alphaMultiplier() const +{ + return dptrc()->m_alphaMultiplier; +} - int dataIndex = 0; - if (axis == Qt::XAxis) { - for (int i = 0; i < y; i++) { - const uchar *p = textureData()->constData() - + (index * pixelWidth) + (textureDataWidth() * i); - for (int j = 0; j < x; j++) { - data[dataIndex++] = *p; - for (int k = 1; k < pixelWidth; k++) - data[dataIndex++] = *(p + k); - p += frameSize; - } - } - } else if (axis == Qt::YAxis) { - for (int i = 0; i < y; i++) { - const uchar *p = textureData()->constData() + (index * textureDataWidth()) - + (frameSize * i); - for (int j = 0; j < (x * pixelWidth); j++) { - data[dataIndex++] = *p; - p++; - } - } - } else { - for (int i = 0; i < y; i++) { - const uchar *p = textureData()->constData() + (index * frameSize) - + (textureDataWidth() * i); - for (int j = 0; j < (x * pixelWidth); j++) { - data[dataIndex++] = *p; - p++; - } - } +/*! + * \property QCustom3DVolume::preserveOpacity + * + * If this property value is \c{true}, alphaMultiplier is only applied to texels that already have + * some transparency. If it is \c{false}, the multiplier is applied to the alpha value of all + * texels. + * Defaults to \c{true}. + * + * \sa alphaMultiplier + */ +void QCustom3DVolume::setPreserveOpacity(bool enable) +{ + if (dptr()->m_preserveOpacity != enable) { + dptr()->m_preserveOpacity = enable; + dptr()->m_dirtyBitsVolume.alphaDirty = true; + emit preserveOpacityChanged(enable); + emit dptr()->needUpdate(); } +} - QImage image(data.constData(), x, y, x * pixelWidth, textureFormat()); - image.bits(); // Call bits() to detach the new image from local data - if (textureFormat() == QImage::Format_Indexed8) - image.setColorTable(colorTable()); +bool QCustom3DVolume::preserveOpacity() const +{ + return dptrc()->m_preserveOpacity; +} - return image; +/*! + * Renders the slice specified by \a index along \a axis into an image. + * The texture format of this object is used. + * + * \return the rendered image of the slice, or a null image if invalid index is specified. + * + * \sa textureFormat + */ +QImage QCustom3DVolume::renderSlice(Qt::Axis axis, int index) +{ + return dptr()->renderSlice(axis, index); } /*! @@ -683,7 +695,9 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q) : m_textureHeight(0), m_textureDepth(0), m_textureFormat(QImage::Format_ARGB32), - m_textureData(0) + m_textureData(0), + m_alphaMultiplier(1.0f), + m_preserveOpacity(true) { m_isVolumeItem = true; m_meshFile = QStringLiteral(":/defaultMeshes/barFull"); @@ -705,7 +719,9 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q, const QVector m_textureDepth(textureDepth), m_textureFormat(textureFormat), m_colorTable(colorTable), - m_textureData(textureData) + m_textureData(textureData), + m_alphaMultiplier(1.0f), + m_preserveOpacity(true) { m_isVolumeItem = true; m_shadowCasting = false; @@ -738,6 +754,103 @@ void QCustom3DVolumePrivate::resetDirtyBits() m_dirtyBitsVolume.textureFormatDirty = false; } +QImage QCustom3DVolumePrivate::renderSlice(Qt::Axis axis, int index) +{ + if (index < 0) + return QImage(); + + int x; + int y; + if (axis == Qt::XAxis) { + if (index >= m_textureWidth) + return QImage(); + x = m_textureDepth; + y = m_textureHeight; + } else if (axis == Qt::YAxis) { + if (index >= m_textureHeight) + return QImage(); + x = m_textureWidth; + y = m_textureDepth; + } else { + if (index >= m_textureDepth) + return QImage(); + x = m_textureWidth; + y = m_textureHeight; + } + + int padding = 0; + int pixelWidth = 4; + int dataWidth = qptr()->textureDataWidth(); + if (m_textureFormat == QImage::Format_Indexed8) { + padding = x % 4; + pixelWidth = 1; + } + QVector<uchar> data((x + padding) * y * pixelWidth); + int frameSize = qptr()->textureDataWidth() * m_textureHeight; + + int dataIndex = 0; + if (axis == Qt::XAxis) { + for (int i = 0; i < y; i++) { + const uchar *p = m_textureData->constData() + + (index * pixelWidth) + (dataWidth * i); + for (int j = 0; j < x; j++) { + for (int k = 0; k < pixelWidth; k++) + data[dataIndex++] = *(p + k); + p += frameSize; + } + } + } else if (axis == Qt::YAxis) { + for (int i = 0; i < y; i++) { + const uchar *p = m_textureData->constData() + (index * dataWidth) + + (frameSize * i); + for (int j = 0; j < (x * pixelWidth); j++) { + data[dataIndex++] = *p; + p++; + } + } + } else { + for (int i = 0; i < y; i++) { + const uchar *p = m_textureData->constData() + (index * frameSize) + (dataWidth * i); + for (int j = 0; j < (x * pixelWidth); j++) { + data[dataIndex++] = *p; + p++; + } + } + } + + if (m_textureFormat != QImage::Format_Indexed8 && m_alphaMultiplier != 1.0f) { + for (int i = pixelWidth - 1; i < data.size(); i += pixelWidth) + data[i] = static_cast<uchar>(multipliedAlphaValue(data.at(i))); + } + + QImage image(data.constData(), x, y, x * pixelWidth, m_textureFormat); + image.bits(); // Call bits() to detach the new image from local data + if (m_textureFormat == QImage::Format_Indexed8) { + QVector<QRgb> colorTable = m_colorTable; + if (m_alphaMultiplier != 1.0f) { + for (int i = 0; i < colorTable.size(); i++) { + QRgb curCol = colorTable.at(i); + int alpha = multipliedAlphaValue(qAlpha(curCol)); + if (alpha != qAlpha(curCol)) + colorTable[i] = qRgba(qRed(curCol), qGreen(curCol), qBlue(curCol), alpha); + } + } + image.setColorTable(colorTable); + } + + return image; +} + +int QCustom3DVolumePrivate::multipliedAlphaValue(int alpha) +{ + int modifiedAlpha = alpha; + if (!m_preserveOpacity || alpha != 255) { + modifiedAlpha = int(m_alphaMultiplier * float(alpha)); + modifiedAlpha = qMin(modifiedAlpha, 255); + } + return modifiedAlpha; +} + QCustom3DVolume *QCustom3DVolumePrivate::qptr() { return static_cast<QCustom3DVolume *>(q_ptr); diff --git a/src/datavisualization/data/qcustom3dvolume.h b/src/datavisualization/data/qcustom3dvolume.h index 00733d17..2f95fa5d 100644 --- a/src/datavisualization/data/qcustom3dvolume.h +++ b/src/datavisualization/data/qcustom3dvolume.h @@ -40,7 +40,8 @@ class QT_DATAVISUALIZATION_EXPORT QCustom3DVolume : public QCustom3DItem Q_PROPERTY(QVector<QRgb> colorTable READ colorTable WRITE setColorTable NOTIFY colorTableChanged) Q_PROPERTY(QVector<uchar> *textureData READ textureData WRITE setTextureData NOTIFY textureDataChanged) Q_PROPERTY(QImage::Format textureFormat READ textureFormat WRITE setTextureFormat NOTIFY textureFormatChanged) - + Q_PROPERTY(float alphaMultiplier READ alphaMultiplier WRITE setAlphaMultiplier NOTIFY alphaMultiplierChanged) + Q_PROPERTY(bool preserveOpacity READ preserveOpacity WRITE setPreserveOpacity NOTIFY preserveOpacityChanged) public: explicit QCustom3DVolume(QObject *parent = 0); @@ -80,6 +81,11 @@ public: void setTextureFormat(QImage::Format format); QImage::Format textureFormat() const; + void setAlphaMultiplier(float mult); + float alphaMultiplier() const; + void setPreserveOpacity(bool enable); + bool preserveOpacity() const; + QImage renderSlice(Qt::Axis axis, int index); signals: @@ -92,6 +98,8 @@ signals: void colorTableChanged(); void textureDataChanged(QVector<uchar> *data); void textureFormatChanged(QImage::Format format); + void alphaMultiplierChanged(float mult); + void preserveOpacityChanged(bool enabled); protected: QCustom3DVolumePrivate *dptr(); diff --git a/src/datavisualization/data/qcustom3dvolume_p.h b/src/datavisualization/data/qcustom3dvolume_p.h index 69dd1eb2..b83e27fb 100644 --- a/src/datavisualization/data/qcustom3dvolume_p.h +++ b/src/datavisualization/data/qcustom3dvolume_p.h @@ -40,13 +40,15 @@ struct QCustomVolumeDirtyBitField { bool colorTableDirty : 1; bool textureDataDirty : 1; bool textureFormatDirty : 1; + bool alphaDirty : 1; QCustomVolumeDirtyBitField() : textureDimensionsDirty(false), sliceIndicesDirty(false), colorTableDirty(false), textureDataDirty(false), - textureFormatDirty(false) + textureFormatDirty(false), + alphaDirty(false) { } }; @@ -64,6 +66,7 @@ public: virtual ~QCustom3DVolumePrivate(); void resetDirtyBits(); + QImage renderSlice(Qt::Axis axis, int index); QCustom3DVolume *qptr(); @@ -79,9 +82,14 @@ public: QVector<QRgb> m_colorTable; QVector<uchar> *m_textureData; + float m_alphaMultiplier; + bool m_preserveOpacity; + QCustomVolumeDirtyBitField m_dirtyBitsVolume; private: + int multipliedAlphaValue(int alpha); + friend class QCustom3DVolume; }; diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index 8eb1d2ce..37688beb 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -967,6 +967,8 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) newItem->setSliceIndexX(volumeItem->sliceIndexX()); newItem->setSliceIndexY(volumeItem->sliceIndexY()); newItem->setSliceIndexZ(volumeItem->sliceIndexZ()); + newItem->setAlphaMultiplier(volumeItem->alphaMultiplier()); + newItem->setPreserveOpacity(volumeItem->preserveOpacity()); #endif } newItem->setScaling(scaling); @@ -1114,6 +1116,11 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) renderItem->setSliceIndexZ(volumeItem->sliceIndexZ()); volumeItem->dptr()->m_dirtyBitsVolume.sliceIndicesDirty = false; } + if (volumeItem->dptr()->m_dirtyBitsVolume.alphaDirty) { + renderItem->setAlphaMultiplier(volumeItem->alphaMultiplier()); + renderItem->setPreserveOpacity(volumeItem->preserveOpacity()); + volumeItem->dptr()->m_dirtyBitsVolume.alphaDirty = false; + } #endif } } @@ -1292,6 +1299,9 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state, item->colorTable().constData(), 256); } shader->setUniformValue(shader->color8Bit(), color8Bit); + shader->setUniformValue(shader->alphaMultiplier(), item->alphaMultiplier()); + shader->setUniformValue(shader->preserveOpacity(), + item->preserveOpacity() ? 1 : 0); if (shader == volumeSliceShader) { QVector3D slices((float(item->sliceIndexX()) + 0.5f) / float(item->textureWidth()) * 2.0 - 1.0, diff --git a/src/datavisualization/engine/shaders/texture3d.frag b/src/datavisualization/engine/shaders/texture3d.frag index 90876596..1192ae85 100644 --- a/src/datavisualization/engine/shaders/texture3d.frag +++ b/src/datavisualization/engine/shaders/texture3d.frag @@ -8,6 +8,8 @@ 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; const highp float alphaThreshold = 0.0001; @@ -69,7 +71,7 @@ void main() { // Adjust alpha multiplier according to the step size to get uniform alpha effect // regardless of the ray angle. - highp float alphaMultiplier = stepSize / (1.0 / sampleCount); + highp float totalAlphaMultiplier = (stepSize / (1.0 / sampleCount)) * alphaMultiplier; highp vec4 curColor = vec4(0, 0, 0, 0); highp vec3 curRgb = vec3(0, 0, 0); @@ -81,10 +83,12 @@ void main() { if (color8Bit != 0) curColor = colorIndex[int(curColor.r * 255.0)]; - if (curColor.a == 1.0) + // Unless we have explicit alpha multiplier, we want to preserve opacity anyway + if (curColor.a == 1.0 && (preserveOpacity != 0 || alphaMultiplier == 1.0)) curAlpha = 1.0; else - curAlpha = clamp(curColor.a * alphaMultiplier, 0.0, 1.0); + curAlpha = clamp(curColor.a * totalAlphaMultiplier, 0.0, 1.0); + if (curAlpha > alphaThreshold) { curRgb = curColor.rgb * curAlpha * (1.0 - totalAlpha); destColor.rgb += curRgb; @@ -96,6 +100,10 @@ void main() { } } + // Brighten up the final color if there is some transparency left + if (totalAlpha > alphaThreshold && totalAlpha < 1.0) + destColor *= 1.0 / totalAlpha; + destColor.a = totalAlpha; gl_FragColor = clamp(destColor, 0.0, 1.0); } diff --git a/src/datavisualization/engine/shaders/texture3dslice.frag b/src/datavisualization/engine/shaders/texture3dslice.frag index 8870b26d..3d4c9030 100644 --- a/src/datavisualization/engine/shaders/texture3dslice.frag +++ b/src/datavisualization/engine/shaders/texture3dslice.frag @@ -7,6 +7,8 @@ uniform highp vec3 cameraPositionRelativeToModel; uniform highp vec3 volumeSliceIndices; uniform highp vec4 colorIndex[256]; uniform highp int color8Bit; +uniform highp float alphaMultiplier; +uniform highp int preserveOpacity; const highp vec3 xPlaneNormal = vec3(1.0, 0, 0); const highp vec3 yPlaneNormal = vec3(0, 1.0, 0); @@ -76,47 +78,67 @@ void main() { } highp vec4 destColor = vec4(0.0, 0.0, 0.0, 0.0); + highp vec4 curColor = vec4(0.0, 0.0, 0.0, 0.0); highp float totalAlpha = 0.0; highp vec3 curRgb = vec3(0, 0, 0); + highp float curAlpha = 0.0; // Convert intersection to texture coords if (firstD <= tFar) { highp vec3 firstTex = rayStart + rayDir * firstD; firstTex = 0.5 * (firstTex + 1.0); - highp vec4 firstColor = texture3D(textureSampler, firstTex); + curColor = texture3D(textureSampler, firstTex); if (color8Bit != 0) - firstColor = colorIndex[int(firstColor.r * 255.0)]; + curColor = colorIndex[int(curColor.r * 255.0)]; - if (firstColor.a > alphaThreshold) { - destColor.rgb = firstColor.rgb * firstColor.a; - totalAlpha = firstColor.a; + if (curColor.a > alphaThreshold) { + curAlpha = curColor.a; + if (curColor.a == 1.0 && preserveOpacity != 0) + curAlpha = 1.0; + else + curAlpha = clamp(curColor.a * alphaMultiplier, 0.0, 1.0); + destColor.rgb = curColor.rgb * curAlpha; + totalAlpha = curAlpha; } if (secondD <= tFar && totalAlpha < 1.0) { highp vec3 secondTex = rayStart + rayDir * secondD; secondTex = 0.5 * (secondTex + 1.0); - highp vec4 secondColor = texture3D(textureSampler, secondTex); + curColor = texture3D(textureSampler, secondTex); if (color8Bit != 0) - secondColor = colorIndex[int(secondColor.r * 255.0)]; - if (secondColor.a > alphaThreshold) { - curRgb = secondColor.rgb * secondColor.a * (1.0 - totalAlpha); + curColor = colorIndex[int(curColor.r * 255.0)]; + if (curColor.a > alphaThreshold) { + if (curColor.a == 1.0 && preserveOpacity != 0) + curAlpha = 1.0; + else + curAlpha = clamp(curColor.a * alphaMultiplier, 0.0, 1.0); + curRgb = curColor.rgb * curAlpha * (1.0 - totalAlpha); destColor.rgb += curRgb; - totalAlpha += secondColor.a; + totalAlpha += curAlpha; } if (thirdD <= tFar && totalAlpha < 1.0) { highp vec3 thirdTex = rayStart + rayDir * thirdD; thirdTex = 0.5 * (thirdTex + 1.0); - highp vec4 thirdColor = texture3D(textureSampler, thirdTex); - if (color8Bit != 0) - thirdColor = colorIndex[int(thirdColor.r * 255.0)]; - if (thirdColor.a > alphaThreshold) { - curRgb = thirdColor.rgb * thirdColor.a * (1.0 - totalAlpha); + curColor = texture3D(textureSampler, thirdTex); + if (curColor.a > alphaThreshold) { + if (color8Bit != 0) + curColor = colorIndex[int(curColor.r * 255.0)]; + if (curColor.a == 1.0 && preserveOpacity != 0) + curAlpha = 1.0; + else + curAlpha = clamp(curColor.a * alphaMultiplier, 0.0, 1.0); + curRgb = curColor.rgb * curAlpha * (1.0 - totalAlpha); destColor.rgb += curRgb; - totalAlpha += thirdColor.a; + totalAlpha += curAlpha; } } } } + + // Brighten up the final color if there is some transparency left + if (totalAlpha > alphaThreshold && totalAlpha < 1.0) + destColor *= 1.0 / totalAlpha; + destColor.a = totalAlpha; gl_FragColor = clamp(destColor, 0.0, 1.0); } diff --git a/src/datavisualization/utils/shaderhelper.cpp b/src/datavisualization/utils/shaderhelper.cpp index 3361638a..9d1ad0d9 100644 --- a/src/datavisualization/utils/shaderhelper.cpp +++ b/src/datavisualization/utils/shaderhelper.cpp @@ -99,6 +99,8 @@ void ShaderHelper::initialize() m_color8BitUniform = m_program->uniformLocation("color8Bit"); m_textureDimensionsUniform = m_program->uniformLocation("textureDimensions"); m_sampleCountUniform = m_program->uniformLocation("sampleCount"); + m_alphaMultiplierUniform = m_program->uniformLocation("alphaMultiplier"); + m_preserveOpacityUniform = m_program->uniformLocation("preserveOpacity"); m_initialized = true; } @@ -308,6 +310,20 @@ GLuint ShaderHelper::sampleCount() return m_sampleCountUniform; } +GLuint ShaderHelper::alphaMultiplier() +{ + if (!m_initialized) + qFatal("Shader not initialized"); + return m_alphaMultiplierUniform; +} + +GLuint ShaderHelper::preserveOpacity() +{ + if (!m_initialized) + qFatal("Shader not initialized"); + return m_preserveOpacityUniform; +} + GLuint ShaderHelper::posAtt() { if (!m_initialized) diff --git a/src/datavisualization/utils/shaderhelper_p.h b/src/datavisualization/utils/shaderhelper_p.h index bc7609bb..ac815447 100644 --- a/src/datavisualization/utils/shaderhelper_p.h +++ b/src/datavisualization/utils/shaderhelper_p.h @@ -80,6 +80,8 @@ class ShaderHelper GLuint color8Bit(); GLuint textureDimensions(); GLuint sampleCount(); + GLuint alphaMultiplier(); + GLuint preserveOpacity(); GLuint posAtt(); GLuint uvAtt(); @@ -120,6 +122,8 @@ class ShaderHelper GLuint m_color8BitUniform; GLuint m_textureDimensionsUniform; GLuint m_sampleCountUniform; + GLuint m_alphaMultiplierUniform; + GLuint m_preserveOpacityUniform; GLboolean m_initialized; }; |