When we set heightfield layers, break it up into quadtree.

This commit is contained in:
Andrzej Kapolka 2014-11-25 15:32:02 -08:00
parent fc16207c08
commit a987e7ce10
2 changed files with 109 additions and 5 deletions

View file

@ -1145,6 +1145,94 @@ HeightfieldNode::HeightfieldNode(const HeightfieldHeightPointer& height, const H
_material(material) {
}
const int HEIGHT_LEAF_SIZE = 256 + HeightfieldHeight::HEIGHT_EXTENSION;
void HeightfieldNode::setContents(const HeightfieldHeightPointer& height, const HeightfieldColorPointer& color,
const HeightfieldMaterialPointer& material) {
clearChildren();
int heightWidth = height->getWidth();
if (heightWidth <= HEIGHT_LEAF_SIZE) {
_height = height;
_color = color;
_material = material;
return;
}
int heightHeight = height->getContents().size() / heightWidth;
int innerChildHeightWidth = (heightWidth - HeightfieldHeight::HEIGHT_EXTENSION) / 2;
int innerChildHeightHeight = (heightHeight - HeightfieldHeight::HEIGHT_EXTENSION) / 2;
int childHeightWidth = innerChildHeightWidth + HeightfieldHeight::HEIGHT_EXTENSION;
int childHeightHeight = innerChildHeightHeight + HeightfieldHeight::HEIGHT_EXTENSION;
for (int i = 0; i < CHILD_COUNT; i++) {
QVector<quint16> childHeightContents(childHeightWidth * childHeightHeight);
quint16* heightDest = childHeightContents.data();
bool maximumX = (i & X_MAXIMUM_FLAG), maximumY = (i & Y_MAXIMUM_FLAG);
const quint16* heightSrc = height->getContents().constData() + (maximumY ? innerChildHeightHeight * heightWidth : 0) +
(maximumX ? innerChildHeightWidth : 0);
for (int z = 0; z < childHeightHeight; z++, heightDest += childHeightWidth, heightSrc += heightWidth) {
memcpy(heightDest, heightSrc, childHeightWidth * sizeof(quint16));
}
HeightfieldColorPointer childColor;
if (color) {
int colorWidth = color->getWidth();
int colorHeight = color->getContents().size() / (colorWidth * DataBlock::COLOR_BYTES);
int innerChildColorWidth = (colorWidth - HeightfieldData::SHARED_EDGE) / 2;
int innerChildColorHeight = (colorHeight - HeightfieldData::SHARED_EDGE) / 2;
int childColorWidth = innerChildColorWidth + HeightfieldData::SHARED_EDGE;
int childColorHeight = innerChildColorHeight + HeightfieldData::SHARED_EDGE;
QByteArray childColorContents(childColorWidth * childColorHeight * DataBlock::COLOR_BYTES, 0);
char* dest = childColorContents.data();
const char* src = color->getContents().constData() + ((maximumY ? innerChildColorHeight * colorWidth : 0) +
(maximumX ? innerChildColorWidth : 0)) * DataBlock::COLOR_BYTES;
for (int z = 0; z < childColorHeight; z++, dest += childColorWidth * DataBlock::COLOR_BYTES,
src += colorWidth * DataBlock::COLOR_BYTES) {
memcpy(dest, src, childColorWidth * DataBlock::COLOR_BYTES);
}
childColor = new HeightfieldColor(childColorWidth, childColorContents);
}
HeightfieldMaterialPointer childMaterial;
if (material) {
int materialWidth = material->getWidth();
int materialHeight = material->getContents().size() / materialWidth;
int innerChildMaterialWidth = (materialWidth - HeightfieldData::SHARED_EDGE) / 2;
int innerChildMaterialHeight = (materialHeight - HeightfieldData::SHARED_EDGE) / 2;
int childMaterialWidth = innerChildMaterialWidth + HeightfieldData::SHARED_EDGE;
int childMaterialHeight = innerChildMaterialHeight + HeightfieldData::SHARED_EDGE;
QByteArray childMaterialContents(childMaterialWidth * childMaterialHeight, 0);
QVector<SharedObjectPointer> childMaterials;
uchar* dest = (uchar*)childMaterialContents.data();
const uchar* src = (const uchar*)material->getContents().data() +
(maximumY ? innerChildMaterialHeight * materialWidth : 0) + (maximumX ? innerChildMaterialWidth : 0);
QHash<int, int> materialMap;
for (int z = 0; z < childMaterialHeight; z++, dest += childMaterialWidth, src += materialWidth) {
const uchar* lineSrc = src;
for (uchar* lineDest = dest, *end = dest + childMaterialWidth; lineDest != end; lineDest++, lineSrc++) {
int value = *lineSrc;
if (value != 0) {
int& mapping = materialMap[value];
if (mapping == 0) {
childMaterials.append(material->getMaterials().at(value - 1));
mapping = childMaterials.size();
}
value = mapping;
}
*lineDest = value;
}
}
childMaterial = new HeightfieldMaterial(childMaterialWidth, childMaterialContents, childMaterials);
}
_children[i] = new HeightfieldNode();
_children[i]->setContents(HeightfieldHeightPointer(new HeightfieldHeight(childHeightWidth, childHeightContents)),
childColor, childMaterial);
}
mergeChildren();
}
bool HeightfieldNode::isLeaf() const {
for (int i = 0; i < CHILD_COUNT; i++) {
if (_children[i]) {
@ -1406,8 +1494,7 @@ void HeightfieldNode::mergeChildren() {
Heightfield::Heightfield() :
_aspectY(1.0f),
_aspectZ(1.0f),
_root(new HeightfieldNode()) {
_aspectZ(1.0f) {
connect(this, &Heightfield::translationChanged, this, &Heightfield::updateBounds);
connect(this, &Heightfield::rotationChanged, this, &Heightfield::updateBounds);
@ -1415,6 +1502,11 @@ Heightfield::Heightfield() :
connect(this, &Heightfield::aspectYChanged, this, &Heightfield::updateBounds);
connect(this, &Heightfield::aspectZChanged, this, &Heightfield::updateBounds);
updateBounds();
connect(this, &Heightfield::heightChanged, this, &Heightfield::updateRoot);
connect(this, &Heightfield::colorChanged, this, &Heightfield::updateRoot);
connect(this, &Heightfield::materialChanged, this, &Heightfield::updateRoot);
updateRoot();
}
void Heightfield::setAspectY(float aspectY) {
@ -2486,6 +2578,13 @@ void Heightfield::updateBounds() {
setBounds(glm::translate(getTranslation()) * rotationMatrix * Box(glm::vec3(), extent));
}
void Heightfield::updateRoot() {
_root = new HeightfieldNode();
if (_height) {
_root->setContents(_height, _color, _material);
}
}
MetavoxelLOD Heightfield::transformLOD(const MetavoxelLOD& lod) const {
// after transforming into unit space, we scale the threshold in proportion to vertical distance
glm::vec3 inverseScale(1.0f / getScale(), 1.0f / (getScale() * _aspectY), 1.0f / (getScale() * _aspectZ));

View file

@ -494,6 +494,9 @@ public:
const HeightfieldColorPointer& color = HeightfieldColorPointer(),
const HeightfieldMaterialPointer& material = HeightfieldMaterialPointer());
void setContents(const HeightfieldHeightPointer& height, const HeightfieldColorPointer& color,
const HeightfieldMaterialPointer& material);
const HeightfieldHeightPointer& getHeight() const { return _height; }
const HeightfieldColorPointer& getColor() const { return _color; }
const HeightfieldMaterialPointer& getMaterial() const { return _material; }
@ -533,9 +536,10 @@ class Heightfield : public Transformable {
Q_OBJECT
Q_PROPERTY(float aspectY MEMBER _aspectY WRITE setAspectY NOTIFY aspectYChanged)
Q_PROPERTY(float aspectZ MEMBER _aspectZ WRITE setAspectZ NOTIFY aspectZChanged)
Q_PROPERTY(HeightfieldHeightPointer height MEMBER _height WRITE setHeight NOTIFY heightChanged)
Q_PROPERTY(HeightfieldColorPointer color MEMBER _color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(HeightfieldMaterialPointer material MEMBER _material WRITE setMaterial NOTIFY materialChanged DESIGNABLE false)
Q_PROPERTY(HeightfieldHeightPointer height MEMBER _height WRITE setHeight NOTIFY heightChanged STORED false)
Q_PROPERTY(HeightfieldColorPointer color MEMBER _color WRITE setColor NOTIFY colorChanged STORED false)
Q_PROPERTY(HeightfieldMaterialPointer material MEMBER _material WRITE setMaterial NOTIFY materialChanged STORED false
DESIGNABLE false)
public:
@ -600,6 +604,7 @@ protected:
private slots:
void updateBounds();
void updateRoot();
private: