Material/ray testing bits.

This commit is contained in:
Andrzej Kapolka 2015-01-05 18:37:47 -08:00
parent 808cb2e4bc
commit 5a46f3e20d
5 changed files with 302 additions and 178 deletions

View file

@ -1044,16 +1044,17 @@ VoxelBuffer::VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>
_materials(materials) {
}
bool VoxelBuffer::findFirstRayIntersection(const glm::vec3& entry, const glm::vec3& origin,
const glm::vec3& direction, float& distance) const {
bool VoxelBuffer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float boundsDistance, float& distance) const {
float highest = _size - 1.0f;
glm::vec3 position = entry * highest;
glm::vec3 position = (origin + direction * boundsDistance) * highest;
glm::vec3 floors = glm::floor(position);
int max = _size - 2;
int x = qMin((int)floors.x, max), y = qMin((int)floors.y, max), z = qMin((int)floors.z, max);
forever {
for (QMultiHash<VoxelCoord, int>::const_iterator it = _quadIndices.constFind(qRgb(x + 1, y + 1, z + 1));
it != _quadIndices.constEnd(); it++) {
VoxelCoord key(qRgb(x, y, z));
for (QMultiHash<VoxelCoord, int>::const_iterator it = _quadIndices.constFind(key);
it != _quadIndices.constEnd() && it.key() == key; it++) {
const int* indices = _indices.constData() + *it;
if (findRayTriangleIntersection(origin, direction, _vertices.at(indices[0]).vertex,
_vertices.at(indices[1]).vertex, _vertices.at(indices[2]).vertex, distance) ||
@ -1397,6 +1398,19 @@ HeightfieldNodeRenderer::~HeightfieldNodeRenderer() {
Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID));
}
bool HeightfieldNodeRenderer::findRayIntersection(const glm::vec3& translation, const glm::quat& rotation,
const glm::vec3& scale, const glm::vec3& origin, const glm::vec3& direction,
float boundsDistance, float& distance) const {
if (!_voxels) {
return false;
}
glm::quat inverseRotation = glm::inverse(rotation);
float inverseScale = 1.0f / scale.x;
return static_cast<const VoxelBuffer*>(_voxels.data())->findRayIntersection(
inverseRotation * (origin - translation) * inverseScale, inverseRotation * direction * inverseScale,
boundsDistance, distance);
}
class EdgeCrossing {
public:
glm::vec3 point;
@ -2030,8 +2044,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
}
indicesZ.swap(lastIndicesZ);
}
_voxels = new VoxelBuffer(vertices, indices, hermiteSegments, quadIndices, width, node->getStack()->getMaterials());
_voxels = new VoxelBuffer(vertices, indices, hermiteSegments, quadIndices, stackWidth,
node->getStack()->getMaterials());
}
if (_voxels) {

View file

@ -323,9 +323,7 @@ public:
bool isHermiteEnabled() const { return _hermiteEnabled; }
/// Finds the first intersection between the described ray and the voxel data.
/// \param entry the entry point of the ray in relative coordinates, from (0, 0, 0) to (1, 1, 1)
bool findFirstRayIntersection(const glm::vec3& entry, const glm::vec3& origin,
const glm::vec3& direction, float& distance) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const;
virtual void render(const glm::vec3& translation, const glm::quat& rotation,
const glm::vec3& scale, bool cursor = false);
@ -425,6 +423,9 @@ public:
HeightfieldNodeRenderer();
virtual ~HeightfieldNodeRenderer();
virtual bool findRayIntersection(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale,
const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const;
void render(const HeightfieldNodePointer& node, const glm::vec3& translation,
const glm::quat& rotation, const glm::vec3& scale, bool cursor);

View file

@ -1134,9 +1134,8 @@ static QHash<uchar, int> countIndices(const QByteArray& contents) {
return counts;
}
const float EIGHT_BIT_MAXIMUM = 255.0f;
uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObjectPointer>& materials, QByteArray& contents) {
static uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObjectPointer>& materials,
QByteArray& contents) {
if (!(material && static_cast<MaterialObject*>(material.data())->getDiffuse().isValid())) {
return 0;
}
@ -1157,7 +1156,7 @@ uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObject
materials[firstEmptyIndex] = material;
return firstEmptyIndex + 1;
}
if (materials.size() < EIGHT_BIT_MAXIMUM) {
if (materials.size() < numeric_limits<quint8>::max()) {
materials.append(material);
return materials.size();
}
@ -1175,7 +1174,85 @@ uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObject
return materialIndex;
}
void clearUnusedMaterials(QVector<SharedObjectPointer>& materials, const QByteArray& contents) {
static void clearUnusedMaterials(QVector<SharedObjectPointer>& materials, const QByteArray& contents) {
QHash<uchar, int> counts = countIndices(contents);
for (int i = 0; i < materials.size(); i++) {
if (counts.value(i + 1) == 0) {
materials[i] = SharedObjectPointer();
}
}
while (!(materials.isEmpty() || materials.last())) {
materials.removeLast();
}
}
static QHash<uchar, int> countIndices(const QVector<StackArray>& contents) {
QHash<uchar, int> counts;
foreach (const StackArray& array, contents) {
if (array.isEmpty()) {
continue;
}
for (const StackArray::Entry* entry = array.getEntryData(), *end = entry + array.getEntryCount();
entry != end; entry++) {
if (entry->material != 0) {
counts[entry->material]++;
}
}
}
return counts;
}
static uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObjectPointer>& materials,
QVector<StackArray>& contents) {
if (!(material && static_cast<MaterialObject*>(material.data())->getDiffuse().isValid())) {
return 0;
}
// first look for a matching existing material, noting the first reusable slot
int firstEmptyIndex = -1;
for (int i = 0; i < materials.size(); i++) {
const SharedObjectPointer& existingMaterial = materials.at(i);
if (existingMaterial) {
if (existingMaterial->equals(material.data())) {
return i + 1;
}
} else if (firstEmptyIndex == -1) {
firstEmptyIndex = i;
}
}
// if nothing found, use the first empty slot or append
if (firstEmptyIndex != -1) {
materials[firstEmptyIndex] = material;
return firstEmptyIndex + 1;
}
if (materials.size() < numeric_limits<quint8>::max()) {
materials.append(material);
return materials.size();
}
// last resort: find the least-used material and remove it
QHash<uchar, int> counts = countIndices(contents);
uchar materialIndex = 0;
int lowestCount = INT_MAX;
for (QHash<uchar, int>::const_iterator it = counts.constBegin(); it != counts.constEnd(); it++) {
if (it.value() < lowestCount) {
materialIndex = it.key();
lowestCount = it.value();
}
}
for (StackArray* array = contents.data(), *end = array + contents.size(); array != end; array++) {
if (array->isEmpty()) {
continue;
}
for (StackArray::Entry* entry = array->getEntryData(), *end = entry + array->getEntryCount();
entry != end; entry++) {
if (entry->material == materialIndex) {
entry->material = 0;
}
}
}
return materialIndex;
}
static void clearUnusedMaterials(QVector<SharedObjectPointer>& materials, const QVector<StackArray>& contents) {
QHash<uchar, int> counts = countIndices(contents);
for (int i = 0; i < materials.size(); i++) {
if (counts.value(i + 1) == 0) {
@ -1688,18 +1765,26 @@ float HeightfieldNode::getHeight(const glm::vec3& location) const {
return interpolatedHeight / numeric_limits<quint16>::max();
}
bool HeightfieldNode::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
bool HeightfieldNode::findRayIntersection(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale,
const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
glm::quat inverseRotation = glm::inverse(rotation);
glm::vec3 inverseScale = 1.0f / scale;
glm::vec3 transformedOrigin = inverseRotation * (origin - translation) * inverseScale;
glm::vec3 transformedDirection = inverseRotation * direction * inverseScale;
float boundsDistance;
if (!Box(glm::vec3(), glm::vec3(1.0f, 1.0f, 1.0f)).findRayIntersection(origin, direction, boundsDistance)) {
if (!Box(glm::vec3(), glm::vec3(1.0f, 1.0f, 1.0f)).findRayIntersection(transformedOrigin, transformedDirection,
boundsDistance)) {
return false;
}
if (!isLeaf()) {
float closestDistance = FLT_MAX;
for (int i = 0; i < CHILD_COUNT; i++) {
glm::vec3 nextScale = scale * glm::vec3(0.5f, 1.0f, 0.5f);
float childDistance;
if (_children[i]->findRayIntersection(origin * glm::vec3(2.0f, 1.0f, 2.0f) -
glm::vec3(i & X_MAXIMUM_FLAG ? 1.0f : 0.0f, 0.0f, i & Y_MAXIMUM_FLAG ? 1.0f : 0.0f),
direction * glm::vec3(2.0f, 1.0f, 2.0f), childDistance)) {
if (_children[i]->findRayIntersection(translation +
rotation * glm::vec3(i & X_MAXIMUM_FLAG ? nextScale.x : 0.0f, 0.0f,
i & Y_MAXIMUM_FLAG ? nextScale.z : 0.0f), rotation,
nextScale, origin, direction, childDistance)) {
closestDistance = qMin(closestDistance, childDistance);
}
}
@ -1709,148 +1794,21 @@ bool HeightfieldNode::findRayIntersection(const glm::vec3& origin, const glm::ve
distance = closestDistance;
return true;
}
if (!_height) {
float shortestDistance = FLT_MAX;
float heightfieldDistance;
if (findHeightfieldRayIntersection(transformedOrigin, transformedDirection, boundsDistance, heightfieldDistance)) {
shortestDistance = heightfieldDistance;
}
float rendererDistance;
if (_renderer && _renderer->findRayIntersection(translation, rotation, scale, origin, direction, boundsDistance,
rendererDistance)) {
shortestDistance = qMin(shortestDistance, rendererDistance);
}
if (shortestDistance == FLT_MAX) {
return false;
}
int width = _height->getWidth();
const QVector<quint16>& contents = _height->getContents();
const quint16* src = contents.constData();
int height = contents.size() / width;
int innerWidth = width - HeightfieldHeight::HEIGHT_EXTENSION;
int innerHeight = height - HeightfieldHeight::HEIGHT_EXTENSION;
int highestX = innerWidth + HeightfieldHeight::HEIGHT_BORDER;
int highestZ = innerHeight + HeightfieldHeight::HEIGHT_BORDER;
glm::vec3 scale((float)innerWidth, (float)numeric_limits<quint16>::max(), (float)innerHeight);
glm::vec3 dir = direction * scale;
glm::vec3 entry = origin * scale + dir * boundsDistance;
entry.x += HeightfieldHeight::HEIGHT_BORDER;
entry.z += HeightfieldHeight::HEIGHT_BORDER;
glm::vec3 floors = glm::floor(entry);
glm::vec3 ceils = glm::ceil(entry);
if (floors.x == ceils.x) {
if (dir.x > 0.0f) {
ceils.x += 1.0f;
} else {
floors.x -= 1.0f;
}
}
if (floors.z == ceils.z) {
if (dir.z > 0.0f) {
ceils.z += 1.0f;
} else {
floors.z -= 1.0f;
}
}
bool withinBounds = true;
float accumulatedDistance = 0.0f;
while (withinBounds) {
// find the heights at the corners of the current cell
int floorX = qMin(qMax((int)floors.x, HeightfieldHeight::HEIGHT_BORDER), highestX);
int floorZ = qMin(qMax((int)floors.z, HeightfieldHeight::HEIGHT_BORDER), highestZ);
int ceilX = qMin(qMax((int)ceils.x, HeightfieldHeight::HEIGHT_BORDER), highestX);
int ceilZ = qMin(qMax((int)ceils.z, HeightfieldHeight::HEIGHT_BORDER), highestZ);
float upperLeft = src[floorZ * width + floorX];
float upperRight = src[floorZ * width + ceilX];
float lowerLeft = src[ceilZ * width + floorX];
float lowerRight = src[ceilZ * width + ceilX];
// find the distance to the next x coordinate
float xDistance = FLT_MAX;
if (dir.x > 0.0f) {
xDistance = (ceils.x - entry.x) / dir.x;
} else if (dir.x < 0.0f) {
xDistance = (floors.x - entry.x) / dir.x;
}
// and the distance to the next z coordinate
float zDistance = FLT_MAX;
if (dir.z > 0.0f) {
zDistance = (ceils.z - entry.z) / dir.z;
} else if (dir.z < 0.0f) {
zDistance = (floors.z - entry.z) / dir.z;
}
// the exit distance is the lower of those two
float exitDistance = qMin(xDistance, zDistance);
glm::vec3 exit, nextFloors = floors, nextCeils = ceils;
if (exitDistance == FLT_MAX) {
if (dir.y > 0.0f) {
return false; // line points upwards; no collisions possible
}
withinBounds = false; // line points downwards; check this cell only
} else {
// find the exit point and the next cell, and determine whether it's still within the bounds
exit = entry + exitDistance * dir;
withinBounds = (exit.y >= 0.0f && exit.y <= numeric_limits<quint16>::max());
if (exitDistance == xDistance) {
if (dir.x > 0.0f) {
nextFloors.x += 1.0f;
withinBounds &= (nextCeils.x += 1.0f) <= highestX;
} else {
withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldHeight::HEIGHT_BORDER;
nextCeils.x -= 1.0f;
}
}
if (exitDistance == zDistance) {
if (dir.z > 0.0f) {
nextFloors.z += 1.0f;
withinBounds &= (nextCeils.z += 1.0f) <= highestZ;
} else {
withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldHeight::HEIGHT_BORDER;
nextCeils.z -= 1.0f;
}
}
// check the vertical range of the ray against the ranges of the cell heights
if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) ||
qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) {
entry = exit;
floors = nextFloors;
ceils = nextCeils;
accumulatedDistance += exitDistance;
continue;
}
}
// having passed the bounds check, we must check against the planes
glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z);
// first check the triangle including the Z+ segment
glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft);
float lowerProduct = glm::dot(lowerNormal, dir);
if (lowerProduct < 0.0f) {
float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct;
glm::vec3 intersection = relativeEntry + planeDistance * dir;
if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
intersection.z >= intersection.x) {
distance = boundsDistance + accumulatedDistance + planeDistance;
return true;
}
}
// then the one with the X+ segment
glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight);
float upperProduct = glm::dot(upperNormal, dir);
if (upperProduct < 0.0f) {
float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct;
glm::vec3 intersection = relativeEntry + planeDistance * dir;
if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
intersection.x >= intersection.z) {
distance = boundsDistance + accumulatedDistance + planeDistance;
return true;
}
}
// no joy; continue on our way
entry = exit;
floors = nextFloors;
ceils = nextCeils;
accumulatedDistance += exitDistance;
}
return false;
distance = shortestDistance;
return true;
}
HeightfieldNode* HeightfieldNode::paintMaterial(const glm::vec3& position, const glm::vec3& radius,
@ -2316,8 +2274,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
glm::vec3 worldStepZ = glm::vec3(transform * glm::vec4(0.0f, 0.0f, 1.0f, 0.0f));
QRgb rgba = color.rgba();
bool erase = (color.alpha() == 0);
QByteArray dummyContents;
uchar stackMaterialIndex = getMaterialIndex(material, newStackMaterials, dummyContents);
uchar stackMaterialIndex = getMaterialIndex(material, newStackMaterials, newStackContents);
bool hasOwnColors = spanner->hasOwnColors();
bool hasOwnMaterials = spanner->hasOwnMaterials();
QHash<int, int> materialMappings;
@ -2384,7 +2341,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
int& mapping = materialMappings[index];
if (mapping == 0) {
mapping = getMaterialIndex(newMaterialMaterials.at(index - 1),
newStackMaterials, dummyContents);
newStackMaterials, newStackContents);
}
index = mapping;
}
@ -2424,7 +2381,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
int& mapping = materialMappings[index];
if (mapping == 0) {
mapping = getMaterialIndex(spanner->getMaterials().at(index - 1),
newStackMaterials, dummyContents);
newStackMaterials, newStackContents);
}
index = mapping;
}
@ -2520,6 +2477,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
}
}
clearUnusedMaterials(newMaterialMaterials, newMaterialContents);
clearUnusedMaterials(newStackMaterials, newStackContents);
return new HeightfieldNode(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, newHeightContents)),
HeightfieldColorPointer(new HeightfieldColor(colorWidth, newColorContents)),
@ -3011,9 +2969,162 @@ void HeightfieldNode::maybeRenormalize(const glm::vec3& scale, float normalizeSc
}
}
bool HeightfieldNode::findHeightfieldRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float boundsDistance, float& distance) const {
if (!_height) {
return false;
}
int width = _height->getWidth();
const QVector<quint16>& contents = _height->getContents();
const quint16* src = contents.constData();
int height = contents.size() / width;
int innerWidth = width - HeightfieldHeight::HEIGHT_EXTENSION;
int innerHeight = height - HeightfieldHeight::HEIGHT_EXTENSION;
int highestX = innerWidth + HeightfieldHeight::HEIGHT_BORDER;
int highestZ = innerHeight + HeightfieldHeight::HEIGHT_BORDER;
glm::vec3 heightScale((float)innerWidth, (float)numeric_limits<quint16>::max(), (float)innerHeight);
glm::vec3 dir = direction * heightScale;
glm::vec3 entry = origin * heightScale + dir * boundsDistance;
entry.x += HeightfieldHeight::HEIGHT_BORDER;
entry.z += HeightfieldHeight::HEIGHT_BORDER;
glm::vec3 floors = glm::floor(entry);
glm::vec3 ceils = glm::ceil(entry);
if (floors.x == ceils.x) {
if (dir.x > 0.0f) {
ceils.x += 1.0f;
} else {
floors.x -= 1.0f;
}
}
if (floors.z == ceils.z) {
if (dir.z > 0.0f) {
ceils.z += 1.0f;
} else {
floors.z -= 1.0f;
}
}
bool withinBounds = true;
float accumulatedDistance = 0.0f;
while (withinBounds) {
// find the heights at the corners of the current cell
int floorX = qMin(qMax((int)floors.x, HeightfieldHeight::HEIGHT_BORDER), highestX);
int floorZ = qMin(qMax((int)floors.z, HeightfieldHeight::HEIGHT_BORDER), highestZ);
int ceilX = qMin(qMax((int)ceils.x, HeightfieldHeight::HEIGHT_BORDER), highestX);
int ceilZ = qMin(qMax((int)ceils.z, HeightfieldHeight::HEIGHT_BORDER), highestZ);
float upperLeft = src[floorZ * width + floorX];
float upperRight = src[floorZ * width + ceilX];
float lowerLeft = src[ceilZ * width + floorX];
float lowerRight = src[ceilZ * width + ceilX];
// find the distance to the next x coordinate
float xDistance = FLT_MAX;
if (dir.x > 0.0f) {
xDistance = (ceils.x - entry.x) / dir.x;
} else if (dir.x < 0.0f) {
xDistance = (floors.x - entry.x) / dir.x;
}
// and the distance to the next z coordinate
float zDistance = FLT_MAX;
if (dir.z > 0.0f) {
zDistance = (ceils.z - entry.z) / dir.z;
} else if (dir.z < 0.0f) {
zDistance = (floors.z - entry.z) / dir.z;
}
// the exit distance is the lower of those two
float exitDistance = qMin(xDistance, zDistance);
glm::vec3 exit, nextFloors = floors, nextCeils = ceils;
if (exitDistance == FLT_MAX) {
if (dir.y > 0.0f) {
return false; // line points upwards; no collisions possible
}
withinBounds = false; // line points downwards; check this cell only
} else {
// find the exit point and the next cell, and determine whether it's still within the bounds
exit = entry + exitDistance * dir;
withinBounds = (exit.y >= 0.0f && exit.y <= numeric_limits<quint16>::max());
if (exitDistance == xDistance) {
if (dir.x > 0.0f) {
nextFloors.x += 1.0f;
withinBounds &= (nextCeils.x += 1.0f) <= highestX;
} else {
withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldHeight::HEIGHT_BORDER;
nextCeils.x -= 1.0f;
}
}
if (exitDistance == zDistance) {
if (dir.z > 0.0f) {
nextFloors.z += 1.0f;
withinBounds &= (nextCeils.z += 1.0f) <= highestZ;
} else {
withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldHeight::HEIGHT_BORDER;
nextCeils.z -= 1.0f;
}
}
// check the vertical range of the ray against the ranges of the cell heights
if (upperLeft == 0 || upperRight == 0 || lowerLeft == 0 || lowerRight == 0 ||
qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) ||
qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) {
entry = exit;
floors = nextFloors;
ceils = nextCeils;
accumulatedDistance += exitDistance;
continue;
}
}
// having passed the bounds check, we must check against the planes
glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z);
// first check the triangle including the Z+ segment
glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft);
float lowerProduct = glm::dot(lowerNormal, dir);
if (lowerProduct < 0.0f) {
float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct;
glm::vec3 intersection = relativeEntry + planeDistance * dir;
if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
intersection.z >= intersection.x) {
distance = boundsDistance + accumulatedDistance + planeDistance;
return true;
}
}
// then the one with the X+ segment
glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight);
float upperProduct = glm::dot(upperNormal, dir);
if (upperProduct < 0.0f) {
float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct;
glm::vec3 intersection = relativeEntry + planeDistance * dir;
if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
intersection.x >= intersection.z) {
distance = boundsDistance + accumulatedDistance + planeDistance;
return true;
}
}
// no joy; continue on our way
entry = exit;
floors = nextFloors;
ceils = nextCeils;
accumulatedDistance += exitDistance;
}
return false;
}
AbstractHeightfieldNodeRenderer::~AbstractHeightfieldNodeRenderer() {
}
bool AbstractHeightfieldNodeRenderer::findRayIntersection(const glm::vec3& translation,
const glm::quat& rotation, const glm::vec3& scale, const glm::vec3& origin, const glm::vec3& direction,
float boundsDistance, float& distance) const {
return false;
}
Heightfield::Heightfield() :
_aspectY(1.0f),
_aspectZ(1.0f) {
@ -3097,10 +3208,8 @@ float Heightfield::getHeight(const glm::vec3& location) const {
}
bool Heightfield::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
glm::quat inverseRotation = glm::inverse(getRotation());
glm::vec3 inverseScale(1.0f / getScale(), 1.0f / (getScale() * _aspectY), 1.0f / (getScale() * _aspectZ));
return _root->findRayIntersection(inverseRotation * (origin - getTranslation()) * inverseScale,
inverseRotation * direction * inverseScale, distance);
return _root->findRayIntersection(getTranslation(), getRotation(), glm::vec3(getScale(), getScale() * _aspectY,
getScale() * _aspectZ), origin, direction, distance);
}
Spanner* Heightfield::paintMaterial(const glm::vec3& position, float radius,

View file

@ -527,13 +527,6 @@ private:
float _scaleT;
};
/// Utility method for editing: given a material pointer and a list of materials, returns the corresponding material index,
/// creating a new entry in the list if necessary.
uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObjectPointer>& materials, QByteArray& contents);
/// Utility method for editing: removes any unused materials from the supplied list.
void clearUnusedMaterials(QVector<SharedObjectPointer>& materials, const QByteArray& contents);
typedef QExplicitlySharedDataPointer<HeightfieldStack> HeightfieldStackPointer;
/// A single column within a stack block.
@ -690,7 +683,8 @@ public:
float getHeight(const glm::vec3& location) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
bool findRayIntersection(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale,
const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
HeightfieldNode* paintMaterial(const glm::vec3& position, const glm::vec3& radius, const SharedObjectPointer& material,
const QColor& color);
@ -733,6 +727,9 @@ private:
void maybeRenormalize(const glm::vec3& scale, float normalizeScale, float normalizeOffset, int innerStackWidth,
QVector<quint16>& heightContents, QVector<StackArray>& stackContents);
bool findHeightfieldRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float boundsDistance, float& distance) const;
HeightfieldHeightPointer _height;
HeightfieldColorPointer _color;
HeightfieldMaterialPointer _material;
@ -748,6 +745,9 @@ class AbstractHeightfieldNodeRenderer {
public:
virtual ~AbstractHeightfieldNodeRenderer();
virtual bool findRayIntersection(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale,
const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const;
};
/// A heightfield represented as a spanner.

View file

@ -262,7 +262,7 @@ bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direc
return false; // origin below plane
}
float divisor = glm::dot(normal, direction);
if (divisor > -EPSILON) {
if (divisor >= 0.0f) {
return false;
}
float t = dividend / divisor;
@ -490,4 +490,4 @@ void PolygonClip::copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& len
vertexArrayA[i] = vertexArrayB[i];
}
}
}
}