From 08dfd28ec0a334e8442afd5e22e8bfaf5b13bf92 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 31 Dec 2014 15:53:38 -0800 Subject: [PATCH] More rendering bits. --- interface/src/MetavoxelSystem.cpp | 131 ++++++++++++++++++++++++++- libraries/metavoxels/src/Spanner.cpp | 82 ----------------- 2 files changed, 129 insertions(+), 84 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 8398128bf4..b477ed41d8 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1338,9 +1338,20 @@ class NormalIndex { public: int indices[MAX_NORMALS_PER_VERTEX]; + bool isValid() const; + int getClosestIndex(const glm::vec3& normal, QVector& vertices) const; }; +bool NormalIndex::isValid() const { + for (int i = 0; i < MAX_NORMALS_PER_VERTEX; i++) { + if (indices[i] != 0) { + return true; + } + } + return false; +} + int NormalIndex::getClosestIndex(const glm::vec3& normal, QVector& vertices) const { int firstIndex = indices[0]; int closestIndex = firstIndex; @@ -2157,6 +2168,22 @@ HeightfieldNodeRenderer::~HeightfieldNodeRenderer() { Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID)); } +class IndexVector : public QVector { +public: + + int position; + + void swap(IndexVector& other) { QVector::swap(other); qSwap(position, other.position); } + + const NormalIndex& get(int y) const; +}; + +const NormalIndex& IndexVector::get(int y) const { + static NormalIndex nullIndex = { { 0, 0, 0, 0 } }; + int relative = y - position; + return (relative >= 0 && relative < size()) ? at(relative) : nullIndex; +} + void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -2298,12 +2325,23 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g const int EDGES_PER_CUBE = 12; EdgeCrossing crossings[EDGES_PER_CUBE]; + IndexVector indicesX; + IndexVector lastIndicesX; + QVector indicesZ(stackWidth + 1); + QVector lastIndicesZ(stackWidth + 1); + for (int z = 0; z <= stackHeight; z++) { const StackArray* lineSrc = src; for (int x = 0; x <= stackWidth; x++) { if (!lineSrc->isEmpty()) { - int y = lineSrc->getPosition(); + int position = lineSrc->getPosition(); + int count = lineSrc->getEntryCount(); + int y = position; NormalIndex lastIndexY; + indicesX.position = position; + indicesX.resize(count); + indicesZ[x].position = position; + indicesZ[x].resize(count); for (const StackArray::Entry* entry = lineSrc->getEntryData(), *end = entry + lineSrc->getEntryCount(); entry != end; entry++, y++) { int clampedX = qMax(x - 1, 0), clampedZ = qMax(z - 1, 0); @@ -2579,29 +2617,118 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g // the first x, y, and z are repeated for the boundary edge; past that, we consider generating // quads for each edge that includes a transition, using indices of previously generated vertices if (x != 0 && z != 0) { + int reclampedX = qMin(clampedX, stackWidth - 1); + int reclampedZ = qMin(clampedZ, stackHeight - 1); if (alpha0 != alpha1) { + quadIndices.insert(qRgb(reclampedX, y, reclampedZ), indices.size()); + if (y > 0) { + quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ), indices.size()); + } + if (reclampedZ > 0) { + if (y > 0) { + quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ - 1), indices.size()); + } + quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size()); + } + const NormalIndex& index1 = lastIndexY; + const NormalIndex& index2 = lastIndicesZ[x].get(y - 1); + const NormalIndex& index3 = lastIndicesZ[x].get(y); + + const glm::vec3& first = vertices.at(index.indices[0]).vertex; + glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first, + vertices.at(index3.indices[0]).vertex - first); + + if (alpha0 == 0) { // quad faces negative x + indices.append(index3.getClosestIndex(normal = -normal, vertices)); + indices.append(index2.getClosestIndex(normal, vertices)); + indices.append(index1.getClosestIndex(normal, vertices)); + } else { // quad faces positive x + indices.append(index1.getClosestIndex(normal, vertices)); + indices.append(index2.getClosestIndex(normal, vertices)); + indices.append(index3.getClosestIndex(normal, vertices)); + } + indices.append(index.getClosestIndex(normal, vertices)); } if (alpha0 != alpha2) { + quadIndices.insert(qRgb(reclampedX, y, reclampedZ), indices.size()); + if (reclampedX > 0) { + quadIndices.insert(qRgb(reclampedX - 1, y, reclampedZ), indices.size()); + if (reclampedZ > 0) { + quadIndices.insert(qRgb(reclampedX - 1, y, reclampedZ - 1), indices.size()); + } + } + if (reclampedZ > 0) { + quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size()); + } + const NormalIndex& index1 = lastIndicesZ[x].get(y); + const NormalIndex& index2 = lastIndicesZ[x - 1].get(y); + const NormalIndex& index3 = lastIndicesX.get(y); + + const glm::vec3& first = vertices.at(index.indices[0]).vertex; + glm::vec3 normal = glm::cross(vertices.at(index3.indices[0]).vertex - first, + vertices.at(index1.indices[0]).vertex - first); + + if (alpha0 == 0) { // quad faces negative y + indices.append(index1.getClosestIndex(normal = -normal, vertices)); + indices.append(index2.getClosestIndex(normal, vertices)); + indices.append(index3.getClosestIndex(normal, vertices)); + } else { // quad faces positive y + indices.append(index3.getClosestIndex(normal, vertices)); + indices.append(index2.getClosestIndex(normal, vertices)); + indices.append(index1.getClosestIndex(normal, vertices)); + } + indices.append(index.getClosestIndex(normal, vertices)); } if (alpha0 != alpha4) { + quadIndices.insert(qRgb(reclampedX, y, reclampedZ), indices.size()); + if (reclampedX > 0) { + quadIndices.insert(qRgb(reclampedX - 1, y, reclampedZ), indices.size()); + if (y > 0) { + quadIndices.insert(qRgb(reclampedX - 1, y - 1, reclampedZ), indices.size()); + } + } + if (y > 0) { + quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ), indices.size()); + } + const NormalIndex& index1 = lastIndexY; + const NormalIndex& index2 = lastIndicesX.get(y - 1); + const NormalIndex& index3 = lastIndicesX.get(y); + + const glm::vec3& first = vertices.at(index.indices[0]).vertex; + glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first, + vertices.at(index3.indices[0]).vertex - first); + + if (alpha0 == 0) { // quad faces negative z + indices.append(index3.getClosestIndex(normal = -normal, vertices)); + indices.append(index2.getClosestIndex(normal, vertices)); + indices.append(index1.getClosestIndex(normal, vertices)); + } else { // quad faces positive z + indices.append(index1.getClosestIndex(normal, vertices)); + indices.append(index2.getClosestIndex(normal, vertices)); + indices.append(index3.getClosestIndex(normal, vertices)); + } + indices.append(index.getClosestIndex(normal, vertices)); } } - lastIndexY = index; + indicesX[y - position] = index; + indicesZ[x][y - position] = index; } } if (x != 0) { lineSrc++; } + indicesX.swap(lastIndicesX); } if (z != 0) { src += stackWidth; } + indicesZ.swap(lastIndicesZ); } _voxels = new VoxelBuffer(vertices, indices, hermiteSegments, quadIndices, width, node->getStack()->getMaterials()); diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index c27df63acf..e47182326c 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -2226,7 +2226,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons float startZ = glm::clamp(start.z, 0.0f, (float)highestHeightZ), endZ = glm::clamp(end.z, 0.0f, (float)highestHeightZ); glm::vec3 worldStart = glm::vec3(transform * glm::vec4(startX, start.y, startZ, 1.0f)); glm::vec3 worldStepX = glm::vec3(transform * glm::vec4(stepX, 0.0f, 0.0f, 0.0f)); - glm::vec3 worldStepY = glm::vec3(transform * glm::vec4(0.0f, start.y - end.y, 0.0f, 0.0f)); glm::vec3 worldStepZ = glm::vec3(transform * glm::vec4(0.0f, 0.0f, stepZ, 0.0f)); float voxelStep = scale.x / innerHeightWidth; float voxelScale = scale.y / (numeric_limits::max() * voxelStep); @@ -2237,7 +2236,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons int newBottom = end.y * voxelScale; QRgb rgba = color.rgba(); bool erase = (color.alpha() == 0); - uchar materialMaterialIndex = getMaterialIndex(material, newMaterialMaterials, newMaterialContents); QByteArray dummyContents; uchar stackMaterialIndex = getMaterialIndex(material, newStackMaterials, dummyContents); bool hasOwnColors = spanner->hasOwnColors(); @@ -2248,7 +2246,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons glm::vec3 worldPos = worldStart; for (float x = startX; x >= endX; x -= stepX, worldPos -= worldStepX) { quint16* heightLineDest = heightDest + (int)x; - glm::vec3 endPos = worldPos - worldStepY; float distance; glm::vec3 normal; @@ -2266,10 +2263,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons float stackX = (x - HeightfieldHeight::HEIGHT_BORDER) * innerStackWidth / innerHeightWidth; float stackZ = (z - HeightfieldHeight::HEIGHT_BORDER) * innerStackHeight / innerHeightHeight; - int topHeight = -1; - QRgb topColor = 0; - uchar topMaterial = 0; - if (stackX >= 0.0f && stackX <= innerStackWidth && stackZ >= 0.0f && stackZ <= innerStackHeight) { StackArray* stackDest = newStackContents.data() + (int)stackZ * stackWidth + (int)stackX; if (stackDest->isEmpty() && *heightLineDest != 0) { @@ -2423,24 +2416,9 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons endPruneCount++; } if (endPruneCount == stackDest->getEntryCount()) { - topHeight = 0; stackDest->clear(); } else { - int topIndex = stackDest->getEntryCount() - 1; - while (topIndex > 0 && !stackDest->getEntryData()[topIndex].isSet()) { - topIndex--; - } - StackArray::Entry* topEntry = stackDest->getEntryData() + topIndex; - if (topEntry->isSet()) { - topHeight = ((stackDest->getPosition() + topIndex) + - qAlpha(topEntry->hermiteY) / (float)numeric_limits::max()) / voxelScale; - topColor = topEntry->color; - topMaterial = topEntry->material; - - } else { - topHeight = 0; - } stackDest->removeEntries(stackDest->getEntryCount() - endPruneCount, endPruneCount); int beginningPruneCount = 0; for (int i = 0; i < stackDest->getEntryCount() - 1 && stackDest->getEntryData()[i].isMergeable( @@ -2451,66 +2429,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons stackDest->getPositionRef() += beginningPruneCount; } } - - if (topHeight != -1) { - *heightLineDest = topHeight; - if (colorDest) { - colorDest[0] = qRed(topColor); - colorDest[1] = qGreen(topColor); - colorDest[2] = qBlue(topColor); - } - if (materialDest) { - if (topMaterial != 0) { - topMaterial = getMaterialIndex(newStackMaterials.at(topMaterial - 1), - newMaterialMaterials, newMaterialContents); - } - *materialDest = topMaterial; - } - } else if (erase) { - if (spanner->intersects(endPos, worldPos, distance, normal)) { - quint16 height = glm::round(glm::mix(end.y, start.y, distance)); - if (height <= *heightLineDest) { - *heightLineDest = height; - } - } - } else if (spanner->intersects(worldPos, endPos, distance, normal)) { - quint16 height = glm::round(glm::mix(start.y, end.y, distance)); - if (height >= *heightLineDest) { - *heightLineDest = height; - - if (colorDest) { - if (hasOwnColors) { - QRgb spannerColor = spanner->getColorAt(glm::mix(endPos, worldPos, distance)); - colorDest[0] = qRed(spannerColor); - colorDest[1] = qGreen(spannerColor); - colorDest[2] = qBlue(spannerColor); - - } else { - colorDest[0] = color.red(); - colorDest[1] = color.green(); - colorDest[2] = color.blue(); - } - } - - if (materialDest) { - if (hasOwnMaterials) { - int index = spanner->getMaterialAt(glm::mix(endPos, worldPos, distance)); - if (index != 0) { - int& mapping = materialMappings[index]; - if (mapping == 0) { - mapping = getMaterialIndex(spanner->getMaterials().at(index - 1), - newMaterialMaterials, newMaterialContents); - } - index = mapping; - } - *materialDest = index; - - } else { - *materialDest = materialMaterialIndex; - } - } - } - } } } clearUnusedMaterials(newMaterialMaterials, newMaterialContents);