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 // Test using AABB
shared_ptr<ModelSceneNode> model(object->getModelSceneNode()); shared_ptr<ModelSceneNode> model(object->getModelSceneNode());
if (model) { if (model) {
// Prevent division by zero if (model->aabb().raycast(objSpaceOrigin, objSpaceDir, distance) &&
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) &&
distance >= 0.0f && distance <= props.distance) { distance >= 0.0f && distance <= props.distance) {
collisions.push_back(make_pair(object, 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 // Algorithm adapted from https://gamedev.stackexchange.com/a/18459
bool AABB::raycast(const glm::vec3 &origin, const glm::vec3 &invDir, float &distance) const { bool AABB::raycast(const glm::vec3 &origin, const glm::vec3 &dir, float &distance) const {
float tx1 = (_min.x - origin.x) * invDir.x; glm::vec3 dirfrac(1.0f / dir);
float tx2 = (_max.x - origin.x) * invDir.x;
float ty1 = (_min.y - origin.y) * invDir.y; float tx1 = (_min.x - origin.x) * dirfrac.x;
float ty2 = (_max.y - origin.y) * invDir.y; float tx2 = (_max.x - origin.x) * dirfrac.x;
float tz1 = (_min.z - origin.z) * invDir.z; float ty1 = (_min.y - origin.y) * dirfrac.y;
float tz2 = (_max.z - origin.z) * invDir.z; 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 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)); 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 < 0.0f) return false; // AABB is behind
if (tmax < tmin) return false; // neither backside nor frontside if (tmax < tmin) return false; // no intersection
distance = tmin; distance = tmin;
@ -149,28 +151,6 @@ glm::vec3 AABB::getSize() const {
return _max - _min; 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 graphics
} // namespace reone } // namespace reone

View file

@ -43,23 +43,13 @@ public:
* Casts a ray and tests if it intersects this AABB. * Casts a ray and tests if it intersects this AABB.
* *
* @param origin ray origin * @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) * @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; 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 &min() const { return _min; }
const glm::vec3 &max() const { return _max; } const glm::vec3 &max() const { return _max; }
const glm::vec3 &center() const { return _center; } const glm::vec3 &center() const { return _center; }
@ -73,8 +63,6 @@ private:
glm::mat4 _transform { 1.0f }; glm::mat4 _transform { 1.0f };
void updateTransform(); void updateTransform();
inline glm::vec3 getClosestPoint(const glm::vec3 &point) const;
}; };
} // namespace graphics } // namespace graphics

View file

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

View file

@ -74,17 +74,11 @@ float SceneNode::getDistanceTo2(const glm::vec3 &point) const {
} }
float SceneNode::getDistanceTo(const SceneNode &other) 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 { float SceneNode::getDistanceTo2(const SceneNode &other) const {
if (!other.isVolumetric()) { return glm::distance2(getOrigin(), other.getOrigin());
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) { void SceneNode::setParent(const SceneNode *parent) {