mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Height painting.
This commit is contained in:
parent
479bea1eb2
commit
f192f2428e
3 changed files with 85 additions and 86 deletions
|
@ -154,87 +154,18 @@ PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position
|
|||
height(height) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldHeightEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
PaintHeightfieldHeightEdit _edit;
|
||||
Box _bounds;
|
||||
};
|
||||
|
||||
PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute(),
|
||||
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute()),
|
||||
_edit(edit) {
|
||||
|
||||
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
}
|
||||
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
|
||||
int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
HeightfieldHeightDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
|
||||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
QByteArray contents(pointer->getContents());
|
||||
int size = glm::sqrt((float)contents.size());
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||
float scaledRadius = _edit.radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// raise/lower all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
uchar* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
float distanceSquared = dx * dx + dz * dz;
|
||||
if (distanceSquared <= squaredRadius) {
|
||||
// height falls off towards edges
|
||||
int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
|
||||
if (value != *dest) {
|
||||
*dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
if (changed) {
|
||||
HeightfieldHeightDataPointer newPointer(new HeightfieldHeightData(contents));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldHeightDataPointer>(newPointer));
|
||||
}
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldHeightEditVisitor visitor(*this);
|
||||
data.guide(visitor);
|
||||
glm::vec3 extents(radius, radius, radius);
|
||||
QVector<SharedObjectPointer> results;
|
||||
data.getIntersecting(AttributeRegistry::getInstance()->getSpannersAttribute(),
|
||||
Box(position - extents, position + extents), results);
|
||||
|
||||
foreach (const SharedObjectPointer& spanner, results) {
|
||||
Spanner* newSpanner = static_cast<Spanner*>(spanner.data())->paintHeight(position, radius, height);
|
||||
if (newSpanner != spanner) {
|
||||
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
|
@ -256,7 +187,7 @@ void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedOb
|
|||
Box(position - extents, position + extents), results);
|
||||
|
||||
foreach (const SharedObjectPointer& spanner, results) {
|
||||
Spanner* newSpanner = static_cast<Spanner*>(spanner.data())->paint(position, radius, material, averageColor);
|
||||
Spanner* newSpanner = static_cast<Spanner*>(spanner.data())->paintMaterial(position, radius, material, averageColor);
|
||||
if (newSpanner != spanner) {
|
||||
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner);
|
||||
}
|
||||
|
@ -419,7 +350,8 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) {
|
|||
if (minZ > 0) {
|
||||
hermiteMinZ--;
|
||||
hermiteSizeZ++;
|
||||
}
|
||||
}
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QRgb* hermiteDestZ = hermiteContents.data() + hermiteMinZ * hermiteArea + hermiteMinY * hermiteSamples +
|
||||
hermiteMinX * VoxelHermiteData::EDGE_COUNT;
|
||||
for (int z = hermiteMinZ, hermiteMaxZ = z + hermiteSizeZ - 1; z <= hermiteMaxZ; z++, hermiteDestZ += hermiteArea) {
|
||||
|
|
|
@ -108,7 +108,12 @@ bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& dire
|
|||
return _bounds.findRayIntersection(origin, direction, distance);
|
||||
}
|
||||
|
||||
Spanner* Spanner::paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color) {
|
||||
Spanner* Spanner::paintMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material,
|
||||
const QColor& color) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Spanner* Spanner::paintHeight(const glm::vec3& position, float radius, float height) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1608,7 +1613,7 @@ bool Heightfield::findRayIntersection(const glm::vec3& origin, const glm::vec3&
|
|||
return false;
|
||||
}
|
||||
|
||||
Spanner* Heightfield::paint(const glm::vec3& position, float radius,
|
||||
Spanner* Heightfield::paintMaterial(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& color) {
|
||||
if (!_height) {
|
||||
return this;
|
||||
|
@ -1714,6 +1719,60 @@ Spanner* Heightfield::paint(const glm::vec3& position, float radius,
|
|||
return newHeightfield;
|
||||
}
|
||||
|
||||
Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float height) {
|
||||
if (!_height) {
|
||||
return this;
|
||||
}
|
||||
int heightWidth = _height->getWidth();
|
||||
int heightHeight = _height->getContents().size() / heightWidth;
|
||||
QVector<quint16> contents = _height->getContents();
|
||||
int innerWidth = heightWidth - HeightfieldHeight::HEIGHT_EXTENSION;
|
||||
int innerHeight = heightHeight - HeightfieldHeight::HEIGHT_EXTENSION;
|
||||
int highestX = heightWidth - 1;
|
||||
int highestZ = heightHeight - 1;
|
||||
Heightfield* newHeightfield = static_cast<Heightfield*>(clone(true));
|
||||
|
||||
glm::vec3 inverseScale(innerWidth / getScale(), 1.0f, innerHeight / (getScale() * _aspectZ));
|
||||
glm::vec3 center = glm::inverse(getRotation()) * (position - getTranslation()) * inverseScale;
|
||||
center.x += 1.0f;
|
||||
center.z += 1.0f;
|
||||
|
||||
glm::vec3 extents = glm::vec3(radius, radius, radius) * inverseScale;
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highestX);
|
||||
quint16* lineDest = contents.data() + (int)z * heightWidth + (int)startX;
|
||||
float squaredRadius = extents.x * extents.x;
|
||||
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||
float scaledHeight = height * numeric_limits<quint16>::max() / (getScale() * _aspectY);
|
||||
float multiplierZ = inverseScale.x / inverseScale.z;
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highestZ); z <= endZ; z += 1.0f) {
|
||||
quint16* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||
float dx = x - center.x, dz = (z - center.z) * multiplierZ;
|
||||
float distanceSquared = dx * dx + dz * dz;
|
||||
if (distanceSquared <= squaredRadius) {
|
||||
// height falls off towards edges
|
||||
int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
|
||||
if (value != *dest) {
|
||||
*dest = qMin(qMax(value, 0), (int)numeric_limits<quint16>::max());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
lineDest += heightWidth;
|
||||
}
|
||||
if (changed) {
|
||||
newHeightfield->setHeight(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, contents)));
|
||||
}
|
||||
|
||||
return newHeightfield;
|
||||
}
|
||||
|
||||
QByteArray Heightfield::getRendererClassName() const {
|
||||
return "HeightfieldRenderer";
|
||||
}
|
||||
|
|
|
@ -66,7 +66,12 @@ public:
|
|||
|
||||
/// Attempts to paint on the spanner.
|
||||
/// \return the modified spanner, or this if no modification was performed
|
||||
virtual Spanner* paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color);
|
||||
virtual Spanner* paintMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material,
|
||||
const QColor& color);
|
||||
|
||||
/// Attempts to modify the spanner's height.
|
||||
/// \return the modified spanner, or this if no modification was performed
|
||||
virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height);
|
||||
|
||||
/// Checks whether this spanner has its own colors.
|
||||
virtual bool hasOwnColors() const;
|
||||
|
@ -515,8 +520,11 @@ public:
|
|||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
virtual Spanner* paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color);
|
||||
virtual Spanner* paintMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material,
|
||||
const QColor& color);
|
||||
|
||||
virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height);
|
||||
|
||||
signals:
|
||||
|
||||
void aspectYChanged(float aspectY);
|
||||
|
|
Loading…
Reference in a new issue