summaryrefslogtreecommitdiffstats
path: root/src/datavisualization/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavisualization/engine')
-rw-r--r--src/datavisualization/engine/abstract3drenderer.cpp94
-rw-r--r--src/datavisualization/engine/abstract3drenderer_p.h3
-rw-r--r--src/datavisualization/engine/bars3drenderer.cpp52
-rw-r--r--src/datavisualization/engine/bars3drenderer_p.h1
-rw-r--r--src/datavisualization/engine/scatter3drenderer.cpp40
-rw-r--r--src/datavisualization/engine/scatter3drenderer_p.h1
-rw-r--r--src/datavisualization/engine/shaders/texture3d.frag64
-rw-r--r--src/datavisualization/engine/shaders/texture3d.vert26
-rw-r--r--src/datavisualization/engine/shaders/texture3dlowdef.frag64
-rw-r--r--src/datavisualization/engine/shaders/texture3dslice.frag97
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp40
-rw-r--r--src/datavisualization/engine/surface3drenderer_p.h1
12 files changed, 336 insertions, 147 deletions
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp
index 18384872..305d3df0 100644
--- a/src/datavisualization/engine/abstract3drenderer.cpp
+++ b/src/datavisualization/engine/abstract3drenderer.cpp
@@ -960,7 +960,7 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
newItem->setRenderer(this);
newItem->setItemPointer(item); // Store pointer for render item updates
newItem->setMesh(item->meshFile());
- newItem->setPosition(item->position());
+ newItem->setOrigPosition(item->position());
newItem->setOrigScaling(item->scaling());
newItem->setScalingAbsolute(item->isScalingAbsolute());
newItem->setPositionAbsolute(item->isPositionAbsolute());
@@ -1013,7 +1013,7 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
newItem->setUseHighDefShader(volumeItem->useHighDefShader());
#endif
}
- recalculateCustomItemScaling(newItem);
+ recalculateCustomItemScalingAndPos(newItem);
newItem->setRotation(item->rotation());
#if !defined(QT_OPENGL_ES_2)
// In OpenGL ES we simply draw volumes as regular custom item placeholders.
@@ -1025,9 +1025,6 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
}
newItem->setTexture(texture);
item->d_ptr->clearTextureImage();
- QVector3D translation = convertPositionToTranslation(newItem->position(),
- newItem->isPositionAbsolute());
- newItem->setTranslation(translation);
newItem->setVisible(item->isVisible());
newItem->setShadowCasting(item->isShadowCasting());
newItem->setFacingCamera(facingCamera);
@@ -1035,25 +1032,71 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
return newItem;
}
-void Abstract3DRenderer::recalculateCustomItemScaling(CustomRenderItem *item)
+void Abstract3DRenderer::recalculateCustomItemScalingAndPos(CustomRenderItem *item)
{
if (!m_polarGraph && !item->isLabel() && !item->isScalingAbsolute()
&& !item->isPositionAbsolute()) {
QVector3D scale = item->origScaling() / 2.0f;
- QVector3D pos = item->position();
+ QVector3D pos = item->origPosition();
QVector3D minBounds(pos.x() - scale.x(),
pos.y() - scale.y(),
- pos.z() - scale.z());
+ pos.z() + scale.z());
QVector3D maxBounds(pos.x() + scale.x(),
pos.y() + scale.y(),
- pos.z() + scale.z());
- QVector3D min = convertPositionToTranslation(minBounds, false);
- QVector3D max = convertPositionToTranslation(maxBounds, false);
- item->setScaling(QVector3D(qAbs(max.x() - min.x()), qAbs(max.y() - min.y()),
- qAbs(max.z() - min.z())) / 2.0f);
+ pos.z() - scale.z());
+ QVector3D minCorner = convertPositionToTranslation(minBounds, false);
+ QVector3D maxCorner = convertPositionToTranslation(maxBounds, false);
+ scale = QVector3D(qAbs(maxCorner.x() - minCorner.x()),
+ qAbs(maxCorner.y() - minCorner.y()),
+ qAbs(maxCorner.z() - minCorner.z())) / 2.0f;
+ if (item->isVolume()) {
+ // Only volume items need to scale and reposition according to bounds
+ QVector3D minBoundsNormal = minCorner;
+ QVector3D maxBoundsNormal = maxCorner;
+ // getVisibleItemBounds returns bounds normalized for fragment shader [-1,1]
+ // Y and Z are also flipped.
+ getVisibleItemBounds(minBoundsNormal, maxBoundsNormal);
+ item->setMinBounds(minBoundsNormal);
+ item->setMaxBounds(maxBoundsNormal);
+ // For scaling calculations, we want [0,1] normalized values
+ minBoundsNormal = item->minBoundsNormal();
+ maxBoundsNormal = item->maxBoundsNormal();
+
+ // Rescale and reposition the item so that it doesn't go over the edges
+ QVector3D adjScaling =
+ QVector3D(scale.x() * (maxBoundsNormal.x() - minBoundsNormal.x()),
+ scale.y() * (maxBoundsNormal.y() - minBoundsNormal.y()),
+ scale.z() * (maxBoundsNormal.z() - minBoundsNormal.z()));
+
+ item->setScaling(adjScaling);
+
+ QVector3D adjPos = item->origPosition();
+ QVector3D dataExtents = QVector3D(maxBounds.x() - minBounds.x(),
+ maxBounds.y() - minBounds.y(),
+ maxBounds.z() - minBounds.z()) / 2.0f;
+ adjPos.setX(adjPos.x() + (dataExtents.x() * minBoundsNormal.x())
+ - (dataExtents.x() * (1.0f - maxBoundsNormal.x())));
+ adjPos.setY(adjPos.y() + (dataExtents.y() * minBoundsNormal.y())
+ - (dataExtents.y() * (1.0f - maxBoundsNormal.y())));
+ adjPos.setZ(adjPos.z() + (dataExtents.z() * minBoundsNormal.z())
+ - (dataExtents.z() * (1.0f - maxBoundsNormal.z())));
+ item->setPosition(adjPos);
+ } else {
+ // Only scale for non-volume items, and do not readjust position
+ item->setScaling(scale);
+ item->setPosition(item->origPosition());
+ }
} else {
item->setScaling(item->origScaling());
+ item->setPosition(item->origPosition());
+ if (item->isVolume()) {
+ item->setMinBounds(-1.0f * zeroVector);
+ item->setMaxBounds(oneVector);
+ }
}
+ QVector3D translation = convertPositionToTranslation(item->position(),
+ item->isPositionAbsolute());
+ item->setTranslation(translation);
}
void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
@@ -1064,11 +1107,10 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
item->d_ptr->m_dirtyBits.meshDirty = false;
}
if (item->d_ptr->m_dirtyBits.positionDirty) {
- renderItem->setPosition(item->position());
+ renderItem->setOrigPosition(item->position());
renderItem->setPositionAbsolute(item->isPositionAbsolute());
- QVector3D translation = convertPositionToTranslation(renderItem->position(),
- renderItem->isPositionAbsolute());
- renderItem->setTranslation(translation);
+ if (!item->d_ptr->m_dirtyBits.scalingDirty)
+ recalculateCustomItemScalingAndPos(renderItem);
item->d_ptr->m_dirtyBits.positionDirty = false;
}
if (item->d_ptr->m_dirtyBits.scalingDirty) {
@@ -1099,7 +1141,7 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
item->d_ptr->clearTextureImage();
renderItem->setOrigScaling(scaling);
}
- recalculateCustomItemScaling(renderItem);
+ recalculateCustomItemScalingAndPos(renderItem);
item->d_ptr->m_dirtyBits.scalingDirty = false;
}
if (item->d_ptr->m_dirtyBits.rotationDirty) {
@@ -1195,10 +1237,7 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
void Abstract3DRenderer::updateCustomItemPositions()
{
foreach (CustomRenderItem *renderItem, m_customRenderCache) {
- recalculateCustomItemScaling(renderItem);
- QVector3D translation = convertPositionToTranslation(renderItem->position(),
- renderItem->isPositionAbsolute());
- renderItem->setTranslation(translation);
+ recalculateCustomItemScalingAndPos(renderItem);
}
}
@@ -1243,7 +1282,7 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
continue;
}
- // Check if the render item is in data coordinates and not within axis ranges, and skip drawing if it is
+ // If the render item is in data coordinates and not within axis ranges, skip it
if (!item->isPositionAbsolute()
&& (item->position().x() < m_axisCacheX.min()
|| item->position().x() > m_axisCacheX.max()
@@ -1353,9 +1392,12 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
// Set shadowless shader bindings
#if !defined(QT_OPENGL_ES_2)
if (item->isVolume()) {
- // Volume shaders repurpose light position for camera position relative to item
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);
GLint color8Bit = (item->textureFormat() == QImage::Format_Indexed8) ? 1 : 0;
if (color8Bit) {
@@ -1366,6 +1408,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
shader->setUniformValue(shader->alphaMultiplier(), item->alphaMultiplier());
shader->setUniformValue(shader->preserveOpacity(),
item->preserveOpacity() ? 1 : 0);
+
+ shader->setUniformValue(shader->minBounds(), item->minBounds());
+ shader->setUniformValue(shader->maxBounds(), item->maxBounds());
+
if (shader == m_volumeTextureSliceShader) {
QVector3D slices((float(item->sliceIndexX()) + 0.5f)
/ float(item->textureWidth()) * 2.0 - 1.0,
diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h
index 8152e0c9..c8bfa7af 100644
--- a/src/datavisualization/engine/abstract3drenderer_p.h
+++ b/src/datavisualization/engine/abstract3drenderer_p.h
@@ -205,7 +205,8 @@ protected:
virtual void fixCameraTarget(QVector3D &target) = 0;
void updateCameraViewport();
- void recalculateCustomItemScaling(CustomRenderItem *item);
+ void recalculateCustomItemScalingAndPos(CustomRenderItem *item);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds) = 0;
bool m_hasNegativeValues;
Q3DTheme *m_cachedTheme;
diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp
index 1614b563..3e83a830 100644
--- a/src/datavisualization/engine/bars3drenderer.cpp
+++ b/src/datavisualization/engine/bars3drenderer.cpp
@@ -138,6 +138,46 @@ void Bars3DRenderer::fixCameraTarget(QVector3D &target)
target.setZ(target.z() * -m_zScaleFactor);
}
+void Bars3DRenderer::getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds)
+{
+ // The inputs are the item bounds in OpenGL coordinates.
+ // The outputs limit these bounds to visible ranges, normalized to range [-1, 1]
+ // Volume shader flips the Y and Z axes, so we need to set negatives of actual values to those
+ float itemRangeX = (maxBounds.x() - minBounds.x());
+ float itemRangeY = (maxBounds.y() - minBounds.y());
+ float itemRangeZ = (maxBounds.z() - minBounds.z());
+
+ if (minBounds.x() < -m_xScaleFactor)
+ minBounds.setX(-1.0f + (2.0f * qAbs(minBounds.x() + m_xScaleFactor) / itemRangeX));
+ else
+ minBounds.setX(-1.0f);
+
+ if (minBounds.y() < -1.0f + m_backgroundAdjustment)
+ minBounds.setY(-(-1.0f + (2.0f * qAbs(minBounds.y() + 1.0f - m_backgroundAdjustment) / itemRangeY)));
+ else
+ minBounds.setY(1.0f);
+
+ if (minBounds.z() < -m_zScaleFactor)
+ minBounds.setZ(-(-1.0f + (2.0f * qAbs(minBounds.z() + m_zScaleFactor) / itemRangeZ)));
+ else
+ minBounds.setZ(1.0f);
+
+ if (maxBounds.x() > m_xScaleFactor)
+ maxBounds.setX(1.0f - (2.0f * qAbs(maxBounds.x() - m_xScaleFactor) / itemRangeX));
+ else
+ maxBounds.setX(1.0f);
+
+ if (maxBounds.y() > 1.0f + m_backgroundAdjustment)
+ maxBounds.setY(-(1.0f - (2.0f * qAbs(maxBounds.y() - 1.0f - m_backgroundAdjustment) / itemRangeY)));
+ else
+ maxBounds.setY(-1.0f);
+
+ if (maxBounds.z() > m_zScaleFactor)
+ maxBounds.setZ(-(1.0f - (2.0f * qAbs(maxBounds.z() - m_zScaleFactor) / itemRangeZ)));
+ else
+ maxBounds.setZ(-1.0f);
+}
+
void Bars3DRenderer::updateData()
{
int minRow = m_axisCacheZ.min();
@@ -1042,7 +1082,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
}
if (m_reflectionEnabled && ((m_yFlipped && item.height() > 0.0)
- || (!m_yFlipped && item.height() < 0.0))) {
+ || (!m_yFlipped && item.height() < 0.0))) {
continue;
}
@@ -1564,7 +1604,7 @@ bool Bars3DRenderer::drawBars(BarRenderItem **selectedBar,
&& (reflection == 1.0f
|| (reflection != 1.0f
&& ((m_yFlipped && item.height() < 0.0)
- || (!m_yFlipped && item.height() > 0.0)))))
+ || (!m_yFlipped && item.height() > 0.0)))))
|| !m_reflectionEnabled) {
// Skip drawing of 0-height bars and reflections of bars on the "wrong side"
// Set shader bindings
@@ -2775,10 +2815,10 @@ QVector3D Bars3DRenderer::convertPositionToTranslation(const QVector3D &position
float zTrans = 0.0f;
if (!isAbsolute) {
// Convert row and column to translation on graph
- xTrans = (((position.x() + 0.5f) * m_cachedBarSpacing.width()) - m_rowWidth)
- / m_scaleFactor;
- zTrans = (m_columnDepth - ((position.z() + 0.5f) * m_cachedBarSpacing.height()))
- / m_scaleFactor;
+ xTrans = (((position.x() - m_axisCacheX.min() + 0.5f) * m_cachedBarSpacing.width())
+ - m_rowWidth) / m_scaleFactor;
+ zTrans = (m_columnDepth - ((position.z() - m_axisCacheZ.min() + 0.5f)
+ * m_cachedBarSpacing.height())) / m_scaleFactor;
yTrans = m_axisCacheY.positionAt(position.y());
} else {
xTrans = position.x() * m_xScaleFactor;
diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h
index 44837ba2..7f1e83bb 100644
--- a/src/datavisualization/engine/bars3drenderer_p.h
+++ b/src/datavisualization/engine/bars3drenderer_p.h
@@ -120,6 +120,7 @@ public:
protected:
virtual void initializeOpenGL();
virtual void fixCameraTarget(QVector3D &target);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds);
public slots:
void updateMultiSeriesScaling(bool uniform);
diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp
index ba1019ad..34386ca6 100644
--- a/src/datavisualization/engine/scatter3drenderer.cpp
+++ b/src/datavisualization/engine/scatter3drenderer.cpp
@@ -141,6 +141,46 @@ void Scatter3DRenderer::fixCameraTarget(QVector3D &target)
target.setZ(target.z() * -m_scaleZ);
}
+void Scatter3DRenderer::getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds)
+{
+ // The inputs are the item bounds in OpenGL coordinates.
+ // The outputs limit these bounds to visible ranges, normalized to range [-1, 1]
+ // Volume shader flips the Y and Z axes, so we need to set negatives of actual values to those
+ float itemRangeX = (maxBounds.x() - minBounds.x());
+ float itemRangeY = (maxBounds.y() - minBounds.y());
+ float itemRangeZ = (maxBounds.z() - minBounds.z());
+
+ if (minBounds.x() < -m_scaleX)
+ minBounds.setX(-1.0f + (2.0f * qAbs(minBounds.x() + m_scaleX) / itemRangeX));
+ else
+ minBounds.setX(-1.0f);
+
+ if (minBounds.y() < -m_scaleY)
+ minBounds.setY(-(-1.0f + (2.0f * qAbs(minBounds.y() + m_scaleY) / itemRangeY)));
+ else
+ minBounds.setY(1.0f);
+
+ if (minBounds.z() < -m_scaleZ)
+ minBounds.setZ(-(-1.0f + (2.0f * qAbs(minBounds.z() + m_scaleZ) / itemRangeZ)));
+ else
+ minBounds.setZ(1.0f);
+
+ if (maxBounds.x() > m_scaleX)
+ maxBounds.setX(1.0f - (2.0f * qAbs(maxBounds.x() - m_scaleX) / itemRangeX));
+ else
+ maxBounds.setX(1.0f);
+
+ if (maxBounds.y() > m_scaleY)
+ maxBounds.setY(-(1.0f - (2.0f * qAbs(maxBounds.y() - m_scaleY) / itemRangeY)));
+ else
+ maxBounds.setY(-1.0f);
+
+ if (maxBounds.z() > m_scaleZ)
+ maxBounds.setZ(-(1.0f - (2.0f * qAbs(maxBounds.z() - m_scaleZ) / itemRangeZ)));
+ else
+ maxBounds.setZ(-1.0f);
+}
+
void Scatter3DRenderer::updateData()
{
calculateSceneScalingFactors();
diff --git a/src/datavisualization/engine/scatter3drenderer_p.h b/src/datavisualization/engine/scatter3drenderer_p.h
index 3fc517d0..0852f262 100644
--- a/src/datavisualization/engine/scatter3drenderer_p.h
+++ b/src/datavisualization/engine/scatter3drenderer_p.h
@@ -114,6 +114,7 @@ public slots:
protected:
virtual void initializeOpenGL();
virtual void fixCameraTarget(QVector3D &target);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds);
private:
virtual void initShaders(const QString &vertexShader, const QString &fragmentShader);
diff --git a/src/datavisualization/engine/shaders/texture3d.frag b/src/datavisualization/engine/shaders/texture3d.frag
index 460cbcc6..3f9c42ff 100644
--- a/src/datavisualization/engine/shaders/texture3d.frag
+++ b/src/datavisualization/engine/shaders/texture3d.frag
@@ -1,15 +1,17 @@
#version 120
varying highp vec3 pos;
+varying highp vec3 rayDir;
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;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
// 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
@@ -17,51 +19,38 @@ uniform highp int preserveOpacity;
const highp float alphaThicknesses = 32.0;
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;
+ highp vec3 startBounds = minBounds;
+ highp vec3 endBounds = maxBounds;
+ if (rayDir.x < 0.0) {
+ startBounds.x = maxBounds.x;
+ endBounds.x = minBounds.x;
+ }
+ if (rayDir.y > 0.0) {
+ startBounds.y = maxBounds.y;
+ endBounds.y = minBounds.y;
+ }
+ if (rayDir.z > 0.0) {
+ startBounds.z = maxBounds.z;
+ endBounds.z = minBounds.z;
}
+ // Calculate ray intersection endpoint
+ highp vec3 rayStop;
+ highp vec3 invRayDir = 1.0 / rayDir;
+ highp vec3 t = (endBounds - rayStart) * invRayDir;
+ highp float endT = min(t.x, min(t.y, t.z));
+ rayStop = rayStart + endT * rayDir;
+ if (endT <= 0.0)
+ discard;
+
// 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 vec3 absRay = abs(ray);
highp vec3 invAbsRay = 1.0 / absRay;
highp float fullDist = length(ray);
@@ -154,6 +143,9 @@ void main() {
break;
}
+ if (totalOpacity == 1.0)
+ discard;
+
// 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);
diff --git a/src/datavisualization/engine/shaders/texture3d.vert b/src/datavisualization/engine/shaders/texture3d.vert
index cad1ce06..ef3f1b25 100644
--- a/src/datavisualization/engine/shaders/texture3d.vert
+++ b/src/datavisualization/engine/shaders/texture3d.vert
@@ -1,12 +1,36 @@
uniform highp mat4 MVP;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
+uniform highp vec3 cameraPositionRelativeToModel;
attribute highp vec3 vertexPosition_mdl;
attribute highp vec2 vertexUV;
attribute highp vec3 vertexNormal_mdl;
varying highp vec3 pos;
+varying highp vec3 rayDir;
void main() {
gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
- pos = vertexPosition_mdl;
+
+ highp vec3 minBoundsNorm = minBounds;
+ highp vec3 maxBoundsNorm = maxBounds;
+
+ // Y and Z are flipped in bounds to be directly usable in texture calculations,
+ // so flip them back to normal for position calculations
+ minBoundsNorm.yz = -minBoundsNorm.yz;
+ maxBoundsNorm.yz = -maxBoundsNorm.yz;
+
+ minBoundsNorm = 0.5 * (minBoundsNorm + 1.0);
+ maxBoundsNorm = 0.5 * (maxBoundsNorm + 1.0);
+
+ pos = vertexPosition_mdl
+ + ((1.0 - vertexPosition_mdl) * minBoundsNorm)
+ - ((1.0 + vertexPosition_mdl) * (1.0 - maxBoundsNorm));
+
+ rayDir = -(cameraPositionRelativeToModel - pos);
+
+ // Flip Y and Z so QImage bits work directly for texture and first image is in the front
+ rayDir.yz = -rayDir.yz;
+ pos.yz = -pos.yz;
}
diff --git a/src/datavisualization/engine/shaders/texture3dlowdef.frag b/src/datavisualization/engine/shaders/texture3dlowdef.frag
index 72b959fc..ed0d41ce 100644
--- a/src/datavisualization/engine/shaders/texture3dlowdef.frag
+++ b/src/datavisualization/engine/shaders/texture3dlowdef.frag
@@ -1,15 +1,17 @@
#version 120
varying highp vec3 pos;
+varying highp vec3 rayDir;
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;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
// 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
@@ -18,36 +20,30 @@ 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;
+ highp vec3 startBounds = minBounds;
+ highp vec3 endBounds = maxBounds;
+ if (rayDir.x < 0.0) {
+ startBounds.x = maxBounds.x;
+ endBounds.x = minBounds.x;
+ }
+ if (rayDir.y > 0.0) {
+ startBounds.y = maxBounds.y;
+ endBounds.y = minBounds.y;
+ }
+ if (rayDir.z > 0.0) {
+ startBounds.z = maxBounds.z;
+ endBounds.z = minBounds.z;
+ }
// 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;
- }
+ highp vec3 rayStop;
+ highp vec3 invRayDir = 1.0 / rayDir;
+ highp vec3 t = (endBounds - rayStart) * invRayDir;
+ highp float endT = min(t.x, min(t.y, t.z));
+ if (endT <= 0.0)
+ discard;
+ rayStop = rayStart + endT * rayDir;
// Convert intersections to texture coords
rayStart = 0.5 * (rayStart + 1.0);
@@ -55,15 +51,6 @@ void main() {
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;
@@ -110,6 +97,9 @@ void main() {
break;
}
+ if (totalOpacity == 1.0)
+ discard;
+
// 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);
diff --git a/src/datavisualization/engine/shaders/texture3dslice.frag b/src/datavisualization/engine/shaders/texture3dslice.frag
index 00584744..c555af98 100644
--- a/src/datavisualization/engine/shaders/texture3dslice.frag
+++ b/src/datavisualization/engine/shaders/texture3dslice.frag
@@ -1,14 +1,16 @@
#version 120
varying highp vec3 pos;
+varying highp vec3 rayDir;
uniform highp sampler3D textureSampler;
-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;
+uniform highp vec3 minBounds;
+uniform highp vec3 maxBounds;
const highp vec3 xPlaneNormal = vec3(1.0, 0, 0);
const highp vec3 yPlaneNormal = vec3(0, 1.0, 0);
@@ -16,21 +18,17 @@ const highp vec3 zPlaneNormal = vec3(0, 0, 1.0);
void main() {
// Find out where ray intersects the slice planes
- highp vec3 rayDir = -(cameraPositionRelativeToModel - pos);
- rayDir = normalize(rayDir);
+ vec3 normRayDir = normalize(rayDir);
highp vec3 rayStart = pos;
- // Flip Y and Z so QImage bits work directly for texture and first image is in the front
- rayStart.yz = -rayStart.yz;
- rayDir.yz = -rayDir.yz;
highp float minT = 2.0f;
- if (rayDir.x != 0.0 && rayDir.y != 0.0 && rayDir.z != 0.0) {
+ if (normRayDir.x != 0.0 && normRayDir.y != 0.0 && normRayDir.z != 0.0) {
highp vec3 boxBounds = vec3(1.0, 1.0, 1.0);
- highp vec3 invRayDir = 1.0 / rayDir;
- if (rayDir.x < 0)
+ highp vec3 invRayDir = 1.0 / normRayDir;
+ if (normRayDir.x < 0)
boxBounds.x = -1.0;
- if (rayDir.y < 0)
+ if (normRayDir.y < 0)
boxBounds.y = -1.0;
- if (rayDir.z < 0)
+ if (normRayDir.z < 0)
boxBounds.z = -1.0;
highp vec3 t = (boxBounds - rayStart) * invRayDir;
minT = min(t.x, min(t.y, t.z));
@@ -43,12 +41,12 @@ void main() {
highp float secondD = firstD;
highp float thirdD = firstD;
if (volumeSliceIndices.x >= -1.0) {
- highp float dx = dot(xPoint - rayStart, xPlaneNormal) / dot(rayDir, xPlaneNormal);
+ highp float dx = dot(xPoint - rayStart, xPlaneNormal) / dot(normRayDir, xPlaneNormal);
if (dx >= 0.0 && dx <= minT)
firstD = min(dx, firstD);
}
if (volumeSliceIndices.y >= -1.0) {
- highp float dy = dot(yPoint - rayStart, yPlaneNormal) / dot(rayDir, yPlaneNormal);
+ highp float dy = dot(yPoint - rayStart, yPlaneNormal) / dot(normRayDir, yPlaneNormal);
if (dy >= 0.0 && dy <= minT) {
if (dy < firstD) {
secondD = firstD;
@@ -59,7 +57,7 @@ void main() {
}
}
if (volumeSliceIndices.z >= -1.0) {
- highp float dz = dot(zPoint - rayStart, zPlaneNormal) / dot(rayDir, zPlaneNormal);
+ highp float dz = dot(zPoint - rayStart, zPlaneNormal) / dot(normRayDir, zPlaneNormal);
if (dz >= 0.0) {
if (dz < firstD && dz <= minT) {
thirdD = secondD;
@@ -83,43 +81,35 @@ void main() {
// Convert intersection to texture coords
if (firstD <= minT) {
- highp vec3 firstTex = rayStart + rayDir * firstD;
- firstTex = 0.5 * (firstTex + 1.0);
- curColor = texture3D(textureSampler, firstTex);
- if (color8Bit != 0)
- curColor = colorIndex[int(curColor.r * 255.0)];
-
- if (curColor.a > 0.0) {
- 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 <= minT && totalAlpha < 1.0) {
- highp vec3 secondTex = rayStart + rayDir * secondD;
- secondTex = 0.5 * (secondTex + 1.0);
- curColor = texture3D(textureSampler, secondTex);
+ highp vec3 texelVec = rayStart + normRayDir * firstD;
+ if (clamp(texelVec.x, minBounds.x, maxBounds.x) == texelVec.x
+ && clamp(texelVec.y, maxBounds.y, minBounds.y) == texelVec.y
+ && clamp(texelVec.z, maxBounds.z, minBounds.z) == texelVec.z) {
+ texelVec = 0.5 * (texelVec + 1.0);
+ curColor = texture3D(textureSampler, texelVec);
if (color8Bit != 0)
curColor = colorIndex[int(curColor.r * 255.0)];
+
if (curColor.a > 0.0) {
+ curAlpha = curColor.a;
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 += curAlpha;
+ destColor.rgb = curColor.rgb * curAlpha;
+ totalAlpha = curAlpha;
}
- if (thirdD <= minT && totalAlpha < 1.0) {
- highp vec3 thirdTex = rayStart + rayDir * thirdD;
- thirdTex = 0.5 * (thirdTex + 1.0);
- curColor = texture3D(textureSampler, thirdTex);
+ }
+ if (secondD <= minT && totalAlpha < 1.0) {
+ texelVec = rayStart + normRayDir * secondD;
+ if (clamp(texelVec.x, minBounds.x, maxBounds.x) == texelVec.x
+ && clamp(texelVec.y, maxBounds.y, minBounds.y) == texelVec.y
+ && clamp(texelVec.z, maxBounds.z, minBounds.z) == texelVec.z) {
+ texelVec = 0.5 * (texelVec + 1.0);
+ curColor = texture3D(textureSampler, texelVec);
+ if (color8Bit != 0)
+ curColor = colorIndex[int(curColor.r * 255.0)];
if (curColor.a > 0.0) {
- if (color8Bit != 0)
- curColor = colorIndex[int(curColor.r * 255.0)];
if (curColor.a == 1.0 && preserveOpacity != 0)
curAlpha = 1.0;
else
@@ -129,9 +119,32 @@ void main() {
totalAlpha += curAlpha;
}
}
+ if (thirdD <= minT && totalAlpha < 1.0) {
+ texelVec = rayStart + normRayDir * thirdD;
+ if (clamp(texelVec.x, minBounds.x, maxBounds.x) == texelVec.x
+ && clamp(texelVec.y, maxBounds.y, minBounds.y) == texelVec.y
+ && clamp(texelVec.z, maxBounds.z, minBounds.z) == texelVec.z) {
+ texelVec = 0.5 * (texelVec + 1.0);
+ curColor = texture3D(textureSampler, texelVec);
+ if (curColor.a > 0.0) {
+ 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 += curAlpha;
+ }
+ }
+ }
}
}
+ if (totalAlpha == 0.0)
+ discard;
+
// Brighten up the final color if there is some transparency left
if (totalAlpha > 0.0 && totalAlpha < 1.0)
destColor *= 1.0 / totalAlpha;
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
index ced4c789..fb7322cc 100644
--- a/src/datavisualization/engine/surface3drenderer.cpp
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -158,6 +158,46 @@ void Surface3DRenderer::fixCameraTarget(QVector3D &target)
target.setZ(target.z() * -m_scaleZ);
}
+void Surface3DRenderer::getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds)
+{
+ // The inputs are the item bounds in OpenGL coordinates.
+ // The outputs limit these bounds to visible ranges, normalized to range [-1, 1]
+ // Volume shader flips the Y and Z axes, so we need to set negatives of actual values to those
+ float itemRangeX = (maxBounds.x() - minBounds.x());
+ float itemRangeY = (maxBounds.y() - minBounds.y());
+ float itemRangeZ = (maxBounds.z() - minBounds.z());
+
+ if (minBounds.x() < -m_scaleX)
+ minBounds.setX(-1.0f + (2.0f * qAbs(minBounds.x() + m_scaleX) / itemRangeX));
+ else
+ minBounds.setX(-1.0f);
+
+ if (minBounds.y() < -m_scaleY)
+ minBounds.setY(-(-1.0f + (2.0f * qAbs(minBounds.y() + m_scaleY) / itemRangeY)));
+ else
+ minBounds.setY(1.0f);
+
+ if (minBounds.z() < -m_scaleZ)
+ minBounds.setZ(-(-1.0f + (2.0f * qAbs(minBounds.z() + m_scaleZ) / itemRangeZ)));
+ else
+ minBounds.setZ(1.0f);
+
+ if (maxBounds.x() > m_scaleX)
+ maxBounds.setX(1.0f - (2.0f * qAbs(maxBounds.x() - m_scaleX) / itemRangeX));
+ else
+ maxBounds.setX(1.0f);
+
+ if (maxBounds.y() > m_scaleY)
+ maxBounds.setY(-(1.0f - (2.0f * qAbs(maxBounds.y() - m_scaleY) / itemRangeY)));
+ else
+ maxBounds.setY(-1.0f);
+
+ if (maxBounds.z() > m_scaleZ)
+ maxBounds.setZ(-(1.0f - (2.0f * qAbs(maxBounds.z() - m_scaleZ) / itemRangeZ)));
+ else
+ maxBounds.setZ(-1.0f);
+}
+
void Surface3DRenderer::updateData()
{
calculateSceneScalingFactors();
diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h
index 9c53757d..623951d4 100644
--- a/src/datavisualization/engine/surface3drenderer_p.h
+++ b/src/datavisualization/engine/surface3drenderer_p.h
@@ -111,6 +111,7 @@ public:
protected:
void initializeOpenGL();
virtual void fixCameraTarget(QVector3D &target);
+ virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds);
signals:
void flatShadingSupportedChanged(bool supported);