Extend SDF outside the bounding box for SdfLib plugin.

SdfLib returns the sum of the distance from a given point to the bounding box and a saved minimum distance from the surface over the whole box boundary. This underestimates the true distance and can cause spurious contacts and jittering. This CL performs a box projection of points outside the bounding box and adds the distance of the original point from the box to the distance of the projected point to the surface. This overestimates the true distance and avoids spurious collisions.

PiperOrigin-RevId: 586701933
Change-Id: I22eecb9757fa22359440156ef6433135648fa3ff
This commit is contained in:
Alessio Quaglino
2023-11-30 09:42:07 -08:00
committed by Copybara-Service
parent a306e32707
commit 4c8ffb44bf
+30 -1
View File
@@ -31,6 +31,34 @@ inline unsigned int* MakeNonConstUnsigned(const int* ptr) {
return reinterpret_cast<unsigned int*>(const_cast<int*>(ptr));
}
mjtNum boxProjection(glm::vec3& point, const sdflib::BoundingBox& box) {
glm::vec3 r = point - box.getCenter();
glm::vec3 q = glm::abs(r) - 0.5f * box.getSize();
mjtNum dist_sqr = 0;
mjtNum eps = 1e-6;
// skip the projection if inside
if (q.x <= 0 && q.y <= 0 && q.z <= 0) {
return glm::max(q.x, glm::max(q.y, q.z));
}
// in-place projection inside the box if outside
if ( q.x >= 0 ) {
dist_sqr += q.x * q.x;
point.x -= r.x > 0 ? (q.x+eps) : -(q.x+eps);
}
if ( q.y >= 0 ) {
dist_sqr += q.y * q.y;
point.y -= r.y > 0 ? (q.y+eps) : -(q.y+eps);
}
if ( q.z >= 0 ) {
dist_sqr += q.z * q.z;
point.z -= r.z > 0 ? (q.z+eps) : -(q.z+eps);
}
return mju_sqrt(dist_sqr);
}
} // namespace
// factory function
@@ -89,7 +117,8 @@ void SdfLib::Visualize(const mjModel* m, mjData* d, const mjvOption* opt,
// sdf
mjtNum SdfLib::Distance(const mjtNum p[3]) const {
glm::vec3 point(p[0], p[1], p[2]);
return sdf_func_.getDistance(point);
mjtNum boxDist = boxProjection(point, sdf_func_.getGridBoundingBox());
return sdf_func_.getDistance(point) + (boxDist <= 0 ? 0 : boxDist);
}
// gradient of sdf