Stitching improvement.

This commit is contained in:
Andrzej Kapolka 2015-01-09 16:43:51 -08:00
parent dfbc3502fa
commit d002359989
2 changed files with 110 additions and 115 deletions

View file

@ -1847,34 +1847,32 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
}
NormalIndex index = { { vertices.size(), vertices.size(), vertices.size(), vertices.size() } };
if (stitch) {
// pack the corners set into a set of flags
int corners = 0;
glm::vec2 position;
int count = 0;
for (int i = 0; i < crossingCount; i++) {
const EdgeCrossing& crossing = crossings[i];
if (qAlpha(crossing.color) == 0) {
int corner = (crossing.point.x == 1.0f) | ((crossing.point.z == 1.0f) << 1);
corners |= (1 << corner);
position += glm::vec2(crossing.point.x, crossing.point.z);
count++;
}
}
// fall into four cases based on set corners
int offsetX = 0, offsetZ = 0;
switch(corners) {
case 3:
case 11: // z- edge, x+/z- corner
offsetX = 1;
break;
case 12:
case 13: // z+ edge, x-/z+ corner
offsetZ = 1;
break;
case 10:
case 14: // x+ edge, x+/z+ corner
offsetX = offsetZ = 1;
break;
position /= count;
const int CORNER_COUNT = 4;
float closestDistance = FLT_MAX;
int closestOffsetX = 0;
int closestOffsetZ = 0;
for (int i = 0; i < CORNER_COUNT; i++) {
int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0;
int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0;
float distance = glm::distance(position, glm::vec2(offsetX, offsetZ));
if (distance < closestDistance && heightLineSrc[width * offsetZ + offsetX] != 0) {
closestDistance = distance;
closestOffsetX = offsetX;
closestOffsetZ = offsetZ;
}
}
const quint16* height = heightLineSrc + width * offsetZ + offsetX;
const quint16* height = heightLineSrc + width * closestOffsetZ + closestOffsetX;
int left = height[-1];
int right = height[1];
int down = height[-width];
@ -1884,7 +1882,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
quint8 red = numeric_limits<quint8>::max();
quint8 green = numeric_limits<quint8>::max();
quint8 blue = numeric_limits<quint8>::max();
int clampedOffsetX = clampedX + offsetX, clampedOffsetZ = clampedZ + offsetZ;
int clampedOffsetX = clampedX + closestOffsetX, clampedOffsetZ = clampedZ + closestOffsetZ;
if (colorSrc) {
const uchar* color = colorSrc + ((int)(clampedOffsetZ * colorStepZ) * colorWidth +
(int)(clampedOffsetX * colorStepX)) * DataBlock::COLOR_BYTES;
@ -1905,8 +1903,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
material = mapping;
}
}
VoxelPoint point = { glm::vec3(clampedX + offsetX, *height * voxelScale,
clampedZ + offsetZ) * step, { red, green, blue },
VoxelPoint point = { glm::vec3(clampedOffsetX, *height * voxelScale, clampedOffsetZ) * step,
{ red, green, blue },
{ (char)(normal.x * numeric_limits<qint8>::max()),
(char)(normal.y * numeric_limits<qint8>::max()),
(char)(normal.z * numeric_limits<qint8>::max()) }, { material, 0, 0, 0 },

View file

@ -2827,6 +2827,93 @@ void HeightfieldNode::mergeChildren(bool height, bool colorMaterial) {
} else if (height) {
_height.reset();
}
if (colorWidth > 0 && colorMaterial) {
QByteArray colorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF);
for (int i = 0; i < CHILD_COUNT; i++) {
HeightfieldColorPointer childColor = _children[i]->getColor();
if (!childColor) {
continue;
}
int childColorWidth = childColor->getWidth();
int childColorHeight = childColor->getContents().size() / (childColorWidth * DataBlock::COLOR_BYTES);
if (childColorWidth != colorWidth || childColorHeight != colorHeight) {
qWarning() << "Color dimension mismatch [colorWidth=" << colorWidth << ", colorHeight=" << colorHeight <<
", childColorWidth=" << childColorWidth << ", childColorHeight=" << childColorHeight << "]";
continue;
}
int innerColorWidth = colorWidth - HeightfieldData::SHARED_EDGE;
int innerColorHeight = colorHeight - HeightfieldData::SHARED_EDGE;
int innerQuadrantColorWidth = innerColorWidth / 2;
int innerQuadrantColorHeight = innerColorHeight / 2;
int quadrantColorWidth = innerQuadrantColorWidth + HeightfieldData::SHARED_EDGE;
int quadrantColorHeight = innerQuadrantColorHeight + HeightfieldData::SHARED_EDGE;
char* dest = colorContents.data() + ((i & Y_MAXIMUM_FLAG ? innerQuadrantColorHeight * colorWidth : 0) +
(i & X_MAXIMUM_FLAG ? innerQuadrantColorWidth : 0)) * DataBlock::COLOR_BYTES;
const uchar* src = (const uchar*)childColor->getContents().constData();
for (int z = 0; z < quadrantColorHeight; z++, dest += colorWidth * DataBlock::COLOR_BYTES,
src += colorWidth * DataBlock::COLOR_BYTES * 2) {
const uchar* lineSrc = src;
for (char* lineDest = dest, *end = dest + quadrantColorWidth * DataBlock::COLOR_BYTES;
lineDest != end; lineDest += DataBlock::COLOR_BYTES, lineSrc += DataBlock::COLOR_BYTES * 2) {
lineDest[0] = lineSrc[0];
lineDest[1] = lineSrc[1];
lineDest[2] = lineSrc[2];
}
}
}
_color = new HeightfieldColor(colorWidth, colorContents);
} else {
_color.reset();
}
if (materialWidth > 0 && colorMaterial) {
QByteArray materialContents(materialWidth * materialHeight, 0);
QVector<SharedObjectPointer> materials;
for (int i = 0; i < CHILD_COUNT; i++) {
HeightfieldMaterialPointer childMaterial = _children[i]->getMaterial();
if (!childMaterial) {
continue;
}
int childMaterialWidth = childMaterial->getWidth();
int childMaterialHeight = childMaterial->getContents().size() / childMaterialWidth;
if (childMaterialWidth != materialWidth || childMaterialHeight != materialHeight) {
qWarning() << "Material dimension mismatch [materialWidth=" << materialWidth << ", materialHeight=" <<
materialHeight << ", childMaterialWidth=" << childMaterialWidth << ", childMaterialHeight=" <<
childMaterialHeight << "]";
continue;
}
int innerMaterialWidth = materialWidth - HeightfieldData::SHARED_EDGE;
int innerMaterialHeight = materialHeight - HeightfieldData::SHARED_EDGE;
int innerQuadrantMaterialWidth = innerMaterialWidth / 2;
int innerQuadrantMaterialHeight = innerMaterialHeight / 2;
int quadrantMaterialWidth = innerQuadrantMaterialWidth + HeightfieldData::SHARED_EDGE;
int quadrantMaterialHeight = innerQuadrantMaterialHeight + HeightfieldData::SHARED_EDGE;
uchar* dest = (uchar*)materialContents.data() +
(i & Y_MAXIMUM_FLAG ? innerQuadrantMaterialHeight * materialWidth : 0) +
(i & X_MAXIMUM_FLAG ? innerQuadrantMaterialWidth : 0);
const uchar* src = (const uchar*)childMaterial->getContents().constData();
QHash<int, int> materialMap;
for (int z = 0; z < quadrantMaterialHeight; z++, dest += materialWidth, src += materialWidth * 2) {
const uchar* lineSrc = src;
for (uchar* lineDest = dest, *end = dest + quadrantMaterialWidth; lineDest != end; lineDest++, lineSrc += 2) {
int value = *lineSrc;
if (value != 0) {
int& mapping = materialMap[value];
if (mapping == 0) {
mapping = getMaterialIndex(childMaterial->getMaterials().at(value - 1),
materials, materialContents);
}
value = mapping;
}
*lineDest = value;
}
}
}
_material = new HeightfieldMaterial(materialWidth, materialContents, materials);
} else {
_material.reset();
}
if (stackWidth > 0) {
QVector<StackArray> stackContents(stackWidth * stackHeight);
QVector<SharedObjectPointer> stackMaterials;
@ -2918,96 +3005,6 @@ void HeightfieldNode::mergeChildren(bool height, bool colorMaterial) {
} else {
_stack.reset();
}
if (!colorMaterial) {
return;
}
if (colorWidth > 0) {
QByteArray colorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF);
for (int i = 0; i < CHILD_COUNT; i++) {
HeightfieldColorPointer childColor = _children[i]->getColor();
if (!childColor) {
continue;
}
int childColorWidth = childColor->getWidth();
int childColorHeight = childColor->getContents().size() / (childColorWidth * DataBlock::COLOR_BYTES);
if (childColorWidth != colorWidth || childColorHeight != colorHeight) {
qWarning() << "Color dimension mismatch [colorWidth=" << colorWidth << ", colorHeight=" << colorHeight <<
", childColorWidth=" << childColorWidth << ", childColorHeight=" << childColorHeight << "]";
continue;
}
int innerColorWidth = colorWidth - HeightfieldData::SHARED_EDGE;
int innerColorHeight = colorHeight - HeightfieldData::SHARED_EDGE;
int innerQuadrantColorWidth = innerColorWidth / 2;
int innerQuadrantColorHeight = innerColorHeight / 2;
int quadrantColorWidth = innerQuadrantColorWidth + HeightfieldData::SHARED_EDGE;
int quadrantColorHeight = innerQuadrantColorHeight + HeightfieldData::SHARED_EDGE;
char* dest = colorContents.data() + ((i & Y_MAXIMUM_FLAG ? innerQuadrantColorHeight * colorWidth : 0) +
(i & X_MAXIMUM_FLAG ? innerQuadrantColorWidth : 0)) * DataBlock::COLOR_BYTES;
const uchar* src = (const uchar*)childColor->getContents().constData();
for (int z = 0; z < quadrantColorHeight; z++, dest += colorWidth * DataBlock::COLOR_BYTES,
src += colorWidth * DataBlock::COLOR_BYTES * 2) {
const uchar* lineSrc = src;
for (char* lineDest = dest, *end = dest + quadrantColorWidth * DataBlock::COLOR_BYTES;
lineDest != end; lineDest += DataBlock::COLOR_BYTES, lineSrc += DataBlock::COLOR_BYTES * 2) {
lineDest[0] = lineSrc[0];
lineDest[1] = lineSrc[1];
lineDest[2] = lineSrc[2];
}
}
}
_color = new HeightfieldColor(colorWidth, colorContents);
} else {
_color.reset();
}
if (materialWidth > 0) {
QByteArray materialContents(materialWidth * materialHeight, 0);
QVector<SharedObjectPointer> materials;
for (int i = 0; i < CHILD_COUNT; i++) {
HeightfieldMaterialPointer childMaterial = _children[i]->getMaterial();
if (!childMaterial) {
continue;
}
int childMaterialWidth = childMaterial->getWidth();
int childMaterialHeight = childMaterial->getContents().size() / childMaterialWidth;
if (childMaterialWidth != materialWidth || childMaterialHeight != materialHeight) {
qWarning() << "Material dimension mismatch [materialWidth=" << materialWidth << ", materialHeight=" <<
materialHeight << ", childMaterialWidth=" << childMaterialWidth << ", childMaterialHeight=" <<
childMaterialHeight << "]";
continue;
}
int innerMaterialWidth = materialWidth - HeightfieldData::SHARED_EDGE;
int innerMaterialHeight = materialHeight - HeightfieldData::SHARED_EDGE;
int innerQuadrantMaterialWidth = innerMaterialWidth / 2;
int innerQuadrantMaterialHeight = innerMaterialHeight / 2;
int quadrantMaterialWidth = innerQuadrantMaterialWidth + HeightfieldData::SHARED_EDGE;
int quadrantMaterialHeight = innerQuadrantMaterialHeight + HeightfieldData::SHARED_EDGE;
uchar* dest = (uchar*)materialContents.data() +
(i & Y_MAXIMUM_FLAG ? innerQuadrantMaterialHeight * materialWidth : 0) +
(i & X_MAXIMUM_FLAG ? innerQuadrantMaterialWidth : 0);
const uchar* src = (const uchar*)childMaterial->getContents().constData();
QHash<int, int> materialMap;
for (int z = 0; z < quadrantMaterialHeight; z++, dest += materialWidth, src += materialWidth * 2) {
const uchar* lineSrc = src;
for (uchar* lineDest = dest, *end = dest + quadrantMaterialWidth; lineDest != end; lineDest++, lineSrc += 2) {
int value = *lineSrc;
if (value != 0) {
int& mapping = materialMap[value];
if (mapping == 0) {
mapping = getMaterialIndex(childMaterial->getMaterials().at(value - 1),
materials, materialContents);
}
value = mapping;
}
*lineDest = value;
}
}
}
_material = new HeightfieldMaterial(materialWidth, materialContents, materials);
} else {
_material.reset();
}
}
QRgb HeightfieldNode::getColorAt(const glm::vec3& location) const {