[Bf-blender-cvs] [6b62157e38e] soc-2020-soft-body: sdf is generated on the fly now
mattoverby
noreply at git.blender.org
Thu Aug 20 23:21:53 CEST 2020
Commit: 6b62157e38e85cf82badeab957d557b681ce8db3
Author: mattoverby
Date: Thu Aug 20 16:21:49 2020 -0500
Branches: soc-2020-soft-body
https://developer.blender.org/rB6b62157e38e85cf82badeab957d557b681ce8db3
sdf is generated on the fly now
===================================================================
M extern/discregrid/discregrid/include/Discregrid/cubic_lagrange_discrete_grid.hpp
M extern/softbody/src/admmpd_bvh.h
M extern/softbody/src/admmpd_collision.cpp
M extern/softbody/src/admmpd_collision.h
M intern/softbody/admmpd_api.cpp
M intern/softbody/admmpd_api.h
M source/blender/blenkernel/intern/softbody.c
===================================================================
diff --git a/extern/discregrid/discregrid/include/Discregrid/cubic_lagrange_discrete_grid.hpp b/extern/discregrid/discregrid/include/Discregrid/cubic_lagrange_discrete_grid.hpp
index d6d87d3a791..ba8cea8079f 100755
--- a/extern/discregrid/discregrid/include/Discregrid/cubic_lagrange_discrete_grid.hpp
+++ b/extern/discregrid/discregrid/include/Discregrid/cubic_lagrange_discrete_grid.hpp
@@ -9,7 +9,7 @@ class CubicLagrangeDiscreteGrid : public DiscreteGrid
{
public:
- CubicLagrangeDiscreteGrid(){}
+ CubicLagrangeDiscreteGrid(){ this->m_n_cells = 0; }
CubicLagrangeDiscreteGrid(std::string const& filename);
CubicLagrangeDiscreteGrid(Eigen::AlignedBox3d const& domain,
std::array<unsigned int, 3> const& resolution);
diff --git a/extern/softbody/src/admmpd_bvh.h b/extern/softbody/src/admmpd_bvh.h
index 647442bc4d7..2ad53d0fad8 100644
--- a/extern/softbody/src/admmpd_bvh.h
+++ b/extern/softbody/src/admmpd_bvh.h
@@ -61,6 +61,12 @@ public:
}
};
+ // Return AABB of root
+ Eigen::AlignedBox<T,DIM> bounds() const {
+ if (m_root) { return m_root->aabb; }
+ return Eigen::AlignedBox<T,DIM>();
+ }
+
// Return ptr to the root node
// Becomes invalidated after init()
std::shared_ptr<Node> root() { return m_root; }
diff --git a/extern/softbody/src/admmpd_collision.cpp b/extern/softbody/src/admmpd_collision.cpp
index e984e83098b..09af127a6c2 100644
--- a/extern/softbody/src/admmpd_collision.cpp
+++ b/extern/softbody/src/admmpd_collision.cpp
@@ -26,83 +26,124 @@ VFCollisionPair::VFCollisionPair() :
q_bary(0,0,0)
{}
-void Collision::ObstacleData::clear() {
- V = MatrixXd();
- F = MatrixXi();
- sdf = Discregrid::CubicLagrangeDiscreteGrid();
+bool Collision::ObstacleData::has_obs() const
+{
+ // The obstacle list may include non-closed obstacles,
+ // in which an SDF cannot be computed. This function
+ // instead returns true only if an SDF can be generated.
+ int n_box = box.size();
+ for (int i=0; i<n_box; ++i) {
+ if (!box[i].isEmpty()) {
+ return true;
+ }
+ }
+ return false;
}
-
-bool Collision::set_obstacles(
- const float *v0,
- const float *v1,
- int nv,
- const unsigned int *faces,
- int nf,
- std::string *err)
+bool Collision::ObstacleData::compute_sdf(int idx)
{
- (void)(v0);
- if (nv==0 || nf==0)
- {
- if (err) { *err = "Collision obstacle has no verts or faces"; }
- obsdata.clear();
+ if (idx < 0 || idx >x1.size()) {
return false;
}
- std::vector<double> v1_dbl(nv*3);
- Eigen::AlignedBox<double,3> domain;
-
- if (obsdata.V.rows() != nv)
- obsdata.V.resize(nv,3);
- for (int i=0; i<nv; ++i)
- {
- for (int j=0; j<3; ++j)
- {
- obsdata.V(i,j) = v1[i*3+j];
- v1_dbl[i*3+j] = v1[i*3+j];
- }
- domain.extend(obsdata.V.row(i).transpose());
- }
-
- if (obsdata.F.rows() != nf)
- obsdata.F.resize(nf,3);
- for (int i=0; i<nf; ++i)
- {
- for (int j=0; j<3; ++j)
- obsdata.F(i,j) = faces[i*3+j];
+ // There was an error in init
+ if (box[idx].isEmpty()) {
+ return false;
}
- // Is the mesh closed?
- Discregrid::TriangleMesh tm(v1_dbl.data(), faces, nv, nf);
+ // Test that the mesh is closed
+ Discregrid::TriangleMesh tm(
+ (double const*)x1[idx].data(),
+ (unsigned int const*)F[idx].data(),
+ x1[idx].rows(), F[idx].rows());
if (!tm.is_closed()) {
- if (err) { *err = "Collision obstacle not a closed mesh - ignoring"; }
- obsdata.clear();
return false;
}
// Generate signed distance field
- {
- Discregrid::MeshDistance md(tm);
- domain.max() += 1e-3 * domain.diagonal().norm() * Eigen::Vector3d::Ones();
- domain.min() -= 1e-3 * domain.diagonal().norm() * Eigen::Vector3d::Ones();
- std::array<unsigned int, 3> resolution;
- resolution[0] = 30; resolution[1] = 30; resolution[2] = 30;
- obsdata.sdf = Discregrid::CubicLagrangeDiscreteGrid(domain, resolution);
- auto func = Discregrid::DiscreteGrid::ContinuousFunction{};
- std::vector<std::thread::id> thread_map;
- md.set_thread_map(&thread_map);
- func = [&md](Eigen::Vector3d const& xi) {
- return md.signedDistanceCached(xi);
- };
- obsdata.sdf.addFunction(func, &thread_map, false);
+ Discregrid::MeshDistance md(tm);
+ std::array<unsigned int, 3> resolution;
+ resolution[0] = 30; resolution[1] = 30; resolution[2] = 30;
+ sdf[idx] = Discregrid::CubicLagrangeDiscreteGrid(box[idx], resolution);
+ auto func = Discregrid::DiscreteGrid::ContinuousFunction{};
+ std::vector<std::thread::id> thread_map;
+ md.set_thread_map(&thread_map);
+ func = [&md](Eigen::Vector3d const& xi) {
+ return md.signedDistanceCached(xi);
+ };
+ sdf[idx].addFunction(func, &thread_map, false);
+
+ if (sdf[idx].nCells()==0) {
+ return false;
}
+ return true;
+}
- if (obsdata.sdf.nCells()==0) {
- if (err) { *err = "SDF gen failed for collision obstacle"; }
- obsdata.clear();
+bool Collision::set_obstacles(
+ std::vector<Eigen::MatrixXd> &v0,
+ std::vector<Eigen::MatrixXd> &v1,
+ std::vector<Eigen::MatrixXi> &F,
+ std::string *err)
+{
+ if (v0.size() != v1.size() || v0.size() != F.size()) {
+ if (err) { *err = "Bad dimensions on obstacle input"; }
return false;
}
+ // Copy the obstacle data from the input to the stored
+ // data container. If the vertex locations have changed,
+ // we need to recompute the SDF. Otherwise, leave it as is.
+ int n_obs_new = v0.size();
+ int n_obs_old = obsdata.x0.size();
+ obsdata.sdf.resize(n_obs_new);
+ obsdata.x0.resize(n_obs_new);
+ obsdata.x1.resize(n_obs_new);
+ obsdata.F.resize(n_obs_new);
+ obsdata.box.resize(n_obs_new);
+
+ // We can use isApprox for testing if the obstacle has
+ // moved from the last call to set_obstacles. The SDF
+ // has limited accuracy anyway...
+ double approx_eps = 1e-6;
+ for (int i=0; i<n_obs_new; ++i) {
+
+ bool reset_obs = false;
+ if (i >= n_obs_old) {
+ reset_obs=true; // is new obs
+ }
+ else if (!obsdata.x1[i].isApprox(v1[i],approx_eps) ||
+ !obsdata.x0[i].isApprox(v0[i],approx_eps)) {
+ reset_obs = true; // is different than before
+ }
+
+ if (reset_obs) {
+
+ obsdata.box[i].setEmpty();
+ int nv = v1[i].rows();
+ for (int j=0; j<nv; ++j) {
+ obsdata.box[i].extend(v1[i].row(j).transpose());
+ }
+ obsdata.box[i].max() += 1e-3 * obsdata.box[i].diagonal().norm() * Eigen::Vector3d::Ones();
+ obsdata.box[i].min() -= 1e-3 * obsdata.box[i].diagonal().norm() * Eigen::Vector3d::Ones();
+
+ obsdata.sdf[i] = SDFType(); // clear old sdf
+ obsdata.x0[i] = v0[i];
+ obsdata.x1[i] = v1[i];
+ obsdata.F[i] = F[i].cast<unsigned int>();
+
+ // Determine if the triangle mesh is closed or not.
+ // We want to provide a warning if it is.
+ Discregrid::TriangleMesh tm(
+ (double const*)obsdata.x1[i].data(),
+ (unsigned int const*)obsdata.F[i].data(),
+ obsdata.x1[i].rows(), obsdata.F[i].rows());
+ if (!tm.is_closed()) {
+ obsdata.box[i].setEmpty();
+ if (err) { *err = "Collision obstacle not a closed mesh - ignoring"; }
+ }
+ }
+ }
+
return true;
} // end add obstacle
@@ -121,29 +162,31 @@ Collision::detect_against_obs(
(void)(data);
(void)(pt_t0);
- std::pair<bool,VFCollisionPair> ret =
- std::make_pair(false, VFCollisionPair());
-
- if (!obs->has_obs())
- return ret;
+ int n_obs = obs->num_obs();
+ if (n_obs==0) {
+ return std::make_pair(false, VFCollisionPair());
+ }
- // So I feel bad because we're using the SDF only
- // for inside/outside query. Unfortunately this implementation
- // doesn't store the face indices within the grid cells, so
- // the interpolate function won't return the nearest
- // face at the gradient + distance.
- Vector3d n;
- double dist = obs->sdf.interpolate(0, pt_t1, &n);
- if (dist > 0)
+ for (int i=0; i<n_obs; ++i)
+ {
+ if (obs->sdf[i].nCells()==0) {
+ continue; // not initialized
+ }
+ Vector3d n;
+ double dist = obs->sdf[i].interpolate(0, pt_t1, &n);
+ if (dist > 0) { continue; } // not colliding
+
+ std::pair<bool,VFCollisionPair> ret =
+ std::make_pair(true, VFCollisionPair());
+ ret.first = true;
+ ret.second.q_idx = -1;
+ ret.second.q_is_obs = true;
+ ret.second.q_bary.setZero();
+ ret.second.q_pt = pt_t1 - dist*n;
+ ret.second.q_n = n.normalized();
return ret;
-
- ret.first = true;
- ret.second.q_idx = -1;
- ret.second.q_is_obs = true;
- ret.second.q_bary.setZero();
- ret.second.q_pt = pt_t1 - dist*n;
- ret.second.q_n = n.normalized();
- return ret;
+ }
+ return std::make_pair(false, VFCollisionPair());
}
int EmbeddedMeshCollision::detect(
@@ -159,8 +202,26 @@ int EmbeddedMeshCollision::detect(
if (mesh->type() != MESHTYPE_EMBEDDED)
return 0;
- // Do we even need to process collisions?
- if (!this->obsdata.has_obs() && !options->self_collision)
+ // Compute SDFs if the mesh is intersecting
+ // the associated obstacle. The sdf generation is internally threaded,
+ // but it might be faster to thread the different SDFs.
+ bool has_obs_intersection = false;
+ int n_obs = obsdata.num_obs();
+ AlignedBox<double,3> mesh_box = data->col.prim_tree.bounds();
+ for (int i=0; i<n_obs; ++i) {
+ AlignedBox<double,3> &box = obsdata.box[i];
+ if (box.isEmpty()) { continue; }
+ if (!box.intersects(mesh_box)) { continue; }
+ has_obs_intersection = true;
+ // Do we need to generate a new SDF?
+ if (obsdata.sdf[i].nCells()==0) {
+ obsdata.compute_sdf(i);
+ }
+ }
+
+ // Do we even need to process collisions and launch
+ // the per-vertex threads?
+ if (!has_obs_intersection && !options->self_collision)
{
if (x1->col(2).minCoeff() > options->floor)
{
@@ -236,7 +297,7 @@ int EmbeddedMeshCollision::detect(
}
// Detect against obstacles
- if (td->obsdata->has_obs())
+ if (td->obsdata->num_obs()>0)
{
std::pair<bool,VFCollisionPair> pt_hit_obs =
td->collision->detect_against_obs(
diff --git a/extern/softbody/src/admmpd_collision.h b/extern/softbody/src/admmpd_collision.h
index 25d9feb295b..4869b2b7268 100644
--- a/extern/softbody/src/admmpd_collision.h
+++ b/extern/softbody/src/admmpd_collision.h
@@ -23,11 +23,15 @@ struct VFCollisionPair {
class Collision {
public:
struct ObstacleData {
- bool has_obs() const { return F.rows()>0; }
- void clear();
- Eigen::MatrixXd V;
- Eigen::MatrixXi F;
- SDFType sdf;
+ int num_obs() const { return sdf.size(); }
+ bool has_obs() const;
+ bool
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list