diff options
-rw-r--r-- | intern/softbody/admmpd_api.cpp | 154 | ||||
-rw-r--r-- | intern/softbody/admmpd_api.h | 32 | ||||
-rw-r--r-- | intern/tetgen/tetgen_api.cpp | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/softbody.c | 152 |
4 files changed, 135 insertions, 209 deletions
diff --git a/intern/softbody/admmpd_api.cpp b/intern/softbody/admmpd_api.cpp index 62dc1e7bba5..ade895a1971 100644 --- a/intern/softbody/admmpd_api.cpp +++ b/intern/softbody/admmpd_api.cpp @@ -29,6 +29,7 @@ #include "DNA_meshdata_types.h" // MVert #include "BKE_mesh_remesh_voxel.h" // TetGen #include "BKE_mesh.h" // BKE_mesh_free +#include "BKE_softbody.h" // BodyPoint #include "MEM_guardedalloc.h" // #include <iostream> @@ -38,55 +39,17 @@ struct ADMMPDInternalData { admmpd::Options *options; admmpd::Data *data; // admmpd::Lattice *lattice; + int in_totverts; // number of input verts }; - -void admmpd_alloc(ADMMPDInterfaceData *iface) -{ - if (iface==NULL) - return; - - if (iface->in_verts != NULL) - { - MEM_freeN(iface->in_verts); - iface->in_verts = NULL; - } - if (iface->in_vel != NULL) - { - MEM_freeN(iface->in_vel); - iface->in_vel = NULL; - } - if (iface->in_faces != NULL) - { - MEM_freeN(iface->in_faces); - iface->in_faces = NULL; - } - - iface->in_verts = (float *)MEM_mallocN(iface->in_totverts*3*sizeof(float), "admmpd_verts"); - iface->in_vel = (float *)MEM_mallocN(iface->in_totverts*3*sizeof(float), "admmpd_vel"); - iface->in_faces = (unsigned int *)MEM_mallocN(iface->in_totfaces*3*sizeof(unsigned int), "admmpd_faces"); -} - void admmpd_dealloc(ADMMPDInterfaceData *iface) { if (iface==NULL) return; - iface->in_totverts = 0; - if (iface->in_verts != NULL) - MEM_freeN(iface->in_verts); - if (iface->in_vel != NULL) - MEM_freeN(iface->in_vel); - - iface->in_totfaces = 0; - if (iface->in_faces != NULL) - MEM_freeN(iface->in_faces); - - iface->out_totverts = 0; - if (iface->out_verts != NULL) - MEM_freeN(iface->out_verts); - if (iface->out_vel != NULL) - MEM_freeN(iface->out_vel); + iface->totverts = 0; + iface->mesh_totverts = 0; + iface->mesh_totfaces = 0; if (iface->data) { @@ -97,52 +60,32 @@ void admmpd_dealloc(ADMMPDInterfaceData *iface) delete iface->data; } - iface->in_verts = NULL; - iface->in_vel = NULL; - iface->in_faces = NULL; - iface->out_verts = NULL; - iface->out_vel = NULL; iface->data = NULL; } -int admmpd_init(ADMMPDInterfaceData *iface) +int admmpd_init(ADMMPDInterfaceData *iface, float *in_verts, unsigned int *in_faces) { + if (iface==NULL) return 0; - if (iface->in_verts==NULL || iface->in_vel==NULL || iface->in_faces==NULL) + if (in_verts==NULL || in_faces==NULL) return 0; - if (iface->in_totverts<=0 || iface->in_totfaces<=0) + if (iface->mesh_totverts<=0 || iface->mesh_totfaces<=0) return 0; // Generate tets TetGenRemeshData tg; init_tetgenremeshdata(&tg); - tg.in_verts = iface->in_verts; - tg.in_totverts = iface->in_totverts; - tg.in_faces = iface->in_faces; - tg.in_totfaces = iface->in_totfaces; + tg.in_verts = in_verts; + tg.in_totverts = iface->mesh_totverts; + tg.in_faces = in_faces; + tg.in_totfaces = iface->mesh_totfaces; bool success = tetgen_resmesh(&tg); if (!success || tg.out_tottets==0) return 0; - // Resize data - iface->out_totverts = tg.out_totverts; - if (iface->out_verts != NULL) - { - MEM_freeN(iface->out_verts); - iface->out_verts = NULL; - } - if (iface->out_vel != NULL) - { - MEM_freeN(iface->out_vel); - iface->out_vel = NULL; - } - iface->out_verts = (float *)MEM_callocN( - iface->out_totverts*3*sizeof(float), "ADMMPD_out_verts"); - iface->out_vel = (float *)MEM_callocN( - iface->out_totverts*3*sizeof(float), "ADMMPD_out_vel"); - // Create initializer for ADMMPD + iface->totverts = tg.out_totverts; int nv = tg.out_totverts; int nt = tg.out_tottets; Eigen::MatrixXd V(nv,3); @@ -153,8 +96,6 @@ int admmpd_init(ADMMPDInterfaceData *iface) for (int j=0; j<3; ++j) { V(i,j) = tg.out_verts[i*3+j]; - iface->out_verts[i*3+j] = tg.out_verts[i*3+j]; - iface->out_vel[i*3+j] = 0; } } T.setZero(); @@ -191,60 +132,63 @@ int admmpd_init(ADMMPDInterfaceData *iface) return int(init_success); } -void admmpd_solve(ADMMPDInterfaceData *iface) +void admmpd_copy_from_bodypoint(ADMMPDInterfaceData *iface, const BodyPoint *pts) { - if (iface == NULL) + if (iface == NULL || pts == NULL) return; - // Whatever is in out_verts and out_vel needs - // to be mapped to internal data, as it's used as input - // when reading from cached data. - int nv = iface->out_totverts; - for (int i=0; i<nv; ++i) + for (int i=0; i<iface->totverts; ++i) { - for (int j=0; j<3; ++j) + const BodyPoint *pt = &pts[i]; + for(int j=0; j<3; ++j) { - iface->data->data->x(i,j) = iface->out_verts[i*3+j]; - iface->data->data->v(i,j) = iface->out_vel[i*3+j]; + iface->data->data->x(i,j)=pt->pos[j]; + iface->data->data->v(i,j)=pt->vec[j]; } } +} - try +void admmpd_copy_to_bodypoint_and_object(ADMMPDInterfaceData *iface, BodyPoint *pts, float (*vertexCos)[3]) +{ + if (iface == NULL) + return; + + for (int i=0; i<iface->totverts; ++i) { - admmpd::Solver().solve(iface->data->options,iface->data->data); - for (int i=0; i<iface->data->data->x.rows(); ++i) + if (pts != NULL) { - for (int j=0; j<3; ++j) + BodyPoint *pt = &pts[i]; + for(int j=0; j<3; ++j) { - iface->out_verts[i*3+j] = iface->data->data->x(i,j); - iface->out_vel[i*3+j] = iface->data->data->v(i,j); + pt->pos[j] = iface->data->data->x(i,j); + pt->vec[j] = iface->data->data->v(i,j); } } - } - catch(const std::exception &e) - { - printf("**ADMMPD Error on solve: %s\n", e.what()); + + // 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) + { + 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); + } } } -void admmpd_get_vertices(ADMMPDInterfaceData *iface, float (*vertexCos)[3], int numVerts) +void admmpd_solve(ADMMPDInterfaceData *iface) { + if (iface == NULL) return; - if (numVerts != iface->in_totverts || numVerts > iface->out_totverts) + try { - printf("**ADMMPD TODO: PROPER VERTEX MAPPINGS\n"); - return; + admmpd::Solver().solve(iface->data->options,iface->data->data); } - // TODO double check this, but I believe the first n verts - // created by tetgen are the same as the input. I hope. We'll find out I guess. - // If not, this function will be a placeholder for the mapping that - // will have to occur. - for (int i=0; i<numVerts; ++i) + catch(const std::exception &e) { - vertexCos[i][0] = iface->out_verts[i*3+0]; - vertexCos[i][1] = iface->out_verts[i*3+1]; - vertexCos[i][2] = iface->out_verts[i*3+2]; + printf("**ADMMPD Error on solve: %s\n", e.what()); } }
\ No newline at end of file diff --git a/intern/softbody/admmpd_api.h b/intern/softbody/admmpd_api.h index f90f75a0405..36cbe684e9e 100644 --- a/intern/softbody/admmpd_api.h +++ b/intern/softbody/admmpd_api.h @@ -29,40 +29,40 @@ extern "C" { #endif typedef struct ADMMPDInterfaceData { - float *in_verts; - float *in_vel; - unsigned int *in_faces; - int in_totfaces; - int in_totverts; - // Num output verts might be different than num input verts. + // totverts is usually different than mesh_totverts. // This is due to the lattice/tetmesh that is generated // in init. You can use them as input if reading from cache, // as they will be copied to internal solver data before admmpd_solve. - float *out_verts; - float *out_vel; - int out_totverts; + 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) // Solver data used internally struct ADMMPDInternalData *data; } ADMMPDInterfaceData; -// Allocates ADMMPDInterfaceData, using in_totfaces and in_totverts. -// Does not allocate solver data, which is created on admmpd_init -void admmpd_alloc(ADMMPDInterfaceData*); +// SoftBody bodypoint (contains pos,vec) +typedef struct BodyPoint BodyPoint; // Clears all solver data and ADMMPDInterfaceData void admmpd_dealloc(ADMMPDInterfaceData*); // Initializes solver and allocates internal data -int admmpd_init(ADMMPDInterfaceData*); +int admmpd_init(ADMMPDInterfaceData*, float *in_verts, unsigned int *in_faces); + +// Copies BodyPoint data (from SoftBody) +// to internal vertex position and velocity +void admmpd_copy_from_bodypoint(ADMMPDInterfaceData*, const BodyPoint *pts); + +// Copies internal vertex position and velocity data +// to BodyPoints (from SoftBody) AND surface mesh vertices. +// If pts or vertexCos is null, its skipped +void admmpd_copy_to_bodypoint_and_object(ADMMPDInterfaceData*, BodyPoint *pts, float (*vertexCos)[3]); // Copies out_verts and out_verts to internal data // Performs solve over the time step // Copies internal data to out_verts and out_vel void admmpd_solve(ADMMPDInterfaceData*); -// Copies ADMMPDInterfaceData::out_ to vertexCos -void admmpd_get_vertices(ADMMPDInterfaceData*, float (*vertexCos)[3], int numVerts); - #ifdef __cplusplus } #endif diff --git a/intern/tetgen/tetgen_api.cpp b/intern/tetgen/tetgen_api.cpp index 50b8201caac..33115411d82 100644 --- a/intern/tetgen/tetgen_api.cpp +++ b/intern/tetgen/tetgen_api.cpp @@ -101,14 +101,14 @@ static void make_tetgenio( bool tetgen_resmesh(TetGenRemeshData *tg) { // float maxvol = compute_maxvol(tg->in_verts, tg->in_faces, tg->in_totfaces); -// float quality = 1.4; + float quality = 1.4; // Set up the switches std::stringstream switches; // switches << "Q"; // quiet // switches << "a" << maxvol; -// if (quality>0) -// switches << "q" << quality; + if (quality>0) + switches << "q" << quality; tetgenio in; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 026acd06b04..29e37c67a9c 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -856,14 +856,6 @@ static void renew_softbody(Scene *scene, Object *ob, int totpoint, int totspring sb->bspring = MEM_mallocN(totspring * sizeof(BodySpring), "bodyspring"); } - if (ob->type == OB_MESH) - { - const Mesh *me = ob->data; - sb->admmpd->in_totfaces = poly_to_tri_count(me->totpoly, me->totloop); - sb->admmpd->in_totverts = me->totvert; - admmpd_alloc(sb->admmpd); - } - /* initialize BodyPoint array */ for (i = 0; i < totpoint; i++) { BodyPoint *bp = &sb->bpoint[i]; @@ -3096,6 +3088,12 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, { SoftBody *sb = ob->soft; if (sb) { + int sb_totpt = sb->totpoint; + if(sb_totpt < numVerts) + { + printf("\n\n\n\nsoftbody_to_object ERROR: BAD SIZE TOTPOINT\n\n\n\n\n"); + } + BodyPoint *bp = sb->bpoint; int a; if (sb->solverflags & SBSO_ESTIMATEIPO) { @@ -3547,22 +3545,7 @@ static void sbStoreLastFrame(struct Depsgraph *depsgraph, Object *object, float object_orig->soft->last_frame = framenr; } -static void admmpd_resize_softbody(Object *ob, int totpoint) -{ - if (totpoint<=0) - return; - - SoftBody *sb = ob->soft; - if (sb->totpoint && sb->bpoint != NULL) - { - MEM_freeN(sb->bpoint); - sb->bpoint = NULL; - } - sb->totpoint = totpoint; - sb->totspring = 0; - sb->bpoint = MEM_mallocN(totpoint * sizeof(BodyPoint), "bodypoint"); -} - +/* static void admmpd_copy_to_softbody(Object *ob) { SoftBody *sb = ob->soft; @@ -3570,22 +3553,23 @@ static void admmpd_copy_to_softbody(Object *ob) if (admmpd == NULL) return; - if (sb->totpoint != admmpd->out_totverts) + if (sb->totpoint != admmpd->totverts) { printf("**admm_copy_to_softbody error: DOF missmatch"); return; } - for (int i=0; i<admmpd->out_totverts; ++i) + for (int i=0; i<admmpd->totverts; ++i) { BodyPoint *pt = &sb->bpoint[i]; for (int j=0; j<3; ++j) { - pt->pos[j] = admmpd->out_verts[i*3+j]; - pt->vec[j] = admmpd->out_vel[i*3+j]; + pt->pos[j] = admmpd->verts[i*3+j]; + pt->vec[j] = admmpd->vel[i*3+j]; } } } +*/ static void init_admmpd_interface(Object *ob, float (*vertexCos)[3]) { @@ -3595,15 +3579,16 @@ static void init_admmpd_interface(Object *ob, float (*vertexCos)[3]) Mesh *me = ob->data; SoftBody *sb = ob->soft; - sb->admmpd = MEM_callocN(sizeof(ADMMPDInterfaceData), "SoftBody_ADMMPD"); + sb->admmpd = (ADMMPDInterfaceData*)MEM_callocN(sizeof(ADMMPDInterfaceData), "SoftBody_ADMMPD"); // Resize data - admmpd_dealloc(sb->admmpd); - sb->admmpd->in_totfaces = poly_to_tri_count(me->totpoly, me->totloop); - sb->admmpd->in_totverts = me->totvert; - admmpd_alloc(sb->admmpd); + int totfaces = poly_to_tri_count(me->totpoly, me->totloop); + unsigned int *in_faces = (unsigned int*)MEM_mallocN(sizeof(unsigned int)*totfaces*3, __func__); + float *in_verts = (float*)MEM_mallocN(sizeof(float)*me->totvert*3, __func__); + sb->admmpd->mesh_totverts = me->totvert; + sb->admmpd->mesh_totfaces = totfaces; - // Initialize input data + // Initialize input vertices for (int i=0; i<me->totvert; ++i) { // Local to global coordinates @@ -3613,50 +3598,40 @@ static void init_admmpd_interface(Object *ob, float (*vertexCos)[3]) vi[2] = vertexCos[i][2]; mul_m4_v3(ob->obmat, vi); for (int j=0; j<3; ++j) - { - sb->admmpd->in_verts[i*3+j] = vi[j]; - sb->admmpd->in_vel[i*3+j] = 0; - } + in_verts[i*3+j] = vi[j]; } + + // Initialize input faces MLoopTri *looptri, *lt; - looptri = lt = MEM_mallocN(sizeof(*looptri)*sb->admmpd->in_totfaces, __func__); + looptri = lt = (MLoopTri *)MEM_mallocN(sizeof(*looptri)*totfaces, __func__); BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); - for (int i=0; i<sb->admmpd->in_totfaces; ++i, ++lt) + for (int i=0; i<totfaces; ++i, ++lt) { - sb->admmpd->in_faces[i*3+0] = me->mloop[lt->tri[0]].v; - sb->admmpd->in_faces[i*3+1] = me->mloop[lt->tri[1]].v; - sb->admmpd->in_faces[i*3+2] = me->mloop[lt->tri[2]].v; + in_faces[i*3+0] = me->mloop[lt->tri[0]].v; + in_faces[i*3+1] = me->mloop[lt->tri[1]].v; + in_faces[i*3+2] = me->mloop[lt->tri[2]].v; } MEM_freeN(looptri); looptri = NULL; - // Initalize solver - admmpd_init(sb->admmpd); + // Initalize solver and free tmp data + admmpd_init(sb->admmpd, in_verts, in_faces); + MEM_freeN(in_verts); + MEM_freeN(in_faces); // Set up softbody to store defo verts - int num_defo_verts = sb->admmpd->out_totverts; - admmpd_resize_softbody(ob,num_defo_verts); - admmpd_copy_to_softbody(ob); -} - -static void admmpd_update_from_softbody(Object *ob) -{ - SoftBody *sb = ob->soft; - ADMMPDInterfaceData *admmpd = sb->admmpd; - if (sb->totpoint != admmpd->out_totverts) - { - printf("**admmpd_update_from_softbody Error: DOF missmatch"); - return; - } - BodyPoint *bp = sb->bpoint; - for (int i=0; i<sb->totpoint; ++i, ++bp) - { - for (int j=0; j<3; ++j) - { - admmpd->out_verts[i*3+j] = bp->pos[j]; - admmpd->out_vel[i*3+j] = bp->vec[j]; + if (sb->admmpd->totverts > 0) { + if (sb->totpoint && sb->bpoint != NULL) + { // Free old data if exists + MEM_freeN(sb->bpoint); + sb->bpoint = NULL; } + sb->totpoint = sb->admmpd->totverts; + sb->totspring = 0; + sb->bpoint = MEM_mallocN(sb->totpoint * sizeof(BodyPoint), "bodypoint"); } + + admmpd_copy_to_bodypoint_and_object(sb->admmpd,sb->bpoint,NULL); } /* simulates one step. framenr is in frames */ @@ -3678,19 +3653,21 @@ void sbObjectStep_admmpd( PTCacheID pid; int framenr = (int)cfra; int framedelta = framenr - cache->simframe; - int startframe = 1; - int endframe = 250; - float timescale = 1.f; + int startframe = -1; + int endframe = -1; + float timescale = 0.f; BKE_ptcache_id_from_softbody(&pid, ob, sb); BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); - - // Reset simulation - bool reset_sim = - sb->admmpd == NULL || - sb->admmpd->in_totverts != numVerts; + // BKE_ptcache_validate: + // sets flag that simulation is valid (|=) + // and sets simframe to framenr + // Calling BKE_ptcache_id_reset calls + // free_softbody_intern + // Reset cache - if (reset_sim) + if (sb->admmpd == NULL || + sb->admmpd->mesh_totverts != numVerts) { cache->flag |= PTCACHE_OUTDATED; BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); @@ -3708,10 +3685,6 @@ void sbObjectStep_admmpd( framenr = endframe; } - // Initialize simulation data if needed. - if (sb->admmpd == NULL) - init_admmpd_interface(ob,vertexCos); - // If it's the first frame we reset the cache and data if (framenr == startframe) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); @@ -3719,19 +3692,28 @@ void sbObjectStep_admmpd( BKE_ptcache_validate(cache, framenr); cache->flag &= ~PTCACHE_REDO_NEEDED; sb->last_frame = framenr; + sbStoreLastFrame(depsgraph, ob, framenr); 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); bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED) && can_write_cache; + // Copies cache into softbody bpoint int cache_result = BKE_ptcache_read(&pid, (float)framenr + scene->r.subframe, can_simulate); - - if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED || - (!can_simulate && cache_result == PTCACHE_READ_OLD)) { + if (cache_result == PTCACHE_READ_EXACT || + cache_result == PTCACHE_READ_INTERPOLATED || + (!can_simulate && cache_result == PTCACHE_READ_OLD)) { softbody_to_object(ob, vertexCos, numVerts, sb->local); BKE_ptcache_validate(cache, framenr); if (cache_result == PTCACHE_READ_INTERPOLATED && @@ -3750,6 +3732,7 @@ void sbObjectStep_admmpd( } return; } + if (!can_simulate) return; } // end read from cache @@ -3762,10 +3745,9 @@ void sbObjectStep_admmpd( // Update ADMMPD interface variables from cache // and perform a solve. - admmpd_update_from_softbody(ob); + admmpd_copy_from_bodypoint(sb->admmpd,sb->bpoint); admmpd_solve(sb->admmpd); - admmpd_get_vertices(sb->admmpd,vertexCos,numVerts); - admmpd_copy_to_softbody(ob); + admmpd_copy_to_bodypoint_and_object(sb->admmpd,sb->bpoint,vertexCos); // Write cache BKE_ptcache_validate(cache, framenr); |