static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; 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 numedges = (unsigned int)dm->getNumEdges ( dm ); unsigned int numfaces = (unsigned int)dm->getNumFaces ( dm ); MEdge *medge = dm->getEdgeArray ( dm ); MFace *mface = dm->getFaceArray ( dm ); int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeHash *edgehash = NULL; LinkNode *search = NULL, *search2 = NULL; // error handling if ( numedges==0 ) return 0; cloth->springs = NULL; edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" ); if(!edgelist) return 0; for ( i = 0; i < numverts; i++ ) { edgelist[i] = NULL; } if ( cloth->springs ) MEM_freeN ( cloth->springs ); // create spring network hash edgehash = BLI_edgehash_new(); // structural springs for ( i = 0; i < numedges; i++ ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { spring->ij = MIN2(medge[i].v1, medge[i].v2); spring->kl = MAX2(medge[i].v2, medge[i].v1); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; cloth->verts[spring->ij].spring_count++; cloth->verts[spring->kl].spring_count++; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; spring->flags = 0; spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } else { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } } if(struct_springs > 0) clmd->sim_parms->avg_spring_len /= struct_springs; for(i = 0; i < numverts; i++) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); } // shear springs for ( i = 0; i < numfaces; i++ ) { // triangle faces already have shear springs due to structural geometry if ( !mface[i].v4 ) continue; spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v1, mface[i].v3); spring->kl = MAX2(mface[i].v3, mface[i].v1); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); // if ( mface[i].v4 ) --> Quad face spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v2, mface[i].v4); spring->kl = MAX2(mface[i].v4, mface[i].v2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } if(numfaces) { // bending springs search2 = cloth->springs; for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { if ( !search2 ) break; tspring2 = search2->link; search = edgelist[tspring2->kl]; while ( search ) { tspring = search->link; index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); // check for existing spring // check also if startpoint is equal to endpoint if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) ) && ( index2!=tspring2->ij ) ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(tspring2->ij, index2); spring->kl = MAX2(tspring2->ij, index2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL ); bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; } search2 = search2->next; } } else if(struct_springs > 2) { /* bending springs for hair strands */ /* The current algorightm only goes through the edges in order of the mesh edges list */ /* and makes springs between the outer vert of edges sharing a vertice. This works just */ /* fine for hair, but not for user generated string meshes. This could/should be later */ /* extended to work with non-ordered edges so that it can be used for general "rope */ /* dynamics" without the need for the vertices or edges to be ordered through the length*/ /* of the strands. -jahka */ search = cloth->springs; search2 = search->next; while(search && search2) { tspring = search->link; tspring2 = search2->link; if(tspring->ij == tspring2->kl) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = tspring2->ij; spring->kl = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; search2 = search2->next; } } /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */ for ( i = 0; i < numedges; i++ ) // struct springs BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL ); for ( i = 0; i < numfaces; i++ ) // edge springs { if(mface[i].v4) { BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL ); BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL ); } } cloth->numsprings = struct_springs + shear_springs + bend_springs; if ( edgelist ) { for ( i = 0; i < numverts; i++ ) { BLI_linklist_free ( edgelist[i],NULL ); } MEM_freeN ( edgelist ); } cloth->edgehash = edgehash; if(G.rt>0) printf("avg_len: %f\n",clmd->sim_parms->avg_spring_len); return 1; } /* cloth_build_springs */
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; 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 numedges = (unsigned int)dm->getNumEdges (dm); unsigned int numfaces = (unsigned int)dm->getNumTessFaces (dm); float shrink_factor; MEdge *medge = dm->getEdgeArray (dm); MFace *mface = dm->getTessFaceArray (dm); int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeSet *edgeset = NULL; LinkNode *search = NULL, *search2 = NULL; // error handling if ( numedges==0 ) return 0; /* NOTE: handling ownership of springs and edgeset is quite sloppy * currently they are never initialized but assert just to be sure */ BLI_assert(cloth->springs == NULL); BLI_assert(cloth->edgeset == NULL); cloth->springs = NULL; cloth->edgeset = NULL; edgelist = MEM_callocN ( sizeof (LinkNode *) * numverts, "cloth_edgelist_alloc" ); if (!edgelist) return 0; // structural springs for ( i = 0; i < numedges; i++ ) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { spring_verts_ordered_set(spring, medge[i].v1, medge[i].v2); if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) { // handle sewing (loose edges will be pulled together) spring->restlen = 0.0f; spring->stiffness = 1.0f; spring->type = CLOTH_SPRING_TYPE_SEWING; } else { if (clmd->sim_parms->vgroup_shrink > 0) shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f); else shrink_factor = 1.0f - clmd->sim_parms->shrink_min; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; } clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; cloth->verts[spring->ij].spring_count++; cloth->verts[spring->kl].spring_count++; spring->flags = 0; struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } else { cloth_free_errorsprings(cloth, edgelist); return 0; } } if (struct_springs > 0) clmd->sim_parms->avg_spring_len /= struct_springs; for (i = 0; i < numverts; i++) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); } // shear springs for ( i = 0; i < numfaces; i++ ) { // triangle faces already have shear springs due to structural geometry if ( !mface[i].v4 ) continue; spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring_verts_ordered_set(spring, mface[i].v1, mface[i].v3); if (clmd->sim_parms->vgroup_shrink > 0) shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f); else shrink_factor = 1.0f - clmd->sim_parms->shrink_min; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); // if ( mface[i].v4 ) --> Quad face spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring_verts_ordered_set(spring, mface[i].v2, mface[i].v4); if (clmd->sim_parms->vgroup_shrink > 0) shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f); else shrink_factor = 1.0f - clmd->sim_parms->shrink_min; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } edgeset = BLI_edgeset_new_ex(__func__, numedges); cloth->edgeset = edgeset; if (numfaces) { // bending springs search2 = cloth->springs; for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { if ( !search2 ) break; tspring2 = search2->link; search = edgelist[tspring2->kl]; while ( search ) { tspring = search->link; index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); // check for existing spring // check also if startpoint is equal to endpoint if ((index2 != tspring2->ij) && !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring_verts_ordered_set(spring, tspring2->ij, index2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; BLI_edgeset_insert(edgeset, spring->ij, spring->kl); bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; } search2 = search2->next; } } else if (struct_springs > 2) { /* bending springs for hair strands */ /* The current algorightm only goes through the edges in order of the mesh edges list */ /* and makes springs between the outer vert of edges sharing a vertice. This works just */ /* fine for hair, but not for user generated string meshes. This could/should be later */ /* extended to work with non-ordered edges so that it can be used for general "rope */ /* dynamics" without the need for the vertices or edges to be ordered through the length*/ /* of the strands. -jahka */ search = cloth->springs; search2 = search->next; while (search && search2) { tspring = search->link; tspring2 = search2->link; if (tspring->ij == tspring2->kl) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring->ij = tspring2->ij; spring->kl = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; search2 = search2->next; } } /* note: the edges may already exist so run reinsert */ /* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */ for (i = 0; i < numedges; i++) { /* struct springs */ BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2); } for (i = 0; i < numfaces; i++) { /* edge springs */ if (mface[i].v4) { BLI_edgeset_add(edgeset, mface[i].v1, mface[i].v3); BLI_edgeset_add(edgeset, mface[i].v2, mface[i].v4); } } cloth->numsprings = struct_springs + shear_springs + bend_springs; cloth_free_edgelist(edgelist, numverts); #if 0 if (G.debug_value > 0) printf("avg_len: %f\n", clmd->sim_parms->avg_spring_len); #endif return 1; } /* cloth_build_springs */