Cleanup collision detection

This commit is contained in:
Vsevolod Kremianskii 2021-05-10 16:12:17 +07:00
parent e99822ae3c
commit 235ed4a274
6 changed files with 20 additions and 64 deletions

View file

@ -98,13 +98,7 @@ bool CollisionDetector::rayTestObjects(const RaycastProperties &props, RaycastRe
// Test using AABB
shared_ptr<ModelSceneNode> model(object->getModelSceneNode());
if (model) {
// Prevent division by zero
if (objSpaceDir.x == 0.0f) objSpaceDir.x = 1e-7f;
if (objSpaceDir.y == 0.0f) objSpaceDir.y = 1e-7f;
if (objSpaceDir.z == 0.0f) objSpaceDir.z = 1e-7f;
glm::vec3 invDir(1.0f / objSpaceDir);
if (model->aabb().raycast(objSpaceOrigin, invDir, distance) &&
if (model->aabb().raycast(objSpaceOrigin, objSpaceDir, distance) &&
distance >= 0.0f && distance <= props.distance) {
collisions.push_back(make_pair(object, distance));

View file

@ -127,18 +127,20 @@ bool AABB::intersect(const AABB &other) const {
}
// Algorithm adapted from https://gamedev.stackexchange.com/a/18459
bool AABB::raycast(const glm::vec3 &origin, const glm::vec3 &invDir, float &distance) const {
float tx1 = (_min.x - origin.x) * invDir.x;
float tx2 = (_max.x - origin.x) * invDir.x;
float ty1 = (_min.y - origin.y) * invDir.y;
float ty2 = (_max.y - origin.y) * invDir.y;
float tz1 = (_min.z - origin.z) * invDir.z;
float tz2 = (_max.z - origin.z) * invDir.z;
bool AABB::raycast(const glm::vec3 &origin, const glm::vec3 &dir, float &distance) const {
glm::vec3 dirfrac(1.0f / dir);
float tx1 = (_min.x - origin.x) * dirfrac.x;
float tx2 = (_max.x - origin.x) * dirfrac.x;
float ty1 = (_min.y - origin.y) * dirfrac.y;
float ty2 = (_max.y - origin.y) * dirfrac.y;
float tz1 = (_min.z - origin.z) * dirfrac.z;
float tz2 = (_max.z - origin.z) * dirfrac.z;
float tmin = glm::max(glm::max(glm::min(tx1, tx2), glm::min(ty1, ty2)), glm::min(tz1, tz2));
float tmax = glm::min(glm::min(glm::max(tx1, tx2), glm::max(ty1, ty2)), glm::max(tz1, tz2));
if (tmax < 0.0f) return false; // backside intersection
if (tmax < tmin) return false; // neither backside nor frontside
if (tmax < 0.0f) return false; // AABB is behind
if (tmax < tmin) return false; // no intersection
distance = tmin;
@ -149,28 +151,6 @@ glm::vec3 AABB::getSize() const {
return _max - _min;
}
float AABB::getDistanceFromClosestPoint(const glm::vec3 &point) const {
return glm::distance(getClosestPoint(point), point);
}
glm::vec3 AABB::getClosestPoint(const glm::vec3 &point) const {
glm::vec3 closest;
for (int i = 0; i < 3; ++i) {
if (point[i] > _max[i]) {
closest[i] = _max[i];
} else if (point[i] < _min[i]) {
closest[i] = _min[i];
} else {
closest[i] = point[i];
}
}
return move(closest);
}
float AABB::getDistanceFromClosestPoint2(const glm::vec3 &point) const {
return glm::distance2(getClosestPoint(point), point);
}
} // namespace graphics
} // namespace reone

View file

@ -43,23 +43,13 @@ public:
* Casts a ray and tests if it intersects this AABB.
*
* @param origin ray origin
* @param invDir ray direction inverse
* @param dir ray direction
* @param[out] distance to the intersection point (negative if ray origin is inside this AABB)
*/
bool raycast(const glm::vec3 &origin, const glm::vec3 &invDir, float &distance) const;
bool raycast(const glm::vec3 &origin, const glm::vec3 &dir, float &distance) const;
glm::vec3 getSize() const;
/**
* @return distance from the closest point of this AABB to the specified point
*/
float getDistanceFromClosestPoint(const glm::vec3 &point) const;
/**
* @return squared distance from the closest point of this AABB to the specified point
*/
float getDistanceFromClosestPoint2(const glm::vec3 &point) const;
const glm::vec3 &min() const { return _min; }
const glm::vec3 &max() const { return _max; }
const glm::vec3 &center() const { return _center; }
@ -73,8 +63,6 @@ private:
glm::mat4 _transform { 1.0f };
void updateTransform();
inline glm::vec3 getClosestPoint(const glm::vec3 &point) const;
};
} // namespace graphics

View file

@ -147,9 +147,8 @@ glm::vec2 Mesh::getFaceCenterUV(int faceIdx) const {
if (faceIdx < 0 || faceIdx >= _indices.size() / 3) {
throw out_of_range("faceIdx out of range");
}
if (_offsets.texCoords1 == -1) {
throw logic_error("texCoords1 undefined");
}
if (_offsets.texCoords1 == -1) return glm::vec2(0.0f);
glm::vec2 result(0.0f);
const uint16_t *indices = &_indices[3 * faceIdx];
for (int i = 0; i < 3; ++i) {
@ -159,6 +158,7 @@ glm::vec2 Mesh::getFaceCenterUV(int faceIdx) const {
}
result /= 3.0f;
result = glm::clamp(result);
return move(result);
}

View file

@ -53,7 +53,7 @@ bool Walkmesh::raycast(const glm::vec3 &origin, const glm::vec3 &dir, bool walka
const glm::vec3 &p1 = face.vertices[1];
const glm::vec3 &p2 = face.vertices[2];
if (glm::intersectRayTriangle(origin, dir, p0, p1, p2, baryPosition, localDistance) && localDistance >= 0.0f && localDistance < minDistance) {
if (glm::intersectRayTriangle(origin, dir, p0, p1, p2, baryPosition, localDistance) && localDistance > 0.0f && localDistance < minDistance) {
minDistance = localDistance;
material = static_cast<int>(face.material);
}

View file

@ -74,19 +74,13 @@ float SceneNode::getDistanceTo2(const glm::vec3 &point) const {
}
float SceneNode::getDistanceTo(const SceneNode &other) const {
return glm::sqrt(getDistanceTo2(other));
return glm::distance(getOrigin(), other.getOrigin());
}
float SceneNode::getDistanceTo2(const SceneNode &other) const {
if (!other.isVolumetric()) {
return glm::distance2(getOrigin(), other.getOrigin());
}
glm::vec3 aabbSpaceOrigin(other._absoluteTransformInv * glm::vec4(getOrigin(), 1.0f));
return other.aabb().getDistanceFromClosestPoint2(aabbSpaceOrigin);
}
void SceneNode::setParent(const SceneNode *parent) {
_parent = parent;
updateAbsoluteTransform();