Basic heightfield conversion.

This commit is contained in:
Andrzej Kapolka 2014-10-17 15:23:54 -07:00
parent f115416a5d
commit 1e6aee1872
3 changed files with 216 additions and 42 deletions

View file

@ -2045,6 +2045,27 @@ bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& dire
return _bounds.findRayIntersection(origin, direction, distance);
}
bool Spanner::hasOwnColors() const {
return false;
}
bool Spanner::hasOwnMaterials() const {
return false;
}
QRgb Spanner::getColor(const glm::vec3& point) {
return 0;
}
int Spanner::getMaterial(const glm::vec3& point) {
return 0;
}
QVector<SharedObjectPointer>& Spanner::getMaterials() {
static QVector<SharedObjectPointer> emptyMaterials;
return emptyMaterials;
}
bool Spanner::contains(const glm::vec3& point) {
return false;
}
@ -2381,6 +2402,53 @@ Heightfield::Heightfield(const Box& bounds, float increment, const QByteArray& h
setBounds(bounds);
}
bool Heightfield::hasOwnColors() const {
return true;
}
bool Heightfield::hasOwnMaterials() const {
return true;
}
QRgb Heightfield::getColor(const glm::vec3& point) {
glm::vec3 relative = (point - getBounds().minimum) / _increment;
glm::vec3 floors = glm::floor(relative);
glm::vec3 ceils = glm::ceil(relative);
glm::vec3 fracts = glm::fract(relative);
int floorX = (int)floors.x;
int floorZ = (int)floors.z;
int ceilX = (int)ceils.x;
int ceilZ = (int)ceils.z;
const uchar* src = (const uchar*)_color.constData();
const uchar* upperLeft = src + (floorZ * _width + floorX) * DataBlock::COLOR_BYTES;
const uchar* lowerRight = src + (ceilZ * _width + ceilX) * DataBlock::COLOR_BYTES;
glm::vec3 interpolatedColor = glm::mix(glm::vec3(upperLeft[0], upperLeft[1], upperLeft[2]),
glm::vec3(lowerRight[0], lowerRight[1], lowerRight[2]), fracts.z);
// the final vertex (and thus which triangle we check) depends on which half we're on
if (fracts.x >= fracts.z) {
const uchar* upperRight = src + (floorZ * _width + ceilX) * DataBlock::COLOR_BYTES;
interpolatedColor = glm::mix(interpolatedColor, glm::mix(glm::vec3(upperRight[0], upperRight[1], upperRight[2]),
glm::vec3(lowerRight[0], lowerRight[1], lowerRight[2]), fracts.z), (fracts.x - fracts.z) / (1.0f - fracts.z));
} else {
const uchar* lowerLeft = src + (ceilZ * _width + floorX) * DataBlock::COLOR_BYTES;
interpolatedColor = glm::mix(glm::mix(glm::vec3(upperLeft[0], upperLeft[1], upperLeft[2]),
glm::vec3(lowerLeft[0], lowerLeft[1], lowerLeft[2]), fracts.z), interpolatedColor, fracts.x / fracts.z);
}
return qRgb(interpolatedColor.r, interpolatedColor.g, interpolatedColor.b);
}
int Heightfield::getMaterial(const glm::vec3& point) {
glm::vec3 relative = (point - getBounds().minimum) / _increment;
const uchar* src = (const uchar*)_material.constData();
return src[(int)glm::round(relative.z) * _width + (int)glm::round(relative.x)];
}
QVector<SharedObjectPointer>& Heightfield::getMaterials() {
return _materials;
}
bool Heightfield::contains(const glm::vec3& point) {
if (!getBounds().contains(point)) {
return false;

View file

@ -644,9 +644,24 @@ public:
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
/// Checks whether this spanner has its own colors.
virtual bool hasOwnColors() const;
/// Checks whether this spanner has its own materials.
virtual bool hasOwnMaterials() const;
/// Checks whether the spanner contains the specified point.
virtual bool contains(const glm::vec3& point);
/// Retrieves the color at the specified point.
virtual QRgb getColor(const glm::vec3& point);
/// Retrieves the material at the specified point.
virtual int getMaterial(const glm::vec3& point);
/// Retrieves a reference to the list of materials.
virtual QVector<SharedObjectPointer>& getMaterials();
/// Finds the intersection, if any, between the specified line segment and the spanner.
virtual bool intersects(const glm::vec3& start, const glm::vec3& end, float& distance, glm::vec3& normal);
@ -860,7 +875,12 @@ public:
QByteArray& getHeight() { return _height; }
QByteArray& getColor() { return _color; }
QByteArray& getMaterial() { return _material; }
QVector<SharedObjectPointer>& getMaterials() { return _materials; }
virtual bool hasOwnColors() const;
virtual bool hasOwnMaterials() const;
virtual QRgb getColor(const glm::vec3& point);
virtual int getMaterial(const glm::vec3& point);
virtual QVector<SharedObjectPointer>& getMaterials();
virtual bool contains(const glm::vec3& point);
virtual bool intersects(const glm::vec3& start, const glm::vec3& end, float& distance, glm::vec3& normal);

View file

@ -705,15 +705,31 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) {
bool flipped = (qAlpha(rgb) == 0);
float step = 1.0f / scale;
glm::vec3 position(0.0f, 0.0f, info.minimum.z + minZ * step);
for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) {
position.y = info.minimum.y + minY * step;
for (QRgb* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
destY += VOXEL_BLOCK_SAMPLES, position.y += step) {
position.x = info.minimum.x + minX * step;
for (QRgb* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x += step) {
if (_spanner->contains(position)) {
*destX = rgb;
if (_spanner->hasOwnColors()) {
for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) {
position.y = info.minimum.y + minY * step;
for (QRgb* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
destY += VOXEL_BLOCK_SAMPLES, position.y += step) {
position.x = info.minimum.x + minX * step;
for (QRgb* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x += step) {
if (_spanner->contains(position)) {
*destX = _spanner->getColor(position);
}
}
}
}
} else {
for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) {
position.y = info.minimum.y + minY * step;
for (QRgb* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
destY += VOXEL_BLOCK_SAMPLES, position.y += step) {
position.x = info.minimum.x + minX * step;
for (QRgb* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x += step) {
if (_spanner->contains(position)) {
*destX = rgb;
}
}
}
}
@ -829,18 +845,45 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) {
info.outputValues[1] = AttributeValue(info.inputValues.at(1).getAttribute(),
encodeInline<VoxelHermiteDataPointer>(newHermitePointer));
uchar materialIndex = getMaterialIndex(_material, materials, materialContents);
position.z = info.minimum.z + minZ * step;
for (uchar* destZ = (uchar*)materialContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) {
position.y = info.minimum.y + minY * step;
for (uchar* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
destY += VOXEL_BLOCK_SAMPLES, position.y += step) {
position.x = info.minimum.x + minX * step;
for (uchar* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x += step) {
if (_spanner->contains(position)) {
*destX = materialIndex;
}
if (_spanner->hasOwnMaterials()) {
QHash<int, int> materialMap;
position.z = info.minimum.z + minZ * step;
for (uchar* destZ = (uchar*)materialContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) {
position.y = info.minimum.y + minY * step;
for (uchar* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
destY += VOXEL_BLOCK_SAMPLES, position.y += step) {
position.x = info.minimum.x + minX * step;
for (uchar* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x += step) {
if (_spanner->contains(position)) {
int material = _spanner->getMaterial(position);
if (material != 0) {
int& mapping = materialMap[material];
if (mapping == 0) {
mapping = getMaterialIndex(_spanner->getMaterials().at(material - 1), materials,
materialContents);
}
material = mapping;
}
*destX = material;
}
}
}
}
} else {
uchar materialIndex = getMaterialIndex(_material, materials, materialContents);
position.z = info.minimum.z + minZ * step;
for (uchar* destZ = (uchar*)materialContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) {
position.y = info.minimum.y + minY * step;
for (uchar* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY;
destY += VOXEL_BLOCK_SAMPLES, position.y += step) {
position.x = info.minimum.x + minX * step;
for (uchar* destX = destY, *endX = destX + sizeX; destX != endX; destX++, position.x += step) {
if (_spanner->contains(position)) {
*destX = materialIndex;
}
}
}
}
}
@ -935,7 +978,7 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) {
float increment = 1.0f / heightScale;
if (!spanner) {
_spannerBounds.minimum = glm::floor(_bounds.minimum / increment) * increment;
_spannerBounds.maximum = glm::ceil(_bounds.maximum / increment) * increment;
_spannerBounds.maximum = (glm::ceil(_bounds.maximum / increment) + glm::vec3(1.0f, 0.0f, 1.0f)) * increment;
_spannerBounds.minimum.y = bounds.minimum.y;
_spannerBounds.maximum.y = bounds.maximum.y;
_heightfieldWidth = (int)glm::round((_spannerBounds.maximum.x - _spannerBounds.minimum.x) / increment) + 1;
@ -950,8 +993,8 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) {
overlap = bounds.getIntersection(_spannerBounds);
int destX = (overlap.minimum.x - _spannerBounds.minimum.x) * heightScale;
int destY = (overlap.minimum.z - _spannerBounds.minimum.z) * heightScale;
int destWidth = (int)glm::round((overlap.maximum.x - overlap.minimum.x) * heightScale) + 1;
int destHeight = (int)glm::round((overlap.maximum.z - overlap.minimum.z) * heightScale) + 1;
int destWidth = (int)glm::round((overlap.maximum.x - overlap.minimum.x) * heightScale);
int destHeight = (int)glm::round((overlap.maximum.z - overlap.minimum.z) * heightScale);
char* dest = spanner->getHeight().data() + destY * _heightfieldWidth + destX;
srcX = (overlap.minimum.x - info.minimum.x) * heightScale;
srcY = (overlap.minimum.z - info.minimum.z) * heightScale;
@ -962,14 +1005,16 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) {
}
// clear the inner area
Box innerBounds = _bounds;
Box innerBounds = _spannerBounds;
innerBounds.minimum.x += increment;
innerBounds.minimum.z += increment;
overlap = bounds.getIntersection(innerBounds);
destX = (overlap.minimum.x - info.minimum.x) * heightScale;
destY = (overlap.minimum.z - info.minimum.z) * heightScale;
destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) * heightScale);
destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) * heightScale);
innerBounds.maximum.x -= increment;
innerBounds.maximum.z -= increment;
Box innerOverlap = bounds.getIntersection(innerBounds);
destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale;
destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale;
destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale);
destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale);
dest = contents.data() + destY * size + destX;
for (int y = 0; y < destHeight; y++, dest += size) {
@ -1006,11 +1051,26 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) {
size = glm::sqrt((float)contents.size() / DataBlock::COLOR_BYTES);
heightScale = size / info.size;
int destX = (overlap.minimum.x - info.minimum.x) * heightScale;
int destY = (overlap.minimum.z - info.minimum.z) * heightScale;
int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) * heightScale);
int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) * heightScale);
char* dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES;
// copy the inner area
destX = (overlap.minimum.x - _spannerBounds.minimum.x) * heightScale;
destY = (overlap.minimum.z - _spannerBounds.minimum.z) * heightScale;
destWidth = (int)glm::round((overlap.maximum.x - overlap.minimum.x) * heightScale);
destHeight = (int)glm::round((overlap.maximum.z - overlap.minimum.z) * heightScale);
dest = spanner->getColor().data() + (destY * _heightfieldWidth + destX) * DataBlock::COLOR_BYTES;
srcX = (overlap.minimum.x - info.minimum.x) * heightScale;
srcY = (overlap.minimum.z - info.minimum.z) * heightScale;
src = contents.data() + (srcY * size + srcX) * DataBlock::COLOR_BYTES;
for (int y = 0; y < destHeight; y++, dest += _heightfieldWidth * DataBlock::COLOR_BYTES,
src += size * DataBlock::COLOR_BYTES) {
memcpy(dest, src, destWidth * DataBlock::COLOR_BYTES);
}
destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale;
destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale;
destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale);
destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale);
dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES;
for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) {
memset(dest, 0, destWidth * DataBlock::COLOR_BYTES);
@ -1023,20 +1083,46 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) {
HeightfieldMaterialDataPointer materialPointer = info.inputValues.at(2).getInlineValue<HeightfieldMaterialDataPointer>();
if (materialPointer) {
contents = materialPointer->getContents();
QVector<SharedObjectPointer> materials = materialPointer->getMaterials();
size = glm::sqrt((float)contents.size());
heightScale = size / info.size;
int destX = (overlap.minimum.x - info.minimum.x) * heightScale;
int destY = (overlap.minimum.z - info.minimum.z) * heightScale;
int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) * heightScale);
int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) * heightScale);
char* dest = contents.data() + destY * size + destX;
// copy the inner area
destX = (overlap.minimum.x - _spannerBounds.minimum.x) * heightScale;
destY = (overlap.minimum.z - _spannerBounds.minimum.z) * heightScale;
destWidth = (int)glm::round((overlap.maximum.x - overlap.minimum.x) * heightScale);
destHeight = (int)glm::round((overlap.maximum.z - overlap.minimum.z) * heightScale);
uchar* dest = (uchar*)spanner->getMaterial().data() + destY * _heightfieldWidth + destX;
srcX = (overlap.minimum.x - info.minimum.x) * heightScale;
srcY = (overlap.minimum.z - info.minimum.z) * heightScale;
uchar* src = (uchar*)contents.data() + srcY * size + srcX;
QHash<int, int> materialMap;
for (int y = 0; y < destHeight; y++, dest += _heightfieldWidth, src += size) {
for (uchar* lineSrc = src, *lineDest = dest, *end = src + destWidth; lineSrc != end; lineSrc++, lineDest++) {
int material = *lineSrc;
if (material != 0) {
int& mapping = materialMap[material];
if (mapping == 0) {
mapping = getMaterialIndex(materials.at(material - 1), spanner->getMaterials(),
spanner->getMaterial());
}
material = mapping;
}
*lineDest = material;
}
}
destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale;
destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale;
destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale);
destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale);
dest = (uchar*)contents.data() + destY * size + destX;
for (int y = 0; y < destHeight; y++, dest += size) {
memset(dest, 0, destWidth);
}
QVector<SharedObjectPointer> materials = materialPointer->getMaterials();
clearUnusedMaterials(materials, contents);
HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials));
info.outputValues[2] = AttributeValue(_outputs.at(2),