Replace MFace w/ vert-tri's for collision modifier

Note that the collision modifier doesn't have any use for Loop indices,
so to avoid duplicating the loop array too,
MVertTri has been added which simply stores vertex indices (runtime only).
This commit is contained in:
2015-07-31 14:00:07 +10:00
parent 6b7313be94
commit c582e186d9
19 changed files with 551 additions and 826 deletions

View File

@@ -613,6 +613,7 @@ void DM_ensure_tessface(DerivedMesh *dm);
void DM_ensure_looptri_data(DerivedMesh *dm);
void DM_ensure_looptri(DerivedMesh *dm);
void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num);
void DM_update_tessface_data(DerivedMesh *dm);
void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate);

View File

@@ -86,15 +86,15 @@ typedef struct ClothSolverResult {
typedef struct Cloth {
struct ClothVertex *verts; /* The vertices that represent this cloth. */
struct LinkNode *springs; /* The springs connecting the mesh. */
unsigned int numverts; /* The number of verts == m * n. */
unsigned int numsprings; /* The count of springs. */
unsigned int numfaces;
unsigned int mvert_num; /* The number of verts == m * n. */
unsigned int tri_num;
unsigned char old_solver_type; /* unused, only 1 solver here */
unsigned char pad2;
short pad3;
struct BVHTree *bvhtree; /* collision tree for this cloth object */
struct BVHTree *bvhselftree; /* collision tree for this cloth object */
struct MFace *mfaces;
struct MVertTri *tri;
struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */
struct EdgeSet *edgeset; /* used for selfcollisions */
int last_frame, pad4;
@@ -233,8 +233,8 @@ void clothModifier_do (struct ClothModifierData *clmd, struct Scene *scene, stru
int cloth_uses_vgroup(struct ClothModifierData *clmd);
// needed for collision.c
void bvhtree_update_from_cloth (struct ClothModifierData *clmd, int moving );
void bvhselftree_update_from_cloth (struct ClothModifierData *clmd, int moving );
void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
// needed for button_object.c
void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr );

View File

@@ -49,6 +49,7 @@ struct MFace;
struct MVert;
struct Object;
struct Scene;
struct MVertTri;
////////////////////////////////////////
// used for collisions in collision.c
@@ -124,8 +125,15 @@ FaceCollPair;
// used in modifier.c from collision.c
/////////////////////////////////////////////////
BVHTree *bvhtree_build_from_mvert(struct MFace *mfaces, unsigned int numfaces, struct MVert *x, unsigned int numverts, float epsilon);
void bvhtree_update_from_mvert(BVHTree *bvhtree, struct MFace *faces, int numfaces, struct MVert *x, struct MVert *xnew, int numverts, int moving);
BVHTree *bvhtree_build_from_mvert(
const struct MVert *mvert,
const struct MVertTri *tri, int tri_num,
float epsilon);
void bvhtree_update_from_mvert(
BVHTree *bvhtree,
const struct MVert *mvert, const struct MVert *mvert_moving,
const struct MVertTri *tri, int tri_num,
bool moving);
/////////////////////////////////////////////////

View File

@@ -179,7 +179,7 @@ typedef struct ParticleBillboardData {
typedef struct ParticleCollisionElement {
/* pointers to original data */
float *x[4], *v[4];
float *x[3], *v[3];
/* values interpolated from original data*/
float x0[3], x1[3], x2[3], p[3];

View File

@@ -493,6 +493,16 @@ void DM_ensure_looptri(DerivedMesh *dm)
}
}
void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num)
{
int i;
for (i = 0; i < looptri_num; i++) {
verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
}
}
/* Update tessface CD data from loop/poly ones. Needed when not retessellating after modstack evaluation. */
/* NOTE: Assumes dm has valid tessellated data! */
void DM_update_tessface_data(DerivedMesh *dm)

View File

@@ -137,7 +137,6 @@ static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float eps
BVHTree *bvhtree;
Cloth *cloth;
ClothVertex *verts;
float co[12];
if (!clmd)
return NULL;
@@ -149,21 +148,22 @@ static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float eps
verts = cloth->verts;
// in the moment, return zero if no faces there
if (!cloth->numverts)
/* in the moment, return zero if no faces there */
if (!cloth->mvert_num)
return NULL;
// create quadtree with k=26
bvhtree = BLI_bvhtree_new(cloth->numverts, epsilon, 4, 6);
/* create quadtree with k=26 */
bvhtree = BLI_bvhtree_new(cloth->mvert_num, epsilon, 4, 6);
// fill tree
for (i = 0; i < cloth->numverts; i++, verts++) {
copy_v3_v3(&co[0*3], verts->xold);
/* fill tree */
for (i = 0; i < cloth->mvert_num; i++, verts++) {
const float *co;
co = verts->xold;
BLI_bvhtree_insert(bvhtree, i, co, 1);
}
// balance tree
/* balance tree */
BLI_bvhtree_balance(bvhtree);
return bvhtree;
@@ -175,8 +175,7 @@ static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon
BVHTree *bvhtree;
Cloth *cloth;
ClothVertex *verts;
MFace *mfaces;
float co[12];
const MVertTri *vt;
if (!clmd)
return NULL;
@@ -187,25 +186,24 @@ static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon
return NULL;
verts = cloth->verts;
mfaces = cloth->mfaces;
vt = cloth->tri;
/* in the moment, return zero if no faces there */
if (!cloth->numfaces)
if (!cloth->tri_num)
return NULL;
/* create quadtree with k=26 */
bvhtree = BLI_bvhtree_new(cloth->numfaces, epsilon, 4, 26);
bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26);
/* fill tree */
for (i = 0; i < cloth->numfaces; i++, mfaces++) {
copy_v3_v3(&co[0*3], verts[mfaces->v1].xold);
copy_v3_v3(&co[1*3], verts[mfaces->v2].xold);
copy_v3_v3(&co[2*3], verts[mfaces->v3].xold);
for (i = 0; i < cloth->tri_num; i++, vt++) {
float co[3][3];
if (mfaces->v4)
copy_v3_v3(&co[3*3], verts[mfaces->v4].xold);
copy_v3_v3(co[0], verts[vt->tri[0]].xold);
copy_v3_v3(co[1], verts[vt->tri[1]].xold);
copy_v3_v3(co[2], verts[vt->tri[2]].xold);
BLI_bvhtree_insert(bvhtree, i, co, (mfaces->v4 ? 4 : 3));
BLI_bvhtree_insert(bvhtree, i, co[0], 3);
}
/* balance tree */
@@ -214,90 +212,87 @@ static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon
return bvhtree;
}
void bvhtree_update_from_cloth(ClothModifierData *clmd, int moving)
void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
{
unsigned int i = 0;
Cloth *cloth = clmd->clothObject;
BVHTree *bvhtree = cloth->bvhtree;
ClothVertex *verts = cloth->verts;
MFace *mfaces;
float co[12], co_moving[12];
bool ret = false;
const MVertTri *vt;
if (!bvhtree)
return;
mfaces = cloth->mfaces;
vt = cloth->tri;
// update vertex position in bvh tree
if (verts && mfaces) {
for (i = 0; i < cloth->numfaces; i++, mfaces++) {
copy_v3_v3(&co[0*3], verts[mfaces->v1].txold);
copy_v3_v3(&co[1*3], verts[mfaces->v2].txold);
copy_v3_v3(&co[2*3], verts[mfaces->v3].txold);
if (mfaces->v4)
copy_v3_v3(&co[3*3], verts[mfaces->v4].txold);
// copy new locations into array
/* update vertex position in bvh tree */
if (verts && vt) {
for (i = 0; i < cloth->tri_num; i++, vt++) {
float co[3][3], co_moving[3][3];
bool ret;
copy_v3_v3(co[0], verts[vt->tri[0]].txold);
copy_v3_v3(co[1], verts[vt->tri[1]].txold);
copy_v3_v3(co[2], verts[vt->tri[2]].txold);
/* copy new locations into array */
if (moving) {
// update moving positions
copy_v3_v3(&co_moving[0*3], verts[mfaces->v1].tx);
copy_v3_v3(&co_moving[1*3], verts[mfaces->v2].tx);
copy_v3_v3(&co_moving[2*3], verts[mfaces->v3].tx);
if (mfaces->v4)
copy_v3_v3(&co_moving[3*3], verts[mfaces->v4].tx);
ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, (mfaces->v4 ? 4 : 3));
/* update moving positions */
copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx);
ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
}
else {
ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, (mfaces->v4 ? 4 : 3));
ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
}
// check if tree is already full
if (!ret)
/* check if tree is already full */
if (ret == false) {
break;
}
}
BLI_bvhtree_update_tree(bvhtree);
}
}
void bvhselftree_update_from_cloth(ClothModifierData *clmd, int moving)
void bvhselftree_update_from_cloth(ClothModifierData *clmd, bool moving)
{
unsigned int i = 0;
Cloth *cloth = clmd->clothObject;
BVHTree *bvhtree = cloth->bvhselftree;
ClothVertex *verts = cloth->verts;
MFace *mfaces;
float co[12], co_moving[12];
int ret = 0;
const MVertTri *vt;
if (!bvhtree)
return;
mfaces = cloth->mfaces;
// update vertex position in bvh tree
if (verts && mfaces) {
for (i = 0; i < cloth->numverts; i++, verts++) {
copy_v3_v3(&co[0*3], verts->txold);
vt = cloth->tri;
// copy new locations into array
/* update vertex position in bvh tree */
if (verts && vt) {
for (i = 0; i < cloth->mvert_num; i++, verts++) {
const float *co, *co_moving;
bool ret;
co = verts->txold;
/* copy new locations into array */
if (moving) {
// update moving positions
copy_v3_v3(&co_moving[0*3], verts->tx);
/* update moving positions */
co_moving = verts->tx;
ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
}
else {
ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
}
// check if tree is already full
if (!ret)
/* check if tree is already full */
if (ret == false) {
break;
}
}
BLI_bvhtree_update_tree(bvhtree);
@@ -360,7 +355,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
mvert = result->getVertArray(result);
/* force any pinned verts to their constrained location. */
for (i = 0; i < clmd->clothObject->numverts; i++, verts++) {
for (i = 0; i < clmd->clothObject->mvert_num; i++, verts++) {
/* save the previous position. */
copy_v3_v3(verts->xold, verts->xconst);
copy_v3_v3(verts->txold, verts->x);
@@ -462,7 +457,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
clmd->sim_parms->timescale= timescale;
if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->numverts)) {
if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) {
clmd->sim_parms->reset = 0;
cache->flag |= PTCACHE_OUTDATED;
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
@@ -562,7 +557,7 @@ void cloth_free_modifier(ClothModifierData *clmd )
MEM_freeN ( cloth->verts );
cloth->verts = NULL;
cloth->numverts = 0;
cloth->mvert_num = 0;
// Free the springs.
if ( cloth->springs != NULL ) {
@@ -589,9 +584,9 @@ void cloth_free_modifier(ClothModifierData *clmd )
BLI_bvhtree_free ( cloth->bvhselftree );
// we save our faces for collision objects
if ( cloth->mfaces )
MEM_freeN ( cloth->mfaces );
if (cloth->tri)
MEM_freeN(cloth->tri);
if (cloth->edgeset)
BLI_edgeset_free(cloth->edgeset);
@@ -628,7 +623,7 @@ void cloth_free_modifier_extern(ClothModifierData *clmd )
MEM_freeN ( cloth->verts );
cloth->verts = NULL;
cloth->numverts = 0;
cloth->mvert_num = 0;
// Free the springs.
if ( cloth->springs != NULL ) {
@@ -655,8 +650,8 @@ void cloth_free_modifier_extern(ClothModifierData *clmd )
BLI_bvhtree_free ( cloth->bvhselftree );
// we save our faces for collision objects
if ( cloth->mfaces )
MEM_freeN ( cloth->mfaces );
if (cloth->tri)
MEM_freeN(cloth->tri);
if (cloth->edgeset)
BLI_edgeset_free(cloth->edgeset);
@@ -690,7 +685,7 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte
/* inverse matrix is not uptodate... */
invert_m4_m4(ob->imat, ob->obmat);
for (i = 0; i < cloth->numverts; i++) {
for (i = 0; i < cloth->mvert_num; i++) {
copy_v3_v3 (vertexCos[i], cloth->verts[i].x);
mul_m4_v3(ob->imat, vertexCos[i]); /* cloth is in global coords */
}
@@ -721,7 +716,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
int j = 0;
MDeformVert *dvert = NULL;
Cloth *clothObj = NULL;
int numverts;
int mvert_num;
/* float goalfac = 0; */ /* UNUSED */
ClothVertex *verts = NULL;
@@ -729,12 +724,12 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
clothObj = clmd->clothObject;
numverts = dm->getNumVerts (dm);
mvert_num = dm->getNumVerts(dm);
verts = clothObj->verts;
if (cloth_uses_vgroup(clmd)) {
for ( i = 0; i < numverts; i++, verts++ ) {
for (i = 0; i < mvert_num; i++, verts++) {
/* Reset Goal values to standard */
if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
@@ -831,6 +826,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
if ( !dm )
return 0;
DM_ensure_looptri(dm);
cloth_from_mesh ( clmd, dm );
// create springs
@@ -883,6 +879,9 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
// has to be happen before springs are build!
cloth_apply_vgroup (clmd, dm);
/* springs yse MFace currently */
DM_ensure_tessface(dm);
if ( !cloth_build_springs ( clmd, dm ) ) {
cloth_free_modifier ( clmd );
modifier_setError(&(clmd->modifier), "Cannot build springs");
@@ -915,32 +914,31 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
{
unsigned int numverts = dm->getNumVerts (dm);
unsigned int numfaces = dm->getNumTessFaces (dm);
MFace *mface = dm->getTessFaceArray(dm);
unsigned int i = 0;
const MLoop *mloop = dm->getLoopArray(dm);
const MLoopTri *looptri = dm->getLoopTriArray(dm);
const unsigned int mvert_num = dm->getNumVerts(dm);
const unsigned int looptri_num = dm->getNumLoopTri(dm);
/* Allocate our vertices. */
clmd->clothObject->numverts = numverts;
clmd->clothObject->verts = MEM_callocN ( sizeof ( ClothVertex ) * clmd->clothObject->numverts, "clothVertex" );
if ( clmd->clothObject->verts == NULL ) {
cloth_free_modifier ( clmd );
clmd->clothObject->mvert_num = mvert_num;
clmd->clothObject->verts = MEM_callocN(sizeof(ClothVertex) * clmd->clothObject->mvert_num, "clothVertex");
if (clmd->clothObject->verts == NULL) {
cloth_free_modifier(clmd);
modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts");
printf("cloth_free_modifier clmd->clothObject->verts\n");
return;
}
// save face information
clmd->clothObject->numfaces = numfaces;
clmd->clothObject->mfaces = MEM_callocN ( sizeof ( MFace ) * clmd->clothObject->numfaces, "clothMFaces" );
if ( clmd->clothObject->mfaces == NULL ) {
cloth_free_modifier ( clmd );
modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->mfaces");
printf("cloth_free_modifier clmd->clothObject->mfaces\n");
/* save face information */
clmd->clothObject->tri_num = looptri_num;
clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
if (clmd->clothObject->tri == NULL) {
cloth_free_modifier(clmd);
modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri");
printf("cloth_free_modifier clmd->clothObject->looptri\n");
return;
}
for ( i = 0; i < numfaces; i++ )
memcpy ( &clmd->clothObject->mfaces[i], &mface[i], sizeof ( MFace ) );
DM_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
/* Free the springs since they can't be correct if the vertices
* changed.
@@ -997,11 +995,11 @@ int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int
return 0;
}
static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int numverts)
static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
{
if (edgelist) {
unsigned int i;
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
BLI_linklist_free(edgelist[i].list, NULL);
}
@@ -1024,7 +1022,7 @@ static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist)
cloth->springs = NULL;
}
cloth_free_edgelist(edgelist, cloth->numverts);
cloth_free_edgelist(edgelist, cloth->mvert_num);
if (cloth->edgeset) {
BLI_edgeset_free(cloth->edgeset);
@@ -1253,7 +1251,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0;
unsigned int i = 0;
unsigned int numverts = (unsigned int)dm->getNumVerts (dm);
unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
unsigned int numedges = (unsigned int)dm->getNumEdges (dm);
unsigned int numfaces = (unsigned int)dm->getNumTessFaces (dm);
float shrink_factor;
@@ -1276,7 +1274,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
cloth->springs = NULL;
cloth->edgeset = NULL;
edgelist = MEM_callocN(sizeof(*edgelist) * numverts, "cloth_edgelist_alloc" );
edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" );
if (!edgelist)
return 0;
@@ -1321,7 +1319,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
if (struct_springs > 0)
clmd->sim_parms->avg_spring_len /= struct_springs;
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
}
@@ -1511,7 +1509,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
cloth->numsprings = struct_springs + shear_springs + bend_springs;
cloth_free_edgelist(edgelist, numverts);
cloth_free_edgelist(edgelist, mvert_num);
#if 0
if (G.debug_value > 0)

View File

@@ -71,82 +71,92 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
float tv[3] = {0, 0, 0};
unsigned int i = 0;
for ( i = 0; i < collmd->numverts; i++ ) {
for (i = 0; i < collmd->mvert_num; i++) {
sub_v3_v3v3(tv, collmd->xnew[i].co, collmd->x[i].co);
VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep);
VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step);
sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co);
}
bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 );
bvhtree_update_from_mvert(
collmd->bvhtree, collmd->current_x, collmd->current_xnew,
collmd->tri, collmd->tri_num, true);
}
BVHTree *bvhtree_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int UNUSED(numverts), float epsilon )
BVHTree *bvhtree_build_from_mvert(
const MVert *mvert,
const struct MVertTri *tri, int tri_num,
float epsilon)
{
BVHTree *tree;
float co[12];
unsigned int i;
MFace *tface = mfaces;
const MVertTri *vt;
int i;
tree = BLI_bvhtree_new ( numfaces*2, epsilon, 4, 26 );
tree = BLI_bvhtree_new(tri_num, epsilon, 4, 26);
// fill tree
for ( i = 0; i < numfaces; i++, tface++ ) {
copy_v3_v3 ( &co[0*3], x[tface->v1].co );
copy_v3_v3 ( &co[1*3], x[tface->v2].co );
copy_v3_v3 ( &co[2*3], x[tface->v3].co );
if ( tface->v4 )
copy_v3_v3 ( &co[3*3], x[tface->v4].co );
/* fill tree */
for (i = 0, vt = tri; i < tri_num; i++, vt++) {
float co[3][3];
BLI_bvhtree_insert ( tree, i, co, ( mfaces->v4 ? 4 : 3 ) );
copy_v3_v3(co[0], mvert[vt->tri[0]].co);
copy_v3_v3(co[1], mvert[vt->tri[1]].co);
copy_v3_v3(co[2], mvert[vt->tri[2]].co);
BLI_bvhtree_insert(tree, i, co[0], 3);
}
// balance tree
BLI_bvhtree_balance ( tree );
/* balance tree */
BLI_bvhtree_balance(tree);
return tree;
}
void bvhtree_update_from_mvert(BVHTree *bvhtree, MFace *faces, int numfaces, MVert *x, MVert *xnew, int UNUSED(numverts), int moving )
void bvhtree_update_from_mvert(
BVHTree *bvhtree,
const MVert *mvert, const MVert *mvert_moving,
const MVertTri *tri, int tri_num,
bool moving)
{
const MVertTri *vt;
int i;
MFace *mfaces = faces;
float co[12], co_moving[12];
bool ret = false;
if ( !bvhtree )
if ((bvhtree == NULL) || (mvert == NULL)) {
return;
}
if ( x ) {
for ( i = 0; i < numfaces; i++, mfaces++ ) {
copy_v3_v3 ( &co[0*3], x[mfaces->v1].co );
copy_v3_v3 ( &co[1*3], x[mfaces->v2].co );
copy_v3_v3 ( &co[2*3], x[mfaces->v3].co );
if ( mfaces->v4 )
copy_v3_v3 ( &co[3*3], x[mfaces->v4].co );
if (mvert_moving == NULL) {
moving = false;
}
// copy new locations into array
if ( moving && xnew ) {
// update moving positions
copy_v3_v3 ( &co_moving[0*3], xnew[mfaces->v1].co );
copy_v3_v3 ( &co_moving[1*3], xnew[mfaces->v2].co );
copy_v3_v3 ( &co_moving[2*3], xnew[mfaces->v3].co );
if ( mfaces->v4 )
copy_v3_v3 ( &co_moving[3*3], xnew[mfaces->v4].co );
for (i = 0, vt = tri; i < tri_num; i++, vt++) {
float co[3][3];
bool ret;
ret = BLI_bvhtree_update_node ( bvhtree, i, co, co_moving, ( mfaces->v4 ? 4 : 3 ) );
}
else {
ret = BLI_bvhtree_update_node ( bvhtree, i, co, NULL, ( mfaces->v4 ? 4 : 3 ) );
}
copy_v3_v3(co[0], mvert[vt->tri[0]].co);
copy_v3_v3(co[1], mvert[vt->tri[1]].co);
copy_v3_v3(co[2], mvert[vt->tri[2]].co);
// check if tree is already full
if ( !ret )
break;
/* copy new locations into array */
if (moving) {
float co_moving[3][3];
/* update moving positions */
copy_v3_v3(co_moving[0], mvert_moving[vt->tri[0]].co);
copy_v3_v3(co_moving[1], mvert_moving[vt->tri[1]].co);
copy_v3_v3(co_moving[2], mvert_moving[vt->tri[2]].co);
ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], &co_moving[0][0], 3);
}
else {
ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], NULL, 3);
}
BLI_bvhtree_update_tree ( bvhtree );
/* check if tree is already full */
if (ret == false) {
break;
}
}
BLI_bvhtree_update_tree(bvhtree);
}
/***********************************
@@ -380,80 +390,29 @@ static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
ClothModifierData *clmd = (ClothModifierData *)md1;
CollisionModifierData *collmd = (CollisionModifierData *) md2;
/* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
MFace *face1=NULL, *face2 = NULL;
const MVertTri *tri_a, *tri_b;
#ifdef WITH_BULLET
ClothVertex *verts1 = clmd->clothObject->verts;
#endif
double distance = 0;
float epsilon1 = clmd->coll_parms->epsilon;
float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
int i;
face1 = & ( clmd->clothObject->mfaces[overlap->indexA] );
face2 = & ( collmd->mfaces[overlap->indexB] );
tri_a = &clmd->clothObject->tri[overlap->indexA];
tri_b = &collmd->tri[overlap->indexB];
// check all 4 possible collisions
for ( i = 0; i < 4; i++ ) {
if ( i == 0 ) {
// fill faceA
collpair->ap1 = face1->v1;
collpair->ap2 = face1->v2;
collpair->ap3 = face1->v3;
/* fill face_a */
collpair->ap1 = tri_a->tri[0];
collpair->ap2 = tri_a->tri[1];
collpair->ap3 = tri_a->tri[2];
// fill faceB
collpair->bp1 = face2->v1;
collpair->bp2 = face2->v2;
collpair->bp3 = face2->v3;
}
else if ( i == 1 ) {
if ( face1->v4 ) {
// fill faceA
collpair->ap1 = face1->v1;
collpair->ap2 = face1->v3;
collpair->ap3 = face1->v4;
/* fill face_b */
collpair->bp1 = tri_b->tri[0];
collpair->bp2 = tri_b->tri[1];
collpair->bp3 = tri_b->tri[2];
// fill faceB
collpair->bp1 = face2->v1;
collpair->bp2 = face2->v2;
collpair->bp3 = face2->v3;
}
else {
i++;
}
}
if ( i == 2 ) {
if ( face2->v4 ) {
// fill faceA
collpair->ap1 = face1->v1;
collpair->ap2 = face1->v2;
collpair->ap3 = face1->v3;
{
// fill faceB
collpair->bp1 = face2->v1;
collpair->bp2 = face2->v4;
collpair->bp3 = face2->v3;
}
else {
break;
}
}
else if ( i == 3 ) {
if ( face1->v4 && face2->v4 ) {
// fill faceA
collpair->ap1 = face1->v1;
collpair->ap2 = face1->v3;
collpair->ap3 = face1->v4;
// fill faceB
collpair->bp1 = face2->v1;
collpair->bp2 = face2->v3;
collpair->bp3 = face2->v4;
}
else {
break;
}
}
#ifdef WITH_BULLET
// calc distance + normal
distance = plNearestPoints (
@@ -662,12 +621,12 @@ static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, Collis
static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index)
{
Cloth *cloth = clmd->clothObject;
int i=0, j = 0, /*numfaces = 0, */ numverts = 0;
int i=0, j = 0, /*numfaces = 0, */ mvert_num = 0;
ClothVertex *verts = NULL;
int ret = 0;
int result = 0;
numverts = clmd->clothObject->numverts;
mvert_num = clmd->clothObject->mvert_num;
verts = cloth->verts;
// process all collisions (calculate impulses, TODO: also repulses if distance too short)
@@ -680,7 +639,7 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
// apply impulses in parallel
if (result) {
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
// calculate "velocities" (just xnew = xold + v; no dt in v)
if (verts[i].impulse_count) {
// VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
@@ -706,7 +665,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
{
Cloth *cloth= clmd->clothObject;
BVHTree *cloth_bvh= cloth->bvhtree;
unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ numverts = 0, k, l, j;
unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ mvert_num = 0, k, l, j;
int rounds = 0; // result counts applied collisions; ic is for debug output;
ClothVertex *verts = NULL;
int ret = 0, ret2 = 0;
@@ -718,7 +677,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
verts = cloth->verts;
/* numfaces = cloth->numfaces; */ /* UNUSED */
numverts = cloth->numverts;
mvert_num = cloth->mvert_num;
////////////////////////////////////////////////////////////
// static collisions
@@ -794,8 +753,8 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
// this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
////////////////////////////////////////////////////////////
// verts come from clmd
for ( i = 0; i < numverts; i++ ) {
/* verts come from clmd */
for (i = 0; i < mvert_num; i++) {
if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
continue;
@@ -820,7 +779,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
verts = cloth->verts; // needed for openMP
/* numfaces = cloth->numfaces; */ /* UNUSED */
numverts = cloth->numverts;
mvert_num = cloth->mvert_num;
verts = cloth->verts;
@@ -898,8 +857,8 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
////////////////////////////////////////////////////////////
// SELFCOLLISIONS: update velocities
////////////////////////////////////////////////////////////
if ( ret2 ) {
for ( i = 0; i < cloth->numverts; i++ ) {
if (ret2) {
for (i = 0; i < cloth->mvert_num; i++) {
if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) {
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
}
@@ -1104,10 +1063,11 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float
#endif
}
static CollPair *cloth_point_collpair(float p1[3], float p2[3], MVert *mverts, int bp1, int bp2, int bp3,
int index_cloth, int index_coll, float epsilon, CollPair *collpair)
static CollPair *cloth_point_collpair(
float p1[3], float p2[3], const MVert *mverts, int bp1, int bp2, int bp3,
int index_cloth, int index_coll, float epsilon, CollPair *collpair)
{
float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
float lambda /*, distance1 */, distance2;
float facenor[3], v1p1[3], v1p2[3];
float w[4];
@@ -1149,22 +1109,25 @@ static CollPair *cloth_point_collpair(float p1[3], float p2[3], MVert *mverts, i
}
//Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned
static CollPair* cloth_point_collision(ModifierData *md1, ModifierData *md2,
BVHTreeOverlap *overlap, float epsilon, CollPair *collpair, float UNUSED(dt))
static CollPair *cloth_point_collision(
ModifierData *md1, ModifierData *md2,
BVHTreeOverlap *overlap, float epsilon, CollPair *collpair, float UNUSED(dt))
{
ClothModifierData *clmd = (ClothModifierData *)md1;
CollisionModifierData *collmd = (CollisionModifierData *) md2;
/* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
ClothVertex *vert = NULL;
MFace *face = NULL;
MVert *mverts = collmd->current_x;
const MVertTri *vt;
const MVert *mverts = collmd->current_x;
vert = &clmd->clothObject->verts[overlap->indexA];
face = &collmd->mfaces[overlap->indexB];
vt = &collmd->tri[overlap->indexB];
collpair = cloth_point_collpair(vert->tx, vert->x, mverts, face->v1, face->v2, face->v3, overlap->indexA, overlap->indexB, epsilon, collpair);
if (face->v4)
collpair = cloth_point_collpair(vert->tx, vert->x, mverts, face->v3, face->v4, face->v1, overlap->indexA, overlap->indexB, epsilon, collpair);
collpair = cloth_point_collpair(
vert->tx, vert->x, mverts,
vt->tri[0], vt->tri[1], vt->tri[2],
overlap->indexA, overlap->indexB,
epsilon, collpair);
return collpair;
}
@@ -1189,7 +1152,7 @@ static int cloth_points_objcollisions_resolve(ClothModifierData * clmd, Collisio
CollPair *collisions, CollPair *collisions_index, float dt)
{
Cloth *cloth = clmd->clothObject;
int i=0, numverts = clmd->clothObject->numverts;
int i = 0, mvert_num = clmd->clothObject->mvert_num;
ClothVertex *verts = cloth->verts;
int ret = 0;
@@ -1199,7 +1162,7 @@ static int cloth_points_objcollisions_resolve(ClothModifierData * clmd, Collisio
// apply impulses in parallel
if (result) {
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
// calculate "velocities" (just xnew = xold + v; no dt in v)
if (verts[i].impulse_count) {
// VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
@@ -1223,29 +1186,29 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
BVHTree *cloth_bvh;
int rounds = 0; // result counts applied collisions; ic is for debug output;
float round_dt = dt / (float)clmd->coll_parms->loop_count;
unsigned int i=0, numverts = 0;
unsigned int i = 0, mvert_num = 0;
ClothVertex *verts = NULL;
int ret = 0, ret2 = 0;
Object **collobjs = NULL;
unsigned int numcollobj = 0;
verts = cloth->verts;
numverts = cloth->numverts;
mvert_num = cloth->mvert_num;
////////////////////////////////////////////////////////////
// static collisions
////////////////////////////////////////////////////////////
// create temporary cloth points bvh
cloth_bvh = BLI_bvhtree_new(numverts, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
/* fill tree */
for (i = 0; i < numverts; i++) {
float co[6];
for (i = 0; i < mvert_num; i++) {
float co[2][3];
copy_v3_v3(&co[0*3], verts[i].x);
copy_v3_v3(&co[1*3], verts[i].tx);
copy_v3_v3(co[0], verts[i].x);
copy_v3_v3(co[1], verts[i].tx);
BLI_bvhtree_insert(cloth_bvh, i, co, 2);
BLI_bvhtree_insert(cloth_bvh, i, co[0], 2);
}
/* balance tree */
BLI_bvhtree_balance(cloth_bvh);
@@ -1318,7 +1281,7 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
////////////////////////////////////////////////////////////
// verts come from clmd
for ( i = 0; i < numverts; i++ ) {
for (i = 0; i < mvert_num; i++) {
if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
continue;
@@ -1344,7 +1307,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
{
Cloth *cloth= clmd->clothObject;
BVHTree *cloth_bvh;
unsigned int i=0, numverts = 0;
unsigned int i = 0, mvert_num = 0;
ClothVertex *verts = NULL;
ColliderContacts *collider_contacts;
@@ -1353,16 +1316,16 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
unsigned int numcollobj = 0;
verts = cloth->verts;
numverts = cloth->numverts;
mvert_num = cloth->mvert_num;
////////////////////////////////////////////////////////////
// static collisions
////////////////////////////////////////////////////////////
// create temporary cloth points bvh
cloth_bvh = BLI_bvhtree_new(numverts, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
/* fill tree */
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
float co[6];
copy_v3_v3(&co[0*3], verts[i].x);
@@ -1442,7 +1405,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
////////////////////////////////////////////////////////////
// verts come from clmd
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
continue;

View File

@@ -2477,10 +2477,6 @@ static int collision_sphere_to_edges(ParticleCollision *col, float radius, Parti
int i;
for (i=0; i<3; i++) {
/* in case of a quad, no need to check "edge" that goes through face twice */
if ((pce->x[3] && i==2))
continue;
cur = edge+i;
cur->x[0] = pce->x[i]; cur->x[1] = pce->x[(i+1)%3];
cur->v[0] = pce->v[i]; cur->v[1] = pce->v[(i+1)%3];
@@ -2524,10 +2520,6 @@ static int collision_sphere_to_verts(ParticleCollision *col, float radius, Parti
int i;
for (i=0; i<3; i++) {
/* in case of quad, only check one vert the first time */
if (pce->x[3] && i != 1)
continue;
cur = vert+i;
cur->x[0] = pce->x[i];
cur->v[0] = pce->v[i];
@@ -2555,21 +2547,19 @@ void BKE_psys_collision_neartest_cb(void *userdata, int index, const BVHTreeRay
{
ParticleCollision *col = (ParticleCollision *) userdata;
ParticleCollisionElement pce;
MFace *face = col->md->mfaces + index;
const MVertTri *vt = &col->md->tri[index];
MVert *x = col->md->x;
MVert *v = col->md->current_v;
float t = hit->dist/col->original_ray_length;
int collision = 0;
pce.x[0] = x[face->v1].co;
pce.x[1] = x[face->v2].co;
pce.x[2] = x[face->v3].co;
pce.x[3] = face->v4 ? x[face->v4].co : NULL;
pce.x[0] = x[vt->tri[0]].co;
pce.x[1] = x[vt->tri[1]].co;
pce.x[2] = x[vt->tri[2]].co;
pce.v[0] = v[face->v1].co;
pce.v[1] = v[face->v2].co;
pce.v[2] = v[face->v3].co;
pce.v[3] = face->v4 ? v[face->v4].co : NULL;
pce.v[0] = v[vt->tri[0]].co;
pce.v[1] = v[vt->tri[1]].co;
pce.v[2] = v[vt->tri[2]].co;
pce.tot = 3;
pce.inside = 0;
@@ -2579,31 +2569,20 @@ void BKE_psys_collision_neartest_cb(void *userdata, int index, const BVHTreeRay
if (col->hit == col->current && col->pce.index == index && col->pce.tot == 3)
return;
do {
collision = collision_sphere_to_tri(col, ray->radius, &pce, &t);
if (col->pce.inside == 0) {
collision += collision_sphere_to_edges(col, ray->radius, &pce, &t);
collision += collision_sphere_to_verts(col, ray->radius, &pce, &t);
}
collision = collision_sphere_to_tri(col, ray->radius, &pce, &t);
if (col->pce.inside == 0) {
collision += collision_sphere_to_edges(col, ray->radius, &pce, &t);
collision += collision_sphere_to_verts(col, ray->radius, &pce, &t);
}
if (collision) {
hit->dist = col->original_ray_length * t;
hit->index = index;
collision_point_velocity(&col->pce);
if (collision) {
hit->dist = col->original_ray_length * t;
hit->index = index;
col->hit = col->current;
}
collision_point_velocity(&col->pce);
pce.x[1] = pce.x[2];
pce.x[2] = pce.x[3];
pce.x[3] = NULL;
pce.v[1] = pce.v[2];
pce.v[2] = pce.v[3];
pce.v[3] = NULL;
} while (pce.x[2]);
col->hit = col->current;
}
}
static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, ListBase *colliders)
{

View File

@@ -543,7 +543,7 @@ static void ptcache_cloth_interpolate(int index, void *cloth_v, void **data, flo
static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra))
{
ClothModifierData *clmd= cloth_v;
return clmd->clothObject ? clmd->clothObject->numverts : 0;
return clmd->clothObject ? clmd->clothObject->mvert_num : 0;
}
static void ptcache_cloth_error(void *cloth_v, const char *message)

File diff suppressed because it is too large Load Diff

View File

@@ -4894,9 +4894,10 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
collmd->current_xnew = NULL;
collmd->current_v = NULL;
collmd->time_x = collmd->time_xnew = -1000;
collmd->numverts = 0;
collmd->mvert_num = 0;
collmd->tri_num = 0;
collmd->bvhtree = NULL;
collmd->mfaces = NULL;
collmd->tri = NULL;
}
else if (md->type == eModifierType_Surface) {

View File

@@ -96,6 +96,12 @@ typedef struct MLoopTri {
unsigned int tri[3];
unsigned int poly;
} MLoopTri;
#
#
typedef struct MVertTri {
unsigned int tri[3];
} MVertTri;
typedef struct MTexPoly {
struct Image *tpage;

View File

@@ -612,10 +612,10 @@ typedef struct CollisionModifierData {
struct MVert *current_x; /* position at the actual inter-frame step */
struct MVert *current_v; /* (xnew - x) at the actual inter-frame step */
struct MFace *mfaces; /* object face data */
struct MVertTri *tri;
unsigned int numverts;
unsigned int numfaces;
unsigned int mvert_num;
unsigned int tri_num;
float time_x, time_xnew; /* cfra time of modifier */
struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */
} CollisionModifierData;

View File

@@ -58,7 +58,8 @@ static void initData(ModifierData *md)
collmd->current_xnew = NULL;
collmd->current_v = NULL;
collmd->time_x = collmd->time_xnew = -1000;
collmd->numverts = 0;
collmd->mvert_num = 0;
collmd->tri_num = 0;
collmd->bvhtree = NULL;
}
@@ -77,10 +78,15 @@ static void freeData(ModifierData *md)
MEM_SAFE_FREE(collmd->current_x);
MEM_SAFE_FREE(collmd->current_xnew);
MEM_SAFE_FREE(collmd->current_v);
MEM_SAFE_FREE(collmd->mfaces);
if (collmd->tri) {
MEM_freeN((void *)collmd->tri);
collmd->tri = NULL;
}
collmd->time_x = collmd->time_xnew = -1000;
collmd->numverts = 0;
collmd->mvert_num = 0;
collmd->tri_num = 0;
}
}
@@ -110,7 +116,7 @@ static void deformVerts(ModifierData *md, Object *ob,
if (dm) {
float current_time = 0;
unsigned int numverts = 0;
unsigned int mvert_num = 0;
CDDM_apply_vert_coords(dm, vertexCos);
CDDM_calc_normals(dm);
@@ -120,19 +126,20 @@ static void deformVerts(ModifierData *md, Object *ob,
if (G.debug_value > 0)
printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
numverts = dm->getNumVerts(dm);
mvert_num = dm->getNumVerts(dm);
if (current_time > collmd->time_xnew) {
unsigned int i;
/* check if mesh has changed */
if (collmd->x && (numverts != collmd->numverts))
if (collmd->x && (mvert_num != collmd->mvert_num))
freeData((ModifierData *)collmd);
if (collmd->time_xnew == -1000) { /* first time */
collmd->x = dm->dupVertArray(dm); /* frame start position */
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
/* we save global positions */
mul_m4_v3(ob->obmat, collmd->x[i].co);
}
@@ -142,56 +149,75 @@ static void deformVerts(ModifierData *md, Object *ob,
collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
collmd->numverts = numverts;
collmd->mvert_num = mvert_num;
DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
DM_ensure_looptri(dm);
collmd->tri_num = dm->getNumLoopTri(dm);
{
const MLoop *mloop = dm->getLoopArray(dm);
const MLoopTri *looptri = dm->getLoopTriArray(dm);
MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__);
DM_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
collmd->tri = tri;
}
collmd->mfaces = dm->dupTessFaceArray(dm);
collmd->numfaces = dm->getNumTessFaces(dm);
/* create bounding box hierarchy */
collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft);
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->x,
collmd->tri, collmd->tri_num,
ob->pd->pdef_sboft);
collmd->time_x = collmd->time_xnew = current_time;
}
else if (numverts == collmd->numverts) {
else if (mvert_num == collmd->mvert_num) {
/* put positions to old positions */
tempVert = collmd->x;
collmd->x = collmd->xnew;
collmd->xnew = tempVert;
collmd->time_x = collmd->time_xnew;
memcpy(collmd->xnew, dm->getVertArray(dm), numverts * sizeof(MVert));
memcpy(collmd->xnew, dm->getVertArray(dm), mvert_num * sizeof(MVert));
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
/* we save global positions */
mul_m4_v3(ob->obmat, collmd->xnew[i].co);
}
memcpy(collmd->current_xnew, collmd->x, numverts * sizeof(MVert));
memcpy(collmd->current_x, collmd->x, numverts * sizeof(MVert));
memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
/* check if GUI setting has changed for bvh */
if (collmd->bvhtree) {
if (ob->pd->pdef_sboft != BLI_bvhtree_getepsilon(collmd->bvhtree)) {
BLI_bvhtree_free(collmd->bvhtree);
collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->current_x,
collmd->tri, collmd->tri_num,
ob->pd->pdef_sboft);
}
}
/* happens on file load (ONLY when i decomment changes in readfile.c) */
if (!collmd->bvhtree) {
collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->current_x,
collmd->tri, collmd->tri_num,
ob->pd->pdef_sboft);
}
else {
/* recalc static bounding boxes */
bvhtree_update_from_mvert(collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1);
bvhtree_update_from_mvert(
collmd->bvhtree,
collmd->current_x, collmd->current_xnew,
collmd->tri, collmd->tri_num,
true);
}
collmd->time_xnew = current_time;
}
else if (numverts != collmd->numverts) {
else if (mvert_num != collmd->mvert_num) {
freeData((ModifierData *)collmd);
}
@@ -200,7 +226,7 @@ static void deformVerts(ModifierData *md, Object *ob,
freeData((ModifierData *)collmd);
}
else {
if (numverts != collmd->numverts) {
if (mvert_num != collmd->mvert_num) {
freeData((ModifierData *)collmd);
}
}

View File

@@ -51,6 +51,7 @@ typedef enum eMassSpringSolverStatus {
struct Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings);
void BPH_mass_spring_solver_free(struct Implicit_Data *id);
int BPH_mass_spring_solver_numvert(struct Implicit_Data *id);
int BPH_cloth_solver_init(struct Object *ob, struct ClothModifierData *clmd);
void BPH_cloth_solver_free(struct ClothModifierData *clmd);

View File

@@ -88,13 +88,13 @@ int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
unsigned int i, nondiag;
nondiag = cloth_count_nondiag_blocks(cloth);
cloth->implicit = id = BPH_mass_spring_solver_create(cloth->numverts, nondiag);
cloth->implicit = id = BPH_mass_spring_solver_create(cloth->mvert_num, nondiag);
for (i = 0; i < cloth->numverts; i++) {
for (i = 0; i < cloth->mvert_num; i++) {
BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass);
}
for (i = 0; i < cloth->numverts; i++) {
for (i = 0; i < cloth->mvert_num; i++) {
BPH_mass_spring_set_motion_state(id, i, verts[i].x, ZERO);
}
@@ -115,11 +115,11 @@ void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
ClothVertex *verts = cloth->verts;
unsigned int numverts = cloth->numverts, i;
unsigned int mvert_num = cloth->mvert_num, i;
ClothHairData *cloth_hairdata = clmd->hairdata;
Implicit_Data *id = cloth->implicit;
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
if (cloth_hairdata) {
ClothHairData *root = &cloth_hairdata[i];
BPH_mass_spring_set_rest_transform(id, i, root->rot);
@@ -209,14 +209,14 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c
Cloth *cloth = clmd->clothObject;
Implicit_Data *data = cloth->implicit;
ClothVertex *verts = cloth->verts;
int numverts = cloth->numverts;
int mvert_num = cloth->mvert_num;
int i, j, v;
const float ZERO[3] = {0.0f, 0.0f, 0.0f};
BPH_mass_spring_clear_constraints(data);
for (v = 0; v < numverts; v++) {
for (v = 0; v < mvert_num; v++) {
if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) {
/* pinned vertex constraints */
BPH_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */
@@ -261,15 +261,15 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c
static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData *clmd, float (*initial_cos)[3], float UNUSED(step), float dt)
{
Cloth *cloth= clmd->clothObject;
float (*cos)[3] = (float (*)[3])MEM_callocN(sizeof(float)*3*cloth->numverts, "cos cloth_calc_helper_forces");
float *masses = (float *)MEM_callocN(sizeof(float)*cloth->numverts, "cos cloth_calc_helper_forces");
float (*cos)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * cloth->mvert_num, "cos cloth_calc_helper_forces");
float *masses = (float *)MEM_callocN(sizeof(float) * cloth->mvert_num, "cos cloth_calc_helper_forces");
LinkNode *node;
ClothSpring *spring;
ClothVertex *cv;
int i, steps;
cv = cloth->verts;
for (i=0; i<cloth->numverts; i++, cv++) {
for (i = 0; i < cloth->mvert_num; i++, cv++) {
copy_v3_v3(cos[i], cv->tx);
if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) {
@@ -317,7 +317,7 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo
}
cv = cloth->verts;
for (i=0; i<cloth->numverts; i++, cv++) {
for (i = 0; i < cloth->mvert_num; i++, cv++) {
float vec[3];
/*compute forces*/
@@ -444,11 +444,11 @@ static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax
{
Cloth *cloth = clmd->clothObject;
Implicit_Data *data = cloth->implicit;
unsigned int numverts = cloth->numverts;
unsigned int looptri_num = cloth->tri_num;
int i;
INIT_MINMAX(gmin, gmax);
for (i = 0; i < numverts; i++) {
for (i = 0; i < looptri_num; i++) {
float x[3];
BPH_mass_spring_get_motion_state(data, i, x, NULL);
DO_MINMAX(x, gmin, gmax);
@@ -463,8 +463,8 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
unsigned int i = 0;
float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
float gravity[3] = {0.0f, 0.0f, 0.0f};
MFace *mfaces = cloth->mfaces;
unsigned int numverts = cloth->numverts;
const MVertTri *tri = cloth->tri;
unsigned int mvert_num = cloth->mvert_num;
ClothVertex *vert;
#ifdef CLOTH_FORCE_GRAVITY
@@ -474,7 +474,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
}
vert = cloth->verts;
for (i = 0; i < cloth->numverts; i++, vert++) {
for (i = 0; i < cloth->mvert_num; i++, vert++) {
BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
}
#endif
@@ -488,8 +488,8 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
/* handle external forces like wind */
if (effectors) {
/* cache per-vertex forces to avoid redundant calculation */
float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float) * 3 * numverts, "effector forces");
for (i = 0; i < cloth->numverts; i++) {
float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * mvert_num, "effector forces");
for (i = 0; i < cloth->mvert_num; i++) {
float x[3], v[3];
EffectedPoint epoint;
@@ -498,13 +498,13 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
}
for (i = 0; i < cloth->numfaces; i++) {
MFace *mf = &mfaces[i];
BPH_mass_spring_force_face_wind(data, mf->v1, mf->v2, mf->v3, mf->v4, winvec);
for (i = 0; i < cloth->tri_num; i++) {
const MVertTri *vt = &tri[i];
BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
}
/* Hair has only edges */
if (cloth->numfaces == 0) {
if (cloth->tri_num == 0) {
#if 0
ClothHairData *hairdata = clmd->hairdata;
ClothHairData *hair_ij, *hair_kl;
@@ -525,7 +525,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
ClothHairData *hairdata = clmd->hairdata;
vert = cloth->verts;
for (i = 0; i < cloth->numverts; i++, vert++) {
for (i = 0; i < cloth->mvert_num; i++, vert++) {
if (hairdata) {
ClothHairData *hair = &hairdata[i];
BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec);
@@ -650,11 +650,11 @@ static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth)
{
#if 0
Implicit_Data *data = cloth->implicit;
int numverts = cloth->numverts;
int mvert_num = cloth->mvert_num;
ClothVertex *vert;
int i;
for (i = 0, vert = cloth->verts; i < numverts; i++, vert++) {
for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
float x[3], v[3];
cloth_get_vertex_motion_state(data, vert, x, v);
@@ -689,7 +689,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
ClothSimSettings *parms = clmd->sim_parms;
Cloth *cloth = clmd->clothObject;
Implicit_Data *data = cloth->implicit;
int numverts = cloth->numverts;
int mvert_num = cloth->mvert_num;
ClothVertex *vert;
const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
@@ -719,7 +719,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
/* main hair continuum solver */
BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength);
for (i = 0, vert = cloth->verts; i < numverts; i++, vert++) {
for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
float x[3], v[3], nv[3];
/* calculate volumetric velocity influence */
@@ -799,7 +799,7 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
ClothSimSettings *parms = clmd->sim_parms;
Cloth *cloth = clmd->clothObject;
Implicit_Data *data = cloth->implicit;
int numverts = cloth->numverts;
int mvert_num = cloth->mvert_num;
ClothVertex *vert;
/* 2.0f is an experimental value that seems to give good results */
@@ -817,7 +817,7 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax);
vert = cloth->verts;
for (i = 0; i < numverts; i++, vert++) {
for (i = 0; i < mvert_num; i++, vert++) {
float x[3], v[3];
if (vert->solver_index < 0) {
@@ -832,7 +832,7 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
BPH_hair_volume_normalize_vertex_grid(vertex_grid);
vert = cloth->verts;
for (i = 0; i < numverts; i++, vert++) {
for (i = 0; i < mvert_num; i++, vert++) {
float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3];
if (vert->solver_index < 0)
@@ -858,7 +858,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
Cloth *cloth = clmd->clothObject;
Implicit_Data *id = cloth->implicit;
ClothVertex *verts = cloth->verts;
int numverts = cloth->numverts;
int mvert_num = cloth->mvert_num;
const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
bool do_extra_solve;
@@ -870,7 +870,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
return;
// update verts to current positions
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
BPH_mass_spring_get_new_position(id, i, verts[i].tx);
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
@@ -878,7 +878,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
}
#if 0 /* unused */
for (i=0, cv=cloth->verts; i<cloth->numverts; i++, cv++) {
for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) {
copy_v3_v3(initial_cos[i], cv->tx);
}
#endif
@@ -888,7 +888,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
// copy corrected positions back to simulation
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
float curx[3];
BPH_mass_spring_get_position(id, i, curx);
// correct velocity again, just to be sure we had to change it due to adaptive collisions
@@ -898,7 +898,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
if (do_extra_solve) {
// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
float newv[3];
@@ -985,7 +985,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
float step=0.0f, tf=clmd->sim_parms->timescale;
Cloth *cloth = clmd->clothObject;
ClothVertex *verts = cloth->verts/*, *cv*/;
unsigned int numverts = cloth->numverts;
unsigned int mvert_num = cloth->mvert_num;
float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
Implicit_Data *id = cloth->implicit;
ColliderContacts *contacts = NULL;
@@ -998,7 +998,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
cloth_clear_result(clmd);
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
// update velocities with constrained velocities from pinned verts
if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
float v[3];
@@ -1013,7 +1013,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
ImplicitSolverResult result;
/* copy velocities for collision */
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
copy_v3_v3(verts[i].v, verts[i].tv);
}
@@ -1038,7 +1038,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
// damping velocity for artistic reasons
// this is a bad way to do it, should be removed imo - lukas_t
if (clmd->sim_parms->vel_damping != 1.0f) {
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
float v[3];
BPH_mass_spring_get_motion_state(id, i, NULL, v);
mul_v3_fl(v, clmd->sim_parms->vel_damping);
@@ -1066,7 +1066,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
BPH_mass_spring_apply_result(id);
/* move pinned verts to correct position */
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
float x[3];
@@ -1087,7 +1087,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
}
/* copy results back to cloth data */
for (i = 0; i < numverts; i++) {
for (i = 0; i < mvert_num; i++) {
BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v);
copy_v3_v3(verts[i].txold, verts[i].x);
}

View File

@@ -107,7 +107,7 @@ void BPH_mass_spring_force_drag(struct Implicit_Data *data, float drag);
/* Custom external force */
void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]);
/* Wind force, acting on a face */
void BPH_mass_spring_force_face_wind(struct Implicit_Data *data, int v1, int v2, int v3, int v4, const float (*winvec)[3]);
void BPH_mass_spring_force_face_wind(struct Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]);
/* Wind force, acting on an edge */
void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2, float radius1, float radius2, const float (*winvec)[3]);
/* Wind force, acting on a vertex */

View File

@@ -1424,33 +1424,16 @@ static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3
return normalize_v3(nor);
}
static float calc_nor_area_quad(float nor[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
float n1[3], n2[3];
sub_v3_v3v3(n1, v1, v3);
sub_v3_v3v3(n2, v2, v4);
cross_v3_v3v3(nor, n1, n2);
return normalize_v3(nor);
}
/* XXX does not support force jacobians yet, since the effector system does not provide them either */
void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3, int v4, const float (*winvec)[3])
void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3])
{
const float effector_scale = 0.02f;
float win[3], nor[3], area;
float factor;
// calculate face normal and area
if (v4) {
area = calc_nor_area_quad(nor, data->X[v1], data->X[v2], data->X[v3], data->X[v4]);
factor = effector_scale * area * 0.25f;
}
else {
area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
factor = effector_scale * area / 3.0f;
}
/* calculate face normal and area */
area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
factor = effector_scale * area / 3.0f;
world_to_root_v3(data, v1, win, winvec[v1]);
madd_v3_v3fl(data->F[v1], nor, factor * dot_v3v3(win, nor));
@@ -1460,11 +1443,6 @@ void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3
world_to_root_v3(data, v3, win, winvec[v3]);
madd_v3_v3fl(data->F[v3], nor, factor * dot_v3v3(win, nor));
if (v4) {
world_to_root_v3(data, v4, win, winvec[v4]);
madd_v3_v3fl(data->F[v4], nor, factor * dot_v3v3(win, nor));
}
}
static void edge_wind_vertex(const float dir[3], float length, float radius, const float wind[3], float f[3], float UNUSED(dfdx[3][3]), float UNUSED(dfdv[3][3]))

View File

@@ -92,7 +92,6 @@ extern "C" {
typedef float Scalar;
static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
/* slightly extended Eigen vector class
* with conversion to/from plain C float array
@@ -786,33 +785,16 @@ static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3
return normalize_v3(nor);
}
static float calc_nor_area_quad(float nor[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
float n1[3], n2[3];
sub_v3_v3v3(n1, v1, v3);
sub_v3_v3v3(n2, v2, v4);
cross_v3_v3v3(nor, n1, n2);
return normalize_v3(nor);
}
/* XXX does not support force jacobians yet, since the effector system does not provide them either */
void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3, int v4, const float (*winvec)[3])
void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3])
{
const float effector_scale = 0.02f;
float win[3], nor[3], area;
float factor;
// calculate face normal and area
if (v4) {
area = calc_nor_area_quad(nor, data->X.v3(v1), data->X.v3(v2), data->X.v3(v3), data->X.v3(v4));
factor = effector_scale * area * 0.25f;
}
else {
area = calc_nor_area_tri(nor, data->X.v3(v1), data->X.v3(v2), data->X.v3(v3));
factor = effector_scale * area / 3.0f;
}
area = calc_nor_area_tri(nor, data->X.v3(v1), data->X.v3(v2), data->X.v3(v3));
factor = effector_scale * area / 3.0f;
world_to_root_v3(data, v1, win, winvec[v1]);
madd_v3_v3fl(data->F.v3(v1), nor, factor * dot_v3v3(win, nor));
@@ -822,11 +804,6 @@ void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3
world_to_root_v3(data, v3, win, winvec[v3]);
madd_v3_v3fl(data->F.v3(v3), nor, factor * dot_v3v3(win, nor));
if (v4) {
world_to_root_v3(data, v4, win, winvec[v4]);
madd_v3_v3fl(data->F.v3(v4), nor, factor * dot_v3v3(win, nor));
}
}
void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, const float (*winvec)[3])