summaryrefslogtreecommitdiffstats
path: root/examples/datavisualization/volumetric/volumetric.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/datavisualization/volumetric/volumetric.cpp')
-rw-r--r--examples/datavisualization/volumetric/volumetric.cpp332
1 files changed, 284 insertions, 48 deletions
diff --git a/examples/datavisualization/volumetric/volumetric.cpp b/examples/datavisualization/volumetric/volumetric.cpp
index 1de4b1b7..156e0bf4 100644
--- a/examples/datavisualization/volumetric/volumetric.cpp
+++ b/examples/datavisualization/volumetric/volumetric.cpp
@@ -34,7 +34,21 @@ const int lowDetailSize(128);
const int mediumDetailSize(256);
const int highDetailSize(512);
const int colorTableSize(256);
-const int cutOffColorIndex(15);
+const int layerDataSize(512);
+const int mineShaftDiameter(1);
+
+const int airColorIndex(254);
+const int mineShaftColorIndex(255);
+const int layerColorThickness(60);
+const int magmaColorsMin(0);
+const int magmaColorsMax(layerColorThickness);
+const int aboveWaterGroundColorsMin(magmaColorsMax + 1);
+const int aboveWaterGroundColorsMax(aboveWaterGroundColorsMin + layerColorThickness);
+const int underWaterGroundColorsMin(aboveWaterGroundColorsMax + 1);
+const int underWaterGroundColorsMax(underWaterGroundColorsMin + layerColorThickness);
+const int waterColorsMin(underWaterGroundColorsMax + 1);
+const int waterColorsMax(waterColorsMin + layerColorThickness);
+const int terrainTransparency(12);
VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
: m_graph(scatter),
@@ -49,9 +63,12 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_highDetailData(0),
m_mediumDetailIndex(0),
m_highDetailIndex(0),
+ m_mediumDetailShaftIndex(0),
+ m_highDetailShaftIndex(0),
m_sliceSliderX(0),
m_sliceSliderY(0),
m_sliceSliderZ(0),
+ m_usingPrimaryTable(true),
m_sliceLabelX(0),
m_sliceLabelY(0),
m_sliceLabelZ(0)
@@ -66,7 +83,14 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_mediumDetailData = new QVector<uchar>(mediumDetailSize * mediumDetailSize * mediumDetailSize / 2);
m_highDetailData = new QVector<uchar>(highDetailSize * highDetailSize * highDetailSize / 2);
+ initHeightMap(QStringLiteral(":/heightmaps/layer_ground.png"), m_groundLayer);
+ initHeightMap(QStringLiteral(":/heightmaps/layer_water.png"), m_waterLayer);
+ initHeightMap(QStringLiteral(":/heightmaps/layer_magma.png"), m_magmaLayer);
+
+ initMineShaftArray();
+
createVolume(lowDetailSize, 0, lowDetailSize, m_lowDetailData);
+ excavateMineShaft(lowDetailSize, 0, m_mineShaftArray.size(), m_lowDetailData);
m_volumeItem = new QCustom3DVolume;
m_volumeItem->setScaling(QVector3D(2.0f, 1.0f, 2.0f));
@@ -77,37 +101,47 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_volumeItem->setTextureData(new QVector<uchar>(*m_lowDetailData));
// Generate color tables.
- // Both tables have a fully transparent colors to fill outer portions of the volume.
-
- // The primary color table.
- // The top two layers are transparent.
m_colorTable1.resize(colorTableSize);
m_colorTable2.resize(colorTableSize);
- for (int i = 1; i < colorTableSize; i++) {
- if (i < cutOffColorIndex)
- m_colorTable1[i] = qRgba(0, 0, 0, 0);
- else if (i < 60)
- m_colorTable1[i] = qRgba((i * 2) + 120, 0, 0, 15);
- else if (i < 120)
- m_colorTable1[i] = qRgba(0, ((i - 60) * 2) + 120, 0, 50);
- else if (i < 180)
- m_colorTable1[i] = qRgba(0, 0, ((i - 120) * 2) + 120, 255);
- else
- m_colorTable1[i] = qRgba(i, i, i, 255);
+ for (int i = 0; i < colorTableSize - 2; i++) {
+ if (i < magmaColorsMax) {
+ m_colorTable1[i] = qRgba(130 - (i * 2), 0, 0, 255);
+ } else if (i < aboveWaterGroundColorsMax) {
+ m_colorTable1[i] = qRgba(0, ((i - magmaColorsMax) * 2) + 120, 0, terrainTransparency);
+ } else if (i < underWaterGroundColorsMax) {
+ m_colorTable1[i] = qRgba(((i - aboveWaterGroundColorsMax) * 2) + 30,
+ ((i - aboveWaterGroundColorsMax) * 2) + 100,
+ ((i - aboveWaterGroundColorsMax) * 2) + 30, terrainTransparency);
+ } else if (i < waterColorsMax) {
+ m_colorTable1[i] = qRgba(0, 0, ((i - underWaterGroundColorsMax) * 2) + 120,
+ terrainTransparency);
+ } else {
+ m_colorTable1[i] = qRgba(0, 0, 0, 0); // Not used
+ }
}
-
- // The alternate color table.
- // The first visible layer is a thin opaque color, and rest of the volume uses a smooth
- // transparent gradient.
- for (int i = 1; i < colorTableSize; i++) {
- if (i < cutOffColorIndex)
- m_colorTable2[i] = qRgba(0, 0, 0, 0);
- else if (i < cutOffColorIndex + 4)
- m_colorTable2[i] = qRgba(75, 150, 0, 255);
- else
- m_colorTable2[i] = qRgba(i, 0, 255 - i, i);
+ m_colorTable1[airColorIndex] = qRgba(0, 0, 0, 0);
+ m_colorTable1[mineShaftColorIndex] = qRgba(50, 50, 50, 255);
+
+ // The alternate color table just has gray gradients for all terrain except water
+ for (int i = 0; i < colorTableSize - 2; i++) {
+ if (i < magmaColorsMax) {
+ m_colorTable2[i] = qRgba(((i - aboveWaterGroundColorsMax) * 2),
+ ((i - aboveWaterGroundColorsMax) * 2),
+ ((i - aboveWaterGroundColorsMax) * 2), 255);
+ } else if (i < underWaterGroundColorsMax) {
+ m_colorTable2[i] = qRgba(((i - aboveWaterGroundColorsMax) * 2),
+ ((i - aboveWaterGroundColorsMax) * 2),
+ ((i - aboveWaterGroundColorsMax) * 2), terrainTransparency);
+ } else if (i < waterColorsMax) {
+ m_colorTable2[i] = qRgba(0, 0, ((i - underWaterGroundColorsMax) * 2) + 120,
+ terrainTransparency);
+ } else {
+ m_colorTable2[i] = qRgba(0, 0, 0, 0); // Not used
+ }
}
+ m_colorTable2[airColorIndex] = qRgba(0, 0, 0, 0);
+ m_colorTable2[mineShaftColorIndex] = qRgba(255, 255, 0, 255);
m_volumeItem->setColorTable(m_colorTable1);
@@ -246,18 +280,26 @@ void VolumetricModifier::handleFpsChange(qreal fps)
void VolumetricModifier::handleTimeout()
{
- if (m_mediumDetailIndex < mediumDetailSize) {
- m_mediumDetailIndex = createVolume(mediumDetailSize, m_mediumDetailIndex, 4,
- m_mediumDetailData);
- if (m_mediumDetailIndex == mediumDetailSize) {
+ if (!m_mediumDetailRB->isEnabled()) {
+ if (m_mediumDetailIndex != mediumDetailSize) {
+ m_mediumDetailIndex = createVolume(mediumDetailSize, m_mediumDetailIndex, 4,
+ m_mediumDetailData);
+ } else if (m_mediumDetailShaftIndex != m_mineShaftArray.size()) {
+ m_mediumDetailShaftIndex = excavateMineShaft(mediumDetailSize, m_mediumDetailShaftIndex,
+ 1, m_mediumDetailData );
+ } else {
m_mediumDetailRB->setEnabled(true);
QString label = QStringLiteral("Medium (%1x%2x%1)");
m_mediumDetailRB->setText(label.arg(mediumDetailSize).arg(mediumDetailSize / 2));
}
- } else if (m_highDetailIndex < highDetailSize) {
- m_highDetailIndex = createVolume(highDetailSize, m_highDetailIndex, 1,
- m_highDetailData);
- if (m_highDetailIndex == highDetailSize) {
+ } else if (!m_highDetailRB->isEnabled()) {
+ if (m_highDetailIndex != highDetailSize) {
+ m_highDetailIndex = createVolume(highDetailSize, m_highDetailIndex, 1,
+ m_highDetailData);
+ } else if (m_highDetailShaftIndex != m_mineShaftArray.size()) {
+ m_highDetailShaftIndex = excavateMineShaft(highDetailSize, m_highDetailShaftIndex, 1,
+ m_highDetailData);
+ } else {
m_highDetailRB->setEnabled(true);
QString label = QStringLiteral("High (%1x%2x%1)");
m_highDetailRB->setText(label.arg(highDetailSize).arg(highDetailSize / 2));
@@ -313,6 +355,11 @@ void VolumetricModifier::setSliceSliders(QSlider *sliderX, QSlider *sliderY, QSl
m_sliceSliderX = sliderX;
m_sliceSliderY = sliderY;
m_sliceSliderZ = sliderZ;
+
+ // Set sliders to interesting values
+ m_sliceSliderX->setValue(715);
+ m_sliceSliderY->setValue(612);
+ m_sliceSliderZ->setValue(715);
}
void VolumetricModifier::changeColorTable(int enabled)
@@ -322,6 +369,8 @@ void VolumetricModifier::changeColorTable(int enabled)
else
m_volumeItem->setColorTable(m_colorTable1);
+ m_usingPrimaryTable = !enabled;
+
// Rerender image labels
adjustSliceX(m_sliceSliderX->value());
adjustSliceY(m_sliceSliderY->value());
@@ -338,6 +387,25 @@ void VolumetricModifier::setPreserveOpacity(bool enabled)
adjustSliceZ(m_sliceSliderZ->value());
}
+void VolumetricModifier::setTransparentGround(bool enabled)
+{
+ int newAlpha = enabled ? terrainTransparency : 255;
+ for (int i = aboveWaterGroundColorsMin; i < underWaterGroundColorsMax; i++) {
+ QRgb oldColor1 = m_colorTable1.at(i);
+ QRgb oldColor2 = m_colorTable2.at(i);
+ m_colorTable1[i] = qRgba(qRed(oldColor1), qGreen(oldColor1), qBlue(oldColor1), newAlpha);
+ m_colorTable2[i] = qRgba(qRed(oldColor2), qGreen(oldColor2), qBlue(oldColor2), newAlpha);
+ }
+ if (m_usingPrimaryTable)
+ m_volumeItem->setColorTable(m_colorTable1);
+ else
+ m_volumeItem->setColorTable(m_colorTable2);
+
+ adjustSliceX(m_sliceSliderX->value());
+ adjustSliceY(m_sliceSliderY->value());
+ adjustSliceZ(m_sliceSliderZ->value());
+}
+
void VolumetricModifier::setUseHighDefShader(bool enabled)
{
m_volumeItem->setUseHighDefShader(enabled);
@@ -361,29 +429,65 @@ void VolumetricModifier::adjustAlphaMultiplier(int value)
adjustSliceZ(m_sliceSliderZ->value());
}
+void VolumetricModifier::initHeightMap(QString fileName, QVector<uchar> &layerData)
+{
+ QImage heightImage(fileName);
+
+ layerData.resize(layerDataSize * layerDataSize);
+ const uchar *bits = heightImage.bits();
+ int index = 0;
+ QVector<QRgb> colorTable = heightImage.colorTable();
+ for (int i = 0; i < layerDataSize; i++) {
+ for (int j = 0; j < layerDataSize; j++) {
+ layerData[index] = qRed(colorTable.at(bits[index]));
+ index++;
+ }
+ }
+}
+
int VolumetricModifier::createVolume(int textureSize, int startIndex, int count,
QVector<uchar> *textureData)
{
- // Generate example texture data for an half-ellipsoid with a section missing.
- // This can take a while if the dimensions are large, so we support incremental data generation.
-
- QVector3D midPoint(float(textureSize) / 2.0f,
- float(textureSize) / 2.0f,
- float(textureSize) / 2.0f);
-
+ // Generate volume from layer data.
int index = startIndex * textureSize * textureSize / 2.0f;
int endIndex = startIndex + count;
if (endIndex > textureSize)
endIndex = textureSize;
+ QVector<uchar> magmaHeights(textureSize);
+ QVector<uchar> waterHeights(textureSize);
+ QVector<uchar> groundHeights(textureSize);
+ float multiplier = float(layerDataSize) / float(textureSize);
for (int i = startIndex; i < endIndex; i++) {
+ // Generate layer height arrays
+ for (int l = 0; l < textureSize; l++) {
+ int layerIndex = (int(i * multiplier) * layerDataSize + int(l * multiplier));
+ magmaHeights[l] = int(m_magmaLayer.at(layerIndex));
+ waterHeights[l] = int(m_waterLayer.at(layerIndex));
+ groundHeights[l] = int(m_groundLayer.at(layerIndex));
+ }
for (int j = 0; j < textureSize / 2; j++) {
for (int k = 0; k < textureSize; k++) {
- int colorIndex = 0;
- // Take a section out of the ellipsoid
- if (i >= textureSize / 2 || j >= textureSize / 4 || k >= textureSize / 2) {
- QVector3D distVec = QVector3D(float(k), float(j * 2), float(i)) - midPoint;
- float adjLen = qMin(255.0f, (distVec.length() * 512.0f / float(textureSize)));
- colorIndex = 255 - int(adjLen);
+ int colorIndex;
+ int height((layerDataSize - (j * 2 * multiplier)) / 2);
+ if (height < magmaHeights.at(k)) {
+ // Magma layer
+ colorIndex = int((float(height) / colorTableSize)
+ * float(layerColorThickness)) + magmaColorsMin;
+ } else if (height <= groundHeights.at(k) && height <= waterHeights.at(k)) {
+ // Ground layer below water
+ colorIndex = int((float(waterHeights.at(k) - height) / colorTableSize)
+ * float(layerColorThickness)) + underWaterGroundColorsMin;
+ } else if (height <= waterHeights.at(k)) {
+ // Water layer where water goes over ground
+ colorIndex = int((float(height - magmaHeights.at(k)) / colorTableSize)
+ * float(layerColorThickness)) + waterColorsMin;
+ } else if (height <= groundHeights.at(k)) {
+ // Ground above water
+ colorIndex = int((float(height - waterHeights.at(k)) / colorTableSize)
+ * float(layerColorThickness)) + aboveWaterGroundColorsMin;
+ } else {
+ // Rest is air
+ colorIndex = airColorIndex;
}
(*textureData)[index] = colorIndex;
@@ -391,7 +495,139 @@ int VolumetricModifier::createVolume(int textureSize, int startIndex, int count,
}
}
}
+ return endIndex;
+}
+
+int VolumetricModifier::excavateMineShaft(int textureSize, int startIndex, int count,
+ QVector<uchar> *textureData)
+{
+ int endIndex = startIndex + count;
+ if (endIndex > m_mineShaftArray.size())
+ endIndex = m_mineShaftArray.size();
+ int shaftSize = mineShaftDiameter * textureSize / lowDetailSize;
+ for (int i = startIndex; i < endIndex; i++) {
+ QVector3D shaftStart(m_mineShaftArray.at(i).first);
+ QVector3D shaftEnd(m_mineShaftArray.at(i).second);
+ int shaftLen = (shaftEnd - shaftStart).length() * lowDetailSize;
+ int dataX = shaftStart.x() * textureSize - (shaftSize / 2);
+ int dataY = (shaftStart.y() * textureSize - (shaftSize / 2)) / 2;
+ int dataZ = shaftStart.z() * textureSize - (shaftSize / 2);
+ int dataIndex = dataX + (dataY * textureSize) + dataZ * (textureSize * textureSize / 2);
+ if (shaftStart.x() != shaftEnd.x()) {
+ for (int j = 0; j <= shaftLen; j++) {
+ excavateMineBlock(textureSize, dataIndex, shaftSize, textureData);
+ dataIndex += shaftSize;
+ }
+ } else if (shaftStart.y() != shaftEnd.y()) {
+ shaftLen /= 2; // Vertical shafts are half as long
+ for (int j = 0; j <= shaftLen; j++) {
+ excavateMineBlock(textureSize, dataIndex, shaftSize, textureData);
+ dataIndex += textureSize * shaftSize;
+ }
+ } else {
+ for (int j = 0; j <= shaftLen; j++) {
+ excavateMineBlock(textureSize, dataIndex, shaftSize, textureData);
+ dataIndex += (textureSize * textureSize / 2) * shaftSize;
+ }
+ }
+
+ }
return endIndex;
}
+void VolumetricModifier::excavateMineBlock(int textureSize, int dataIndex, int size,
+ QVector<uchar> *textureData)
+{
+ for (int k = 0; k < size; k++) {
+ int curIndex = dataIndex + (k * textureSize * textureSize / 2);
+ for (int l = 0; l < size; l++) {
+ curIndex = dataIndex + (k * textureSize * textureSize / 2)
+ + (l * textureSize);
+ for (int m = 0; m < size; m++) {
+ if (textureData->at(curIndex) != airColorIndex)
+ (*textureData)[curIndex] = mineShaftColorIndex;
+ curIndex++;
+ }
+
+ }
+ }
+}
+
+void VolumetricModifier::initMineShaftArray()
+{
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.1f, 0.7f),
+ QVector3D(0.7f, 0.8f, 0.7f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.7f, 0.5f),
+ QVector3D(0.7f, 0.7f, 0.7f));
+
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.4f, 0.7f, 0.7f),
+ QVector3D(0.7f, 0.7f, 0.7f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.4f, 0.7f, 0.7f),
+ QVector3D(0.4f, 0.7f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.45f, 0.7f, 0.7f),
+ QVector3D(0.45f, 0.7f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.5f, 0.7f, 0.7f),
+ QVector3D(0.5f, 0.7f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.55f, 0.7f, 0.7f),
+ QVector3D(0.55f, 0.7f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.7f),
+ QVector3D(0.6f, 0.7f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.65f, 0.7f, 0.7f),
+ QVector3D(0.65f, 0.7f, 0.8f));
+
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.5f, 0.6f, 0.7f),
+ QVector3D(0.7f, 0.6f, 0.7f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.5f, 0.6f, 0.7f),
+ QVector3D(0.5f, 0.6f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.55f, 0.6f, 0.7f),
+ QVector3D(0.55f, 0.6f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.7f),
+ QVector3D(0.6f, 0.6f, 0.8f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.65f, 0.6f, 0.7f),
+ QVector3D(0.65f, 0.6f, 0.8f));
+
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.6f, 0.4f),
+ QVector3D(0.7f, 0.6f, 0.7f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.45f),
+ QVector3D(0.8f, 0.6f, 0.45f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.5f),
+ QVector3D(0.8f, 0.6f, 0.5f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.55f),
+ QVector3D(0.8f, 0.6f, 0.55f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.6f),
+ QVector3D(0.8f, 0.6f, 0.6f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.65f),
+ QVector3D(0.8f, 0.6f, 0.65f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.7f),
+ QVector3D(0.8f, 0.6f, 0.7f));
+
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.7f, 0.4f),
+ QVector3D(0.7f, 0.7f, 0.7f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.45f),
+ QVector3D(0.8f, 0.7f, 0.45f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.5f),
+ QVector3D(0.8f, 0.7f, 0.5f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.55f),
+ QVector3D(0.8f, 0.7f, 0.55f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.6f),
+ QVector3D(0.8f, 0.7f, 0.6f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.65f),
+ QVector3D(0.8f, 0.7f, 0.65f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.7f),
+ QVector3D(0.8f, 0.7f, 0.7f));
+
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.8f, 0.5f),
+ QVector3D(0.7f, 0.8f, 0.7f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.55f),
+ QVector3D(0.8f, 0.8f, 0.55f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.6f),
+ QVector3D(0.8f, 0.8f, 0.6f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.65f),
+ QVector3D(0.8f, 0.8f, 0.65f));
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.7f),
+ QVector3D(0.8f, 0.8f, 0.7f));
+
+ m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.1f, 0.4f),
+ QVector3D(0.7f, 0.7f, 0.4f));
+}