Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorover0219 <over0219@umn.edu>2020-06-16 03:56:00 +0300
committerover0219 <over0219@umn.edu>2020-06-16 03:56:00 +0300
commit5b09a54b41084857af4fc00426df9d1e0539e0bd (patch)
tree4cd7b44334cd259f5d315e383e2acf05fbcc8490
parentadc3d113f248ca036fcb8e530aba31edc24cb5f2 (diff)
debugging uniform lattice
-rw-r--r--extern/softbody/src/admmpd_energy.cpp2
-rw-r--r--extern/softbody/src/admmpd_lattice.cpp207
-rw-r--r--extern/softbody/src/admmpd_lattice.h28
-rw-r--r--extern/softbody/src/admmpd_solver.cpp23
-rw-r--r--extern/softbody/src/admmpd_solver.h6
-rw-r--r--intern/softbody/admmpd_api.cpp131
-rw-r--r--intern/softbody/admmpd_api.h1
-rw-r--r--source/blender/blenkernel/intern/softbody.c18
8 files changed, 243 insertions, 173 deletions
diff --git a/extern/softbody/src/admmpd_energy.cpp b/extern/softbody/src/admmpd_energy.cpp
index 36f0bfa1478..41aebbe0739 100644
--- a/extern/softbody/src/admmpd_energy.cpp
+++ b/extern/softbody/src/admmpd_energy.cpp
@@ -94,7 +94,7 @@ int EnergyTerm::init_tet(
volume = edges.determinant() / 6.0f;
if( volume < 0 )
{
- printf("**EnergyTerm::init_tet: Inverted initial tet");
+ printf("**admmpd::EnergyTerm Error: Inverted initial tet: %f\n",volume);
return 0;
}
double k = lame.m_bulk_mod;
diff --git a/extern/softbody/src/admmpd_lattice.cpp b/extern/softbody/src/admmpd_lattice.cpp
index be7a5bc63d2..b0c8f6ca556 100644
--- a/extern/softbody/src/admmpd_lattice.cpp
+++ b/extern/softbody/src/admmpd_lattice.cpp
@@ -4,6 +4,7 @@
#include "admmpd_lattice.h"
#include "admmpd_math.h"
#include <iostream>
+#include <unordered_map>
//#include "vdb.h"
@@ -52,94 +53,114 @@ inline void map_to_x4i(const std::vector<Vector4i> &x_vec, Eigen::MatrixXi *x)
bool Lattice::generate(
const Eigen::MatrixXd &V,
- Eigen::MatrixXd *x, // lattice vertices, n x 3
- Eigen::MatrixXi *tets) // lattice elements, m x 4
+ Eigen::MatrixXd *X, // lattice vertices, n x 3
+ Eigen::MatrixXi *T) // lattice elements, m x 4
{
- // All vertices enclosed in 5 tets!
- // Will generate actual lattice in the future.
- AlignedBox<double,3> box;
- vtx = V;
- int nv = vtx.rows();
- for (int i=0; i<nv; ++i)
+ AlignedBox<double,3> aabb;
+ int nv = V.rows();
+ for(int i=0; i<nv; ++i)
+ aabb.extend(V.row(i).transpose());
+
+ aabb.extend(aabb.min()-Vector3d::Ones()*1e-6);
+ aabb.extend(aabb.max()+Vector3d::Ones()*1e-6);
+ Vector3d mesh_boxmin = aabb.min();
+ Vector3d sizes = aabb.sizes();
+ double grid_dx = sizes.maxCoeff() * 0.2;
+
+ // Generate vertices and tets
+ std::vector<Vector3d> verts;
+ std::vector<Vector4i> tets;
{
- Vector3d v = vtx.row(i);
- box.extend(v);
- }
- box.extend(box.min() - Vector3d::Ones() * 1e-12);
- box.extend(box.max() + Vector3d::Ones() * 1e-12);
+ std::unordered_map<std::string, int> vertex_map; // [i,j,k]->index
- std::vector<Vector3d> x_vec;
- std::vector<Vector4i> t_vec;
- create_packed_tets(box.min(),box.max(),x_vec,t_vec);
+ auto grid_hash = [&](const Vector3d &x)
+ {
+ Vector3i ll = Vector3i( // nearest gridcell
+ std::round((x[0]-mesh_boxmin[0])/grid_dx),
+ std::round((x[1]-mesh_boxmin[1])/grid_dx),
+ std::round((x[2]-mesh_boxmin[2])/grid_dx));
+ return std::to_string(ll[0])+' '+std::to_string(ll[1])+' '+std::to_string(ll[2]);
+ };
+
+ auto add_box = [&](int i_, int j_, int k_)
+ {
+ Vector3d min = mesh_boxmin + Vector3d(i_*grid_dx, j_*grid_dx, k_*grid_dx);
+ Vector3d max = mesh_boxmin + Vector3d((i_+1)*grid_dx, (j_+1)*grid_dx, (k_+1)*grid_dx);
+ std::vector<Vector3d> v = {
+ // Top plane, clockwise looking down
+ max,
+ Vector3d(min[0], max[1], max[2]),
+ Vector3d(min[0], max[1], min[2]),
+ Vector3d(max[0], max[1], min[2]),
+ // Bottom plan, clockwise looking down
+ Vector3d(max[0], min[1], max[2]),
+ Vector3d(min[0], min[1], max[2]),
+ min,
+ Vector3d(max[0], min[1], min[2])
+ };
+ // Add vertices and get indices of the box
+ std::vector<int> b;
+ for(int i=0; i<8; ++i)
+ {
+ std::string hash = grid_hash(v[i]);
+ if( vertex_map.count(hash)==0 )
+ {
+ vertex_map[hash] = verts.size();
+ verts.emplace_back(v[i]);
+ }
+ b.emplace_back(vertex_map[hash]);
+ }
+ // From the box, create five new tets
+ std::vector<Vector4i> new_tets = {
+ Vector4i( b[0], b[5], b[7], b[4] ),
+ Vector4i( b[5], b[7], b[2], b[0] ),
+ Vector4i( b[5], b[0], b[2], b[1] ),
+ Vector4i( b[7], b[2], b[0], b[3] ),
+ Vector4i( b[5], b[2], b[7], b[6] )
+ };
+ for(int i=0; i<5; ++i)
+ tets.emplace_back(new_tets[i]);
+ };
+
+ int ni = std::ceil(sizes[0]/grid_dx);
+ int nj = std::ceil(sizes[1]/grid_dx);
+ int nk = std::ceil(sizes[2]/grid_dx);
+ for(int i=0; i<ni; ++i)
+ {
+ for(int j=0; j<nj; ++j)
+ {
+ for(int k=0; k<nk; ++k)
+ {
+ add_box(i,j,k);
+ }
+ }
+ }
- // Copy vector data to output
- map_to_x3d(x_vec, x);
- map_to_x4i(t_vec, tets);
- return compute_vtx_tet_mapping(&vtx, &vtx_to_tet, &barys, x, tets);
+ } // end create boxes and vertices
-} // end gen lattice
+ // Copy data into matrices
+ {
+ nv = verts.size();
+ X->resize(nv,3);
+ for(int i=0; i<nv; ++i){
+ for(int j=0; j<3; ++j){
+ X->operator()(i,j) = verts[i][j];
+ }
+ }
+ int nt = tets.size();
+ T->resize(nt,4);
+ for(int i=0; i<nt; ++i){
+ for(int j=0; j<4; ++j){
+ T->operator()(i,j) = tets[i][j];
+ }
+ }
+ }
-//
-// Original source (BSD-2):
-// github.com/mattoverby/mclscene/blob/master/include/MCL/EmbeddedMesh.hpp
-//
-void Lattice::create_packed_tets(
- const Eigen::Vector3d &min,
- const Eigen::Vector3d &max,
- std::vector<Vector3d> &verts,
- std::vector<Vector4i> &tets )
-{
+ return compute_vtx_tet_mapping(
+ &V, &vtx_to_tet, &barys,
+ X, T);
- // Top plane, clockwise looking down
- Vector3d a = max;
- Vector3d b( min[0], max[1], max[2] );
- Vector3d c( min[0], max[1], min[2] );
- Vector3d d( max[0], max[1], min[2] );
-
- // Bottom plan, clockwise looking down
- Vector3d e( max[0], min[1], max[2] );
- Vector3d f( min[0], min[1], max[2] );
- Vector3d g( min[0], min[1], min[2] );
- Vector3d h( max[0], min[1], min[2] );
-
- // Add the verts
- int nv = verts.size();
- verts.emplace_back( a ); // 0
- verts.emplace_back( b ); // 1
- verts.emplace_back( c ); // 2
- verts.emplace_back( d ); // 3
- verts.emplace_back( e ); // 4
- verts.emplace_back( f ); // 5
- verts.emplace_back( g ); // 6
- verts.emplace_back( h ); // 7
-
- // Pack 5 tets into the cube
- Vector4i t0( 0, 5, 7, 4 );
- Vector4i t1( 5, 7, 2, 0 );
- Vector4i t2( 5, 0, 2, 1 );
- Vector4i t3( 7, 2, 0, 3 );
- Vector4i t4( 5, 2, 7, 6 );
- Vector4i offset(nv,nv,nv,nv);
-
- // Add the tets
- tets.emplace_back( t0+offset );
- tets.emplace_back( t1+offset );
- tets.emplace_back( t2+offset );
- tets.emplace_back( t3+offset );
- tets.emplace_back( t4+offset );
-
-//vdb_point(a[0],a[1],a[2]);
-//vdb_point(b[0],b[1],b[2]);
-//vdb_point(c[0],c[1],c[2]);
-//vdb_point(d[0],d[1],d[2]);
-//vdb_point(e[0],e[1],e[2]);
-//vdb_point(f[0],f[1],f[2]);
-//vdb_point(g[0],g[1],g[2]);
-//vdb_point(h[0],h[1],h[2]);
-//vdb_line(float x0, float y0, float z0,
-// float x1, float y1, float z1);
-
-} // end create packed tets
+} // end gen lattice
bool Lattice::compute_vtx_tet_mapping(
const Eigen::MatrixXd *vtx_, // embedded vertices, p x 3
@@ -204,27 +225,5 @@ Eigen::Vector3d Lattice::get_mapped_vertex(
x_or_v->row(tet[2]) * b[2] +
x_or_v->row(tet[3]) * b[3]);
}
-/*
-void Lattice::map_to_object(
- const Eigen::MatrixXd *x,
- const Eigen::MatrixXi *tets,
- float (*vertexCos)[3])
-{
- int nv = vtx.rows();
- for (int i=0; i<nv; ++i)
- {
- int t_idx = vtx_to_tet[i];
- RowVector4i tet = tets->row(t_idx);
- RowVector4d b = barys.row(i);
- vtx.row(i) =
- x->row(tet[0]) * b[0] +
- x->row(tet[1]) * b[1] +
- x->row(tet[2]) * b[2] +
- x->row(tet[3]) * b[3];
- vertexCos[i][0] = vtx(i,0);
- vertexCos[i][1] = vtx(i,1);
- vertexCos[i][2] = vtx(i,2);
- }
-} // end map to object
-*/
+
} // namespace admmpd \ No newline at end of file
diff --git a/extern/softbody/src/admmpd_lattice.h b/extern/softbody/src/admmpd_lattice.h
index b341de636ec..15e2d391d11 100644
--- a/extern/softbody/src/admmpd_lattice.h
+++ b/extern/softbody/src/admmpd_lattice.h
@@ -11,8 +11,6 @@ namespace admmpd {
class Lattice {
public:
-
- Eigen::MatrixXd vtx; // rest embedded vertices, p x 3
Eigen::VectorXi vtx_to_tet; // what tet vtx is embedded in, p x 1
Eigen::MatrixXd barys; // barycoords of the embedding, p x 4
@@ -22,17 +20,15 @@ public:
Eigen::MatrixXd *x, // lattice vertices, n x 3
Eigen::MatrixXi *tets); // lattice elements, m x 4
- // Given boxmin and boxmax, adds
- // 5 tets (and verts) to the vectors
- void create_packed_tets(
- const Eigen::Vector3d &min,
- const Eigen::Vector3d &max,
- std::vector<Eigen::Vector3d> &verts,
- std::vector<Eigen::Vector4i> &tets );
+ // Returns the vtx mapped from x/v and tets
+ Eigen::Vector3d get_mapped_vertex(
+ int idx,
+ const Eigen::MatrixXd *x_or_v,
+ const Eigen::MatrixXi *tets );
+
+protected:
// Returns true on success
- // Works on ptrs intead of local vars in case
- // I want to use it for something else.
bool compute_vtx_tet_mapping(
const Eigen::MatrixXd *vtx_, // embedded vertices, p x 3
Eigen::VectorXi *vtx_to_tet_, // what tet vtx is embedded in, p x 1
@@ -40,16 +36,6 @@ public:
const Eigen::MatrixXd *x_, // lattice vertices, n x 3
const Eigen::MatrixXi *tets_); // lattice elements, m x 4
- // Returns the vtx mapped from x/v and tets
- Eigen::Vector3d get_mapped_vertex(
- int idx,
- const Eigen::MatrixXd *x_or_v,
- const Eigen::MatrixXi *tets );
-// void map_to_object(
-// const Eigen::MatrixXd *x,
-// const Eigen::MatrixXi *tets,
-// float (*vertexCos)[3]);
-
}; // class Lattice
} // namespace admmpd
diff --git a/extern/softbody/src/admmpd_solver.cpp b/extern/softbody/src/admmpd_solver.cpp
index 4756cb76fac..298ba7ff173 100644
--- a/extern/softbody/src/admmpd_solver.cpp
+++ b/extern/softbody/src/admmpd_solver.cpp
@@ -32,9 +32,16 @@ bool Solver::init(
if (!data || !options)
throw std::runtime_error("init: data/options null");
+ if (V.rows()==0)
+ throw std::runtime_error("init: no input vertices");
+
data->x = V;
+ data->v.resize(V.rows(),3);
+ data->v.setZero();
data->tets = T;
- compute_matrices(options,data);
+ if (!compute_matrices(options,data))
+ return false;
+
return true;
} // end init
@@ -42,6 +49,8 @@ int Solver::solve(
const Options *options,
Data *data)
{
+ if ((int)data->A.nonZeros()==0)
+ return 0;
// Init the solve which computes
// quantaties like M_xbar and makes sure
@@ -276,12 +285,15 @@ void Solver::solve_conjugate_gradients(
} // end solve conjugate gradients
-void Solver::compute_matrices(
+bool Solver::compute_matrices(
const Options *options,
Data *data)
{
// Allocate per-vertex data
int nx = data->x.rows();
+ if (nx==0)
+ return false;
+
data->x_start = data->x;
data->M_xbar.resize(nx,3);
data->M_xbar.setZero();
@@ -298,6 +310,11 @@ void Solver::compute_matrices(
// Add per-element energies to data
std::vector<Triplet<double> > trips;
append_energies(options,data,trips);
+ if (trips.size()==0)
+ {
+ printf("**admmpd::Solver Error: No reduction coeffs\n");
+ return false;
+ }
int n_row_D = trips.back().row()+1;
double dt2 = options->timestep_s * options->timestep_s;
if (options->timestep_s <= 0)
@@ -338,6 +355,8 @@ void Solver::compute_matrices(
data->u.resize(n_row_D,3);
data->u.setZero();
+ return true;
+
} // end compute matrices
void Solver::compute_masses(
diff --git a/extern/softbody/src/admmpd_solver.h b/extern/softbody/src/admmpd_solver.h
index 0305d535f39..c690bae189c 100644
--- a/extern/softbody/src/admmpd_solver.h
+++ b/extern/softbody/src/admmpd_solver.h
@@ -107,11 +107,7 @@ protected:
const Options *options,
Data *data);
- void compute_lattice(
- const Options *options,
- Data *data);
-
- void compute_matrices(
+ bool compute_matrices(
const Options *options,
Data *data);
diff --git a/intern/softbody/admmpd_api.cpp b/intern/softbody/admmpd_api.cpp
index ade895a1971..f60097666c5 100644
--- a/intern/softbody/admmpd_api.cpp
+++ b/intern/softbody/admmpd_api.cpp
@@ -38,7 +38,7 @@
struct ADMMPDInternalData {
admmpd::Options *options;
admmpd::Data *data;
-// admmpd::Lattice *lattice;
+ admmpd::Lattice *lattice;
int in_totverts; // number of input verts
};
@@ -57,23 +57,18 @@ void admmpd_dealloc(ADMMPDInterfaceData *iface)
delete iface->data->options;
if(iface->data->data)
delete iface->data->data;
+ if(iface->data->lattice)
+ delete iface->data->lattice;
delete iface->data;
}
iface->data = NULL;
}
-int admmpd_init(ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_faces)
+static int admmpd_init_with_tetgen(
+ ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_faces,
+ Eigen::MatrixXd *V, Eigen::MatrixXi *T)
{
-
- if (iface==NULL)
- return 0;
- if (in_verts==NULL || in_faces==NULL)
- return 0;
- if (iface->mesh_totverts<=0 || iface->mesh_totfaces<=0)
- return 0;
-
- // Generate tets
TetGenRemeshData tg;
init_tetgenremeshdata(&tg);
tg.in_verts = in_verts;
@@ -83,29 +78,70 @@ int admmpd_init(ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_fa
bool success = tetgen_resmesh(&tg);
if (!success || tg.out_tottets==0)
return 0;
-
+
// Create initializer for ADMMPD
iface->totverts = tg.out_totverts;
int nv = tg.out_totverts;
int nt = tg.out_tottets;
- Eigen::MatrixXd V(nv,3);
- Eigen::MatrixXi T(nt,4);
- V.setZero();
+ V->resize(nv,3);
+ T->resize(nt,4);
+ V->setZero();
for (int i=0; i<nv; ++i)
{
for (int j=0; j<3; ++j)
{
- V(i,j) = tg.out_verts[i*3+j];
+ V->operator()(i,j) = tg.out_verts[i*3+j];
}
}
- T.setZero();
+ T->setZero();
for (int i=0; i<nt; ++i)
{
- T(i,0) = tg.out_tets[i*4+0];
- T(i,1) = tg.out_tets[i*4+1];
- T(i,2) = tg.out_tets[i*4+2];
- T(i,3) = tg.out_tets[i*4+3];
+ T->operator()(i,0) = tg.out_tets[i*4+0];
+ T->operator()(i,1) = tg.out_tets[i*4+1];
+ T->operator()(i,2) = tg.out_tets[i*4+2];
+ T->operator()(i,3) = tg.out_tets[i*4+3];
}
+ // Clean up tetgen data
+ MEM_freeN(tg.out_tets);
+ MEM_freeN(tg.out_facets);
+ MEM_freeN(tg.out_verts);
+ return 1;
+}
+
+static int admmpd_init_with_lattice(
+ ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_faces,
+ Eigen::MatrixXd *V, Eigen::MatrixXi *T)
+{
+ (void)(in_faces);
+ int nv = iface->mesh_totverts;
+ Eigen::MatrixXd in_V(nv,3);
+ for (int i=0; i<nv; ++i)
+ {
+ for (int j=0; j<3; ++j)
+ {
+ in_V(i,j) = in_verts[i*3+j];
+ }
+ }
+
+ iface->totverts = 0;
+ bool success = iface->data->lattice->generate(in_V,V,T);
+ if (success)
+ {
+ iface->totverts = V->rows();
+ return 1;
+ }
+ return 0;
+}
+
+int admmpd_init(ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_faces)
+{
+
+ if (iface==NULL)
+ return 0;
+ if (in_verts==NULL || in_faces==NULL)
+ return 0;
+ if (iface->mesh_totverts<=0 || iface->mesh_totfaces<=0)
+ return 0;
// Generate solver data
iface->data = new ADMMPDInternalData();
@@ -113,6 +149,27 @@ int admmpd_init(ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_fa
admmpd::Options *options = iface->data->options;
iface->data->data = new admmpd::Data();
admmpd::Data *data = iface->data->data;
+ iface->data->lattice = new admmpd::Lattice();
+
+ // Generate tets and vertices
+ Eigen::MatrixXd V;
+ Eigen::MatrixXi T;
+ int gen_success = 0;
+ switch (iface->init_mode)
+ {
+ default:
+ case 0:
+ gen_success = admmpd_init_with_tetgen(iface,in_verts,in_faces,&V,&T);
+ break;
+ case 1:
+ gen_success = admmpd_init_with_lattice(iface,in_verts,in_faces,&V,&T);
+ break;
+ }
+ if (!gen_success)
+ {
+ printf("**ADMMPD Failed to generate tets\n");
+ return 0;
+ }
// Initialize
bool init_success = false;
@@ -125,11 +182,13 @@ int admmpd_init(ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_fa
printf("**ADMMPD Error on init: %s\n", e.what());
}
- // Clean up tetgen data
- MEM_freeN(tg.out_tets);
- MEM_freeN(tg.out_facets);
- MEM_freeN(tg.out_verts);
- return int(init_success);
+ if (!init_success)
+ {
+ printf("**ADMMPD Failed to initialize\n");
+ return 0;
+ }
+
+ return 1;
}
void admmpd_copy_from_bodypoint(ADMMPDInterfaceData *iface, const BodyPoint *pts)
@@ -165,17 +224,24 @@ void admmpd_copy_to_bodypoint_and_object(ADMMPDInterfaceData *iface, BodyPoint *
}
}
- // TODO eventually replace with mapping. For now
- // we assume TetGen, which the first N vertices are
- // mapped one-to-one.
- if (vertexCos != NULL && i<iface->mesh_totverts)
+ if (vertexCos != NULL && iface->init_mode==0 && i<iface->mesh_totverts)
{
vertexCos[i][0] = iface->data->data->x(i,0);
vertexCos[i][1] = iface->data->data->x(i,1);
vertexCos[i][2] = iface->data->data->x(i,2);
}
+ } // end loop all verts
+
+ if (vertexCos != NULL && iface->init_mode==1)
+ {
+// Eigen::Vector3d xi = iface->data->lattice->get_mapped_vertex(
+// i, &iface->data->data->x, &iface->data->data->tets);
+// vertexCos[i][0] = xi[0];
+// vertexCos[i][1] = xi[1];
+// vertexCos[i][2] = xi[2];
}
-}
+
+} // end map ADMMPD to bodypoint and object
void admmpd_solve(ADMMPDInterfaceData *iface)
{
@@ -183,6 +249,9 @@ void admmpd_solve(ADMMPDInterfaceData *iface)
if (iface == NULL)
return;
+ if (iface->data == NULL || iface->data->options == NULL || iface->data->data == NULL)
+ return;
+
try
{
admmpd::Solver().solve(iface->data->options,iface->data->data);
diff --git a/intern/softbody/admmpd_api.h b/intern/softbody/admmpd_api.h
index 36cbe684e9e..b90a89360bd 100644
--- a/intern/softbody/admmpd_api.h
+++ b/intern/softbody/admmpd_api.h
@@ -36,6 +36,7 @@ typedef struct ADMMPDInterfaceData {
int totverts; // number of deformable verts (output)
int mesh_totverts; // number of surface mesh vertices (input)
int mesh_totfaces; // number of surface mesh faces (input)
+ int init_mode; // 0=tetgen, 1=lattice
// Solver data used internally
struct ADMMPDInternalData *data;
} ADMMPDInterfaceData;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 29e37c67a9c..38cb9f0db08 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -949,7 +949,7 @@ static void free_softbody_intern(SoftBody *sb)
sb->bpoint = NULL;
sb->bspring = NULL;
- if (sb->admmpd) {
+ if (sb->admmpd != NULL) {
admmpd_dealloc(sb->admmpd);
MEM_freeN(sb->admmpd);
sb->admmpd = NULL;
@@ -3579,6 +3579,12 @@ static void init_admmpd_interface(Object *ob, float (*vertexCos)[3])
Mesh *me = ob->data;
SoftBody *sb = ob->soft;
+ if (sb->admmpd != NULL)
+ {
+ admmpd_dealloc(sb->admmpd);
+ MEM_freeN(sb->admmpd);
+ sb->admmpd = NULL;
+ }
sb->admmpd = (ADMMPDInterfaceData*)MEM_callocN(sizeof(ADMMPDInterfaceData), "SoftBody_ADMMPD");
// Resize data
@@ -3615,6 +3621,7 @@ static void init_admmpd_interface(Object *ob, float (*vertexCos)[3])
looptri = NULL;
// Initalize solver and free tmp data
+ sb->admmpd->init_mode = 1;
admmpd_init(sb->admmpd, in_verts, in_faces);
MEM_freeN(in_verts);
MEM_freeN(in_faces);
@@ -3686,7 +3693,7 @@ void sbObjectStep_admmpd(
}
// If it's the first frame we reset the cache and data
- if (framenr == startframe) {
+ if (framenr == startframe || sb->admmpd == NULL) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
init_admmpd_interface(ob,vertexCos);
BKE_ptcache_validate(cache, framenr);
@@ -3696,13 +3703,6 @@ void sbObjectStep_admmpd(
return;
}
- // Initialize simulation data if needed.
- if (sb->admmpd == NULL)
- {
- printf("\n\n\n\n\n**ADMMPD data null!\n\n\n\n\n");
- return;
- }
-
// Read from cache
{
bool can_write_cache = DEG_is_active(depsgraph);