diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 12 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_collision.h | 13 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/SConscript | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collision.c | 874 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/implicit.c | 99 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_math_geom.h | 5 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_geom.c | 30 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_cloth_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_cloth.c | 14 |
11 files changed, 1034 insertions, 27 deletions
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 1ee51cd2122..a5c88000db2 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -35,6 +35,7 @@ */ #include <float.h> +#include "BLI_math_inline.h" struct Object; struct ListBase; @@ -44,16 +45,7 @@ struct DerivedMesh; struct ClothModifierData; struct CollisionTree; -// this is needed for inlining behaviour -#if defined _WIN32 -# define DO_INLINE __inline -#elif defined (__sgi) -# define DO_INLINE -#elif defined (__sun) || defined (__sun__) -# define DO_INLINE -#else -# define DO_INLINE static inline -#endif +#define DO_INLINE MALWAYS_INLINE #define CLOTH_MAX_THREAD 2 diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index b54d4275719..7018a638831 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -63,7 +63,11 @@ struct LinkNode; /* COLLISION FLAGS */ typedef enum { - COLLISION_IN_FUTURE = ( 1 << 1 ), + COLLISION_IN_FUTURE = (1 << 1), +#ifdef USE_ELTOPO + COLLISION_USE_COLLFACE = (1 << 2), + COLLISION_IS_EDGES = (1 << 3), +#endif } COLLISION_FLAGS; @@ -81,7 +85,13 @@ typedef struct CollPair float pa[3], pb[3]; // collision point p1 on face1, p2 on face2 int flag; float time; // collision time, from 0 up to 1 +#ifdef USE_ELTOPO /*either ap* or bp* can be set, but not both*/ + float bary[3]; + int ap1, ap2, ap3, collp, bp1, bp2, bp3; + int collface; +#else int ap1, ap2, ap3, bp1, bp2, bp3; +#endif int pointsb[4]; } CollPair; @@ -109,6 +119,7 @@ typedef struct FaceCollPair float pa[3], pb[3]; // collision point p1 on face1, p2 on face2 } FaceCollPair; + //////////////////////////////////////// diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 0b616f81ef3..4b36b714548 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -145,7 +145,7 @@ set(SRC intern/writeavi.c intern/writeffmpeg.c intern/writeframeserver.c - + BKE_DerivedMesh.h BKE_action.h BKE_anim.h @@ -240,6 +240,11 @@ if(WITH_BULLET) add_definitions(-DUSE_BULLET) endif() +if(WITH_ELTOPO) + list(APPEND INC ../../../extern/eltopo) + add_definitions(-DUSE_ELTOPO) +endif() + if(WITH_IMAGE_OPENEXR) add_definitions(-DWITH_OPENEXR) endif() diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index bef72d3bf67..66011c4f396 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -27,6 +27,10 @@ if env['WITH_BF_PYTHON']: if env['BF_DEBUG']: defs.append('DEBUG') +if env['WITH_BF_ELTOPO']: + incs += ' ../../../extern/eltopo' + defs.append('USE_ELTOPO') + if env['WITH_BF_QUICKTIME']: incs += ' ../quicktime' diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 5eccf724256..ea055e90b45 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -919,7 +919,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d if(!first) implicit_set_positions(clmd); - clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, clmd->coll_parms->epsilon ); + clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) ); for(i = 0; i < dm->getNumVerts(dm); i++) { diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index ebdbbfcf7b4..064f805d046 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -48,6 +48,9 @@ #include "BLI_math.h" #include "BLI_edgehash.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_memarena.h" +#include "BLI_rand.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" @@ -63,6 +66,10 @@ #include "BLI_kdopbvh.h" #include "BKE_collision.h" +#ifdef USE_ELTOPO +#include "eltopo-capi.h" +#endif + /*********************************** Collision modifier code start @@ -486,7 +493,7 @@ DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float VECADDMUL ( to, v3, w3 ); } - +#ifndef USE_ELTOPO static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) { int result = 0; @@ -601,12 +608,799 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM } return result; } +#endif + +#ifdef USE_ELTOPO +typedef struct edgepairkey { + int a1, a2, b1, b2; +} edgepairkey; + +unsigned int edgepair_hash(void *vkey) +{ + edgepairkey *key = vkey; + int keys[4] = {key->a1, key->a2, key->b1, key->b2}; + int i, j; + + for (i=0; i<4; i++) { + for (j=0; j<3; j++) { + if (keys[j] >= keys[j+1]) { + SWAP(int, keys[j], keys[j+1]); + } + } + } + + return keys[0]*101 + keys[1]*72 + keys[2]*53 + keys[3]*34; +} + +int edgepair_cmp(const void *va, const void *vb) +{ + edgepairkey *a = va, *b = vb; + int keysa[4] = {a->a1, a->a2, a->b1, a->b2}; + int keysb[4] = {b->a1, b->a2, b->b1, b->b2}; + int i; + + for (i=0; i<4; i++) { + int j, ok=0; + for (j=0; j<4; j++) { + if (keysa[i] == keysa[j]) { + ok = 1; + break; + } + } + if (!ok) + return -1; + } + + return 0; +} + +static void get_edgepairkey(edgepairkey *key, int a1, int a2, int b1, int b2) +{ + key->a1 = a1; + key->a2 = a2; + key->b1 = b1; + key->b2 = b2; +} + +/*an immense amount of duplication goes on here. . .a major performance hit, I'm sure*/ +static CollPair* cloth_edge_collision ( ModifierData *md1, ModifierData *md2, + BVHTreeOverlap *overlap, CollPair *collpair, + GHash *visithash, MemArena *arena) +{ + ClothModifierData *clmd = ( ClothModifierData * ) md1; + CollisionModifierData *collmd = ( CollisionModifierData * ) md2; + MFace *face1=NULL, *face2 = NULL; + ClothVertex *verts1 = clmd->clothObject->verts; + double distance = 0; + edgepairkey *key, tstkey; + float epsilon1 = clmd->coll_parms->epsilon; + float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); + float no[3], uv[3], t, relnor; + int i, i1, i2, i3, i4, i5, i6; + Cloth *cloth = clmd->clothObject; + float n1[3], n2[3], off[3], v1[2][3], v2[2][3], v3[2][3], v4[2][3], v5[2][3], v6[2][3]; + void **verts[] = {v1, v2, v3, v4, v5, v6}; + int j, ret, bp1, bp2, bp3, ap1, ap2, ap3, table[6]; + + face1 = & ( clmd->clothObject->mfaces[overlap->indexA] ); + face2 = & ( collmd->mfaces[overlap->indexB] ); + + // check all 4 possible collisions + for ( i = 0; i < 4; i++ ) + { + if ( i == 0 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v2; + ap3 = face1->v3; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v2; + bp3 = face2->v3; + } + else if ( i == 1 ) + { + if ( face1->v4 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v3; + ap3 = face1->v4; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v2; + bp3 = face2->v3; + } + else { + continue; + } + } + if ( i == 2 ) + { + if ( face2->v4 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v2; + ap3 = face1->v3; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v3; + bp3 = face2->v4; + } + else { + continue; + } + } + else if ( i == 3 ) + { + if ( face1->v4 && face2->v4 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v3; + ap3 = face1->v4; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v3; + bp3 = face2->v4; + } + else { + continue; + } + } + + copy_v3_v3(v1[0], cloth->verts[ap1].txold); + copy_v3_v3(v1[1], cloth->verts[ap1].tx); + copy_v3_v3(v2[0], cloth->verts[ap2].txold); + copy_v3_v3(v2[1], cloth->verts[ap2].tx); + copy_v3_v3(v3[0], cloth->verts[ap3].txold); + copy_v3_v3(v3[1], cloth->verts[ap3].tx); + + copy_v3_v3(v4[0], collmd->current_x[bp1].co); + copy_v3_v3(v4[1], collmd->current_xnew[bp1].co); + copy_v3_v3(v5[0], collmd->current_x[bp2].co); + copy_v3_v3(v5[1], collmd->current_xnew[bp2].co); + copy_v3_v3(v6[0], collmd->current_x[bp3].co); + copy_v3_v3(v6[1], collmd->current_xnew[bp3].co); + + normal_tri_v3(n2, v4[1], v5[1], v6[1]); + + /*offset new positions a bit, to account for margins*/ + i1 = ap1; i2 = ap2; i3 = ap3; + i4 = bp1; i5 = bp2; i6 = bp3; + + for (j=0; j<3; j++) { + int collp1, collp2, k, j2 = (j+1)%3; + + table[0] = ap1; table[1] = ap2; table[2] = ap3; + table[3] = bp1; table[4] = bp2; table[5] = bp3; + for (k=0; k<3; k++) { + float p1[3], p2[3]; + int k2 = (k+1)%3; + + get_edgepairkey(&tstkey, table[j], table[j2], table[k+3], table[k2+3]); + //if (BLI_ghash_haskey(visithash, &tstkey)) + // continue; + + key = BLI_memarena_alloc(arena, sizeof(edgepairkey)); + *key = tstkey; + BLI_ghash_insert(visithash, key, NULL); + + sub_v3_v3v3(p1, verts[j], verts[j2]); + sub_v3_v3v3(p2, verts[k+3], verts[k2+3]); + + cross_v3_v3v3(off, p1, p2); + normalize_v3(off); + + if (dot_v3v3(n2, off) < 0.0) + negate_v3(off); + + mul_v3_fl(off, epsilon1 + epsilon2 + ALMOST_ZERO); + copy_v3_v3(p1, verts[k+3]); + copy_v3_v3(p2, verts[k2+3]); + add_v3_v3(p1, off); + add_v3_v3(p2, off); + + ret = eltopo_line_line_moving_isect_v3v3_f(verts[j], table[j], verts[j2], table[j2], + p1, table[k+3], p2, table[k2+3], + no, uv, &t, &relnor); + /*cloth vert versus coll face*/ + if (ret) { + collpair->ap1 = table[j]; collpair->ap2 = table[j2]; + collpair->bp1 = table[k+3]; collpair->bp2 = table[k2+3]; + + /*I'm not sure if this is correct, but hopefully it's + better then simply ignoring back edges*/ + if (dot_v3v3(n2, no) < 0.0) { + negate_v3(no); + } + + copy_v3_v3(collpair->normal, no); + mul_v3_v3fl(collpair->vector, collpair->normal, relnor); + collpair->distance = relnor; + collpair->time = t; + + copy_v2_v2(collpair->bary, uv); + + collpair->flag = COLLISION_IS_EDGES; + collpair++; + } + } + } + } + + return collpair; +} + +static int cloth_edge_collision_response_moving ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) +{ + int result = 0; + Cloth *cloth1; + float w1, w2; + float v1[3], v2[3], relativeVelocity[3]; + float magrelVel, pimpulse[3]; + + cloth1 = clmd->clothObject; + + for ( ; collpair != collision_end; collpair++ ) + { + if (!(collpair->flag & COLLISION_IS_EDGES)) + continue; + + // was: txold + w1 = collpair->bary[0]; w2 = collpair->bary[1]; + + // Calculate relative "velocity". + VECADDFAC(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w1); + VECADDFAC(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, w2); + + VECSUB ( relativeVelocity, v2, v1); + + // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). + magrelVel = INPR ( relativeVelocity, collpair->normal ); + + // If v_n_mag < 0 the edges are approaching each other. + if ( magrelVel > ALMOST_ZERO ) + { + // Calculate Impulse magnitude to stop all motion in normal direction. + float magtangent = 0, repulse = 0, d = 0; + double impulse = 0.0; + float vrel_t_pre[3]; + float temp[3], spf; + + zero_v3(pimpulse); + + // calculate tangential velocity + VECCOPY ( temp, collpair->normal ); + mul_v3_fl( temp, magrelVel ); + VECSUB ( vrel_t_pre, relativeVelocity, temp ); + + // Decrease in magnitude of relative tangential velocity due to coulomb friction + // in original formula "magrelVel" should be the "change of relative velocity in normal direction" + magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) ); + + // Apply friction impulse. + if ( magtangent > ALMOST_ZERO ) + { + normalize_v3( vrel_t_pre ); + + impulse = magtangent; + VECADDMUL ( pimpulse, vrel_t_pre, impulse); + } + + // Apply velocity stopping impulse + // I_c = m * v_N / 2.0 + // no 2.0 * magrelVel normally, but looks nicer DG + impulse = magrelVel; + + mul_v3_fl(collpair->normal, 0.5); + VECADDMUL ( pimpulse, collpair->normal, impulse); + + // Apply repulse impulse if distance too short + // I_r = -min(dt*kd, m(0,1d/dt - v_n)) + spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; + + d = collpair->distance; + if ( ( magrelVel < 0.1*d*spf && ( d > ALMOST_ZERO ) ) ) + { + repulse = MIN2 ( d*1.0/spf, 0.1*d*spf - magrelVel ); + + // stay on the safe side and clamp repulse + if ( impulse > ALMOST_ZERO ) + repulse = MIN2 ( repulse, 5.0*impulse ); + repulse = MAX2 ( impulse, repulse ); + + impulse = repulse / ( 5.0 ); // original 2.0 / 0.25 + VECADDMUL ( pimpulse, collpair->normal, impulse); + } + + w2 = 1.0f-w1; + if (w1 < 0.5) + w1 *= 2.0; + else + w2 *= 2.0; + + VECADDFAC(cloth1->verts[collpair->ap1].impulse, cloth1->verts[collpair->ap1].impulse, pimpulse, w1*2.0); + VECADDFAC(cloth1->verts[collpair->ap2].impulse, cloth1->verts[collpair->ap2].impulse, pimpulse, w2*2.0); + + cloth1->verts[collpair->ap1].impulse_count++; + cloth1->verts[collpair->ap2].impulse_count++; + + result = 1; + } + } + + return result; +} + +static int cloth_collision_response_moving ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) +{ + int result = 0; + Cloth *cloth1; + float w1, w2, w3, u1, u2, u3; + float v1[3], v2[3], relativeVelocity[3]; + float magrelVel; + float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); + + cloth1 = clmd->clothObject; + + for ( ; collpair != collision_end; collpair++ ) + { + if (collpair->flag & COLLISION_IS_EDGES) + continue; + + if ( collpair->flag & COLLISION_USE_COLLFACE ) { + // was: txold + w1 = collpair->bary[0]; w2 = collpair->bary[1]; w3 = collpair->bary[2]; + + // Calculate relative "velocity". + collision_interpolateOnTriangle ( v1, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, w1, w2, w3); + + VECSUB ( relativeVelocity, v1, cloth1->verts[collpair->collp].tv); + + // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). + magrelVel = INPR ( relativeVelocity, collpair->normal ); + + // If v_n_mag < 0 the edges are approaching each other. + if ( magrelVel > ALMOST_ZERO ) + { + // Calculate Impulse magnitude to stop all motion in normal direction. + float magtangent = 0, repulse = 0, d = 0; + double impulse = 0.0; + float vrel_t_pre[3]; + float temp[3], spf; + + // calculate tangential velocity + VECCOPY ( temp, collpair->normal ); + mul_v3_fl( temp, magrelVel ); + VECSUB ( vrel_t_pre, relativeVelocity, temp ); + + // Decrease in magnitude of relative tangential velocity due to coulomb friction + // in original formula "magrelVel" should be the "change of relative velocity in normal direction" + magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) ); + + // Apply friction impulse. + if ( magtangent > ALMOST_ZERO ) + { + normalize_v3( vrel_t_pre ); + + impulse = magtangent; // 2.0 * + VECADDMUL ( cloth1->verts[collpair->collp].impulse, vrel_t_pre, impulse); + } + + // Apply velocity stopping impulse + // I_c = m * v_N / 2.0 + // no 2.0 * magrelVel normally, but looks nicer DG + impulse = magrelVel/2.0; + + VECADDMUL ( cloth1->verts[collpair->collp].impulse, collpair->normal, impulse); + cloth1->verts[collpair->collp].impulse_count++; + + // Apply repulse impulse if distance too short + // I_r = -min(dt*kd, m(0,1d/dt - v_n)) + spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; + + d = -collpair->distance; + if ( ( magrelVel < 0.1*d*spf ) && ( d > ALMOST_ZERO ) ) + { + repulse = MIN2 ( d*1.0/spf, 0.1*d*spf - magrelVel ); + + // stay on the safe side and clamp repulse + if ( impulse > ALMOST_ZERO ) + repulse = MIN2 ( repulse, 5.0*impulse ); + repulse = MAX2 ( impulse, repulse ); + + impulse = repulse / ( 5.0 ); // original 2.0 / 0.25 + VECADDMUL ( cloth1->verts[collpair->collp].impulse, collpair->normal, impulse); + } + + result = 1; + } + } else { + w1 = collpair->bary[0]; w2 = collpair->bary[1]; w3 = collpair->bary[2]; + + // Calculate relative "velocity". + collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 ); + + VECSUB ( relativeVelocity, collmd->current_v[collpair->collp].co, v1); + + // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). + magrelVel = INPR ( relativeVelocity, collpair->normal ); + + // If v_n_mag < 0 the edges are approaching each other. + if ( magrelVel > ALMOST_ZERO ) + { + // Calculate Impulse magnitude to stop all motion in normal direction. + float magtangent = 0, repulse = 0, d = 0; + double impulse = 0.0; + float vrel_t_pre[3], pimpulse[3] = {0.0f, 0.0f, 0.0f}; + float temp[3], spf; + + // calculate tangential velocity + VECCOPY ( temp, collpair->normal ); + mul_v3_fl( temp, magrelVel ); + VECSUB ( vrel_t_pre, relativeVelocity, temp ); + + // Decrease in magnitude of relative tangential velocity due to coulomb friction + // in original formula "magrelVel" should be the "change of relative velocity in normal direction" + magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) ); + + // Apply friction impulse. + if ( magtangent > ALMOST_ZERO ) + { + normalize_v3( vrel_t_pre ); + + impulse = magtangent; // 2.0 * + VECADDMUL ( pimpulse, vrel_t_pre, impulse); + } + + // Apply velocity stopping impulse + // I_c = m * v_N / 2.0 + // no 2.0 * magrelVel normally, but looks nicer DG + impulse = magrelVel/2.0; + + VECADDMUL ( pimpulse, collpair->normal, impulse); + + // Apply repulse impulse if distance too short + // I_r = -min(dt*kd, m(0,1d/dt - v_n)) + spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; + + d = -collpair->distance; + if ( ( magrelVel < 0.1*d*spf ) && ( d > ALMOST_ZERO ) ) + { + repulse = MIN2 ( d*1.0/spf, 0.1*d*spf - magrelVel ); + + // stay on the safe side and clamp repulse + if ( impulse > ALMOST_ZERO ) + repulse = MIN2 ( repulse, 5.0*impulse ); + repulse = MAX2 ( impulse, repulse ); + + impulse = repulse / ( 2.0 ); // original 2.0 / 0.25 + VECADDMUL ( pimpulse, collpair->normal, impulse); + } + + if (w1 < 0.5) w1 *= 2.0; + if (w2 < 0.5) w2 *= 2.0; + if (w3 < 0.5) w3 *= 2.0; + + VECADDMUL(cloth1->verts[collpair->ap1].impulse, pimpulse, w1*2.0); + VECADDMUL(cloth1->verts[collpair->ap2].impulse, pimpulse, w2*2.0); + VECADDMUL(cloth1->verts[collpair->ap3].impulse, pimpulse, w3*2.0);; + cloth1->verts[collpair->ap1].impulse_count++; + cloth1->verts[collpair->ap2].impulse_count++; + cloth1->verts[collpair->ap3].impulse_count++; + + result = 1; + } + } + } + + return result; +} + + +typedef struct tripairkey { + int p, a1, a2, a3; +} tripairkey; + +unsigned int tripair_hash(void *vkey) +{ + tripairkey *key = vkey; + int keys[4] = {key->p, key->a1, key->a2, key->a3}; + int i, j; + + for (i=0; i<4; i++) { + for (j=0; j<3; j++) { + if (keys[j] >= keys[j+1]) { + SWAP(int, keys[j], keys[j+1]); + } + } + } + + return keys[0]*101 + keys[1]*72 + keys[2]*53 + keys[3]*34; +} + +int tripair_cmp(const void *va, const void *vb) +{ + tripairkey *a = va, *b = vb; + int keysa[4] = {a->p, a->a1, a->a2, a->a3}; + int keysb[4] = {b->p, b->a1, b->a2, b->a3}; + int i; + + for (i=0; i<4; i++) { + int j, ok=0; + for (j=0; j<4; j++) { + if (keysa[i] == keysa[j]) { + ok = 1; + break; + } + } + if (!ok) + return -1; + } + + return 0; +} + +static void get_tripairkey(tripairkey *key, int p, int a1, int a2, int a3) +{ + key->a1 = a1; + key->a2 = a2; + key->a3 = a3; + key->p = p; +} + +static int checkvisit(MemArena *arena, GHash *gh, int p, int a1, int a2, int a3) +{ + tripairkey key, *key2; + + get_tripairkey(&key, p, a1, a2, a3); + if (BLI_ghash_haskey(gh, &key)) + return 1; + + key2 = BLI_memarena_alloc(arena, sizeof(*key2)); + *key2 = key; + BLI_ghash_insert(gh, key2, NULL); + + return 0; +} + +int cloth_point_tri_moving_v3v3_f(float v1[2][3], int i1, float v2[2][3], int i2, + float v3[2][3], int i3, float v4[2][3], int i4, + float normal[3], float bary[3], float *t, + float *relnor, GHash *gh, MemArena *arena) +{ + if (checkvisit(arena, gh, i1, i2, i3, i4)) + return 0; + + return eltopo_point_tri_moving_v3v3_f(v1, i1, v2, i2, v3, i3, v4, i4, normal, bary, t, relnor); +} + +static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap *overlap, + CollPair *collpair, double dt, GHash *gh, MemArena *arena) +{ + ClothModifierData *clmd = ( ClothModifierData * ) md1; + CollisionModifierData *collmd = ( CollisionModifierData * ) md2; + MFace *face1=NULL, *face2 = NULL; + ClothVertex *verts1 = clmd->clothObject->verts; + double distance = 0; + float epsilon1 = clmd->coll_parms->epsilon; + float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); + float no[3], uv[3], t, relnor; + int i, i1, i2, i3, i4, i5, i6; + Cloth *cloth = clmd->clothObject; + float n1[3], sdis, p[3], l, n2[3], off[3], v1[2][3], v2[2][3], v3[2][3], v4[2][3], v5[2][3], v6[2][3]; + int j, ret, bp1, bp2, bp3, ap1, ap2, ap3; + + face1 = & ( clmd->clothObject->mfaces[overlap->indexA] ); + face2 = & ( collmd->mfaces[overlap->indexB] ); + + // check all 4 possible collisions + for ( i = 0; i < 4; i++ ) + { + if ( i == 0 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v2; + ap3 = face1->v3; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v2; + bp3 = face2->v3; + } + else if ( i == 1 ) + { + if ( face1->v4 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v3; + ap3 = face1->v4; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v2; + bp3 = face2->v3; + } + else { + continue; + } + } + if ( i == 2 ) + { + if ( face2->v4 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v2; + ap3 = face1->v3; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v3; + bp3 = face2->v4; + } + else { + continue; + } + } + else if ( i == 3 ) + { + if ( face1->v4 && face2->v4 ) + { + // fill faceA + ap1 = face1->v1; + ap2 = face1->v3; + ap3 = face1->v4; + + // fill faceB + bp1 = face2->v1; + bp2 = face2->v3; + bp3 = face2->v4; + } + else { + continue; + } + } + + copy_v3_v3(v1[0], cloth->verts[ap1].txold); + copy_v3_v3(v1[1], cloth->verts[ap1].tx); + copy_v3_v3(v2[0], cloth->verts[ap2].txold); + copy_v3_v3(v2[1], cloth->verts[ap2].tx); + copy_v3_v3(v3[0], cloth->verts[ap3].txold); + copy_v3_v3(v3[1], cloth->verts[ap3].tx); + + copy_v3_v3(v4[0], collmd->current_x[bp1].co); + copy_v3_v3(v4[1], collmd->current_xnew[bp1].co); + copy_v3_v3(v5[0], collmd->current_x[bp2].co); + copy_v3_v3(v5[1], collmd->current_xnew[bp2].co); + copy_v3_v3(v6[0], collmd->current_x[bp3].co); + copy_v3_v3(v6[1], collmd->current_xnew[bp3].co); + + normal_tri_v3(n2, v4[1], v5[1], v6[1]); + + sdis = clmd->coll_parms->distance_repel + epsilon2 + FLT_EPSILON; + + /*apply a repulsion force, to help the solver along*/ + copy_v3_v3(off, n2); + negate_v3(off); + if (isect_ray_plane_v3(v1[1], off, v4[1], v5[1], v6[1], &l, 0)) { + if (l >= 0.0 && l < sdis) { + mul_v3_fl(off, (l-sdis)*cloth->verts[ap1].mass*dt*clmd->coll_parms->repel_force*0.1); + + add_v3_v3(cloth->verts[ap1].tv, off); + add_v3_v3(cloth->verts[ap2].tv, off); + add_v3_v3(cloth->verts[ap3].tv, off); + } + } + + /*offset new positions a bit, to account for margins*/ + copy_v3_v3(off, n2); + mul_v3_fl(off, epsilon1 + epsilon2 + ALMOST_ZERO); + add_v3_v3(v4[1], off); add_v3_v3(v5[1], off); add_v3_v3(v6[1], off); + + i1 = ap1; i2 = ap2; i3 = ap3; + i4 = bp1+cloth->numverts; i5 = bp2+cloth->numverts; i6 = bp3+cloth->numverts; + + for (j=0; j<6; j++) { + int collp; + + switch (j) { + case 0: + ret = cloth_point_tri_moving_v3v3_f(v1, i1, v4, i4, v5, i5, v6, i6, no, uv, &t, &relnor, gh, arena); + collp = ap1; + break; + case 1: + collp = ap2; + ret = cloth_point_tri_moving_v3v3_f(v2, i2, v4, i4, v5, i5, v6, i6, no, uv, &t, &relnor, gh, arena); + break; + case 2: + collp = ap3; + ret = cloth_point_tri_moving_v3v3_f(v3, i3, v4, i4, v5, i5, v6, i6, no, uv, &t, &relnor, gh, arena); + break; + case 3: + collp = bp1; + ret = cloth_point_tri_moving_v3v3_f(v4, i4, v1, i1, v2, i2, v3, i3, no, uv, &t, &relnor, gh, arena); + break; + case 4: + collp = bp2; + ret = cloth_point_tri_moving_v3v3_f(v5, i5, v1, i1, v2, i2, v3, i3, no, uv, &t, &relnor, gh, arena); + break; + case 5: + collp = bp3; + ret = cloth_point_tri_moving_v3v3_f(v6, i6, v1, i1, v2, i2, v3, i3, no, uv, &t, &relnor, gh, arena); + break; + } + + /*cloth vert versus coll face*/ + if (ret && j < 3) { + collpair->bp1 = bp1; collpair->bp2 = bp2; collpair->bp3 = bp3; + collpair->collp = collp; + + copy_v3_v3(collpair->normal, no); + mul_v3_v3fl(collpair->vector, collpair->normal, relnor); + collpair->distance = relnor; + collpair->time = t; + + copy_v3_v3(collpair->bary, uv); + + collpair->flag = COLLISION_USE_COLLFACE; + collpair++; + } else if (ret && j >= 3) { /*coll vert versus cloth face*/ + collpair->ap1 = ap1; collpair->ap2 = ap2; collpair->ap3 = ap3; + collpair->collp = collp; + + copy_v3_v3(collpair->normal, no); + mul_v3_v3fl(collpair->vector, collpair->normal, relnor); + collpair->distance = relnor; + collpair->time = t; + + copy_v3_v3(collpair->bary, uv); + + collpair->flag = 0; + collpair++; + } + } + } + + return collpair; +} + +static void machine_epsilon_offset(Cloth *cloth) { + ClothVertex *cv; + int i, j; + + cv = cloth->verts; + for (i=0; i<cloth->numverts; i++, cv++) { + /*aggrevatingly enough, it's necassary to offset the coordinates + by a multiple of the 32-bit floating point epsilon when switching + into doubles*/ + #define RNDSIGN (float)(-1*(BLI_rand()%2==0)|1) + for (j=0; j<3; j++) { + cv->tx[j] += FLT_EPSILON*30.0f*RNDSIGN; + cv->txold[j] += FLT_EPSILON*30.0f*RNDSIGN; + cv->tv[j] += FLT_EPSILON*30.0f*RNDSIGN; + } + } +} + +#else //Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned -static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap *overlap, CollPair *collpair ) +static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, + BVHTreeOverlap *overlap, CollPair *collpair, float dt ) { ClothModifierData *clmd = ( ClothModifierData * ) md1; CollisionModifierData *collmd = ( CollisionModifierData * ) md2; + Cloth *cloth = clmd->clothObject; MFace *face1=NULL, *face2 = NULL; #ifdef USE_BULLET ClothVertex *verts1 = clmd->clothObject->verts; @@ -614,6 +1408,7 @@ static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTree double distance = 0; float epsilon1 = clmd->coll_parms->epsilon; float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); + float n2[3], sdis, l; int i; face1 = & ( clmd->clothObject->mfaces[overlap->indexA] ); @@ -685,7 +1480,28 @@ static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTree else break; } + + normal_tri_v3(n2, collmd->current_xnew[collpair->bp1].co, + collmd->current_xnew[collpair->bp2].co, + collmd->current_xnew[collpair->bp3].co); + + sdis = clmd->coll_parms->distance_repel + epsilon2 + FLT_EPSILON; + + /*apply a repulsion force, to help the solver along. + this is kindof crude, it only tests one vert of the triangle*/ + if (isect_ray_plane_v3(cloth->verts[collpair->ap1].tx, n2, collmd->current_xnew[collpair->bp1].co, + collmd->current_xnew[collpair->bp2].co, + collmd->current_xnew[collpair->bp3].co, &l, 0)) + { + if (l >= 0.0 && l < sdis) { + mul_v3_fl(n2, (l-sdis)*cloth->verts[collpair->ap1].mass*dt*clmd->coll_parms->repel_force*0.1); + add_v3_v3(cloth->verts[collpair->ap1].tv, n2); + add_v3_v3(cloth->verts[collpair->ap2].tv, n2); + add_v3_v3(cloth->verts[collpair->ap3].tv, n2); + } + } + #ifdef USE_BULLET // calc distance + normal distance = plNearestPoints ( @@ -741,6 +1557,8 @@ static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTree } return collpair; } +#endif + #if 0 static int cloth_collision_response_moving( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) @@ -1446,17 +2264,45 @@ void free_collider_cache(ListBase **colliders) } } -static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap) + +static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, + CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap, double dt) { int i; +#ifdef USE_ELTOPO + GHash *visithash = BLI_ghash_new(edgepair_hash, edgepair_cmp, "visthash, collision.c"); + GHash *tri_visithash = BLI_ghash_new(tripair_hash, tripair_cmp, "tri_visthash, collision.c"); + MemArena *arena = BLI_memarena_new(1<<16, "edge hash arena, collision.c"); +#endif - *collisions = ( CollPair* ) MEM_mallocN ( sizeof ( CollPair ) * numresult * 4, "collision array" ); //*4 since cloth_collision_static can return more than 1 collision + *collisions = ( CollPair* ) MEM_mallocN ( sizeof ( CollPair ) * numresult * 64, "collision array" ); //*4 since cloth_collision_static can return more than 1 collision *collisions_index = *collisions; + +#ifdef USE_ELTOPO + machine_epsilon_offset(clmd->clothObject); for ( i = 0; i < numresult; i++ ) { - *collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, overlap+i, *collisions_index ); + *collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, + overlap+i, *collisions_index, dt, tri_visithash, arena ); } + + for ( i = 0; i < numresult; i++ ) + { + *collisions_index = cloth_edge_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, + overlap+i, *collisions_index, visithash, arena ); + } + BLI_ghash_free(visithash, NULL, NULL); + BLI_ghash_free(tri_visithash, NULL, NULL); + BLI_memarena_free(arena); +#else + for ( i = 0; i < numresult; i++ ) + { + *collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, + overlap+i, *collisions_index, dt ); + } +#endif + } static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index) @@ -1481,11 +2327,19 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision if ( collmd->bvhtree ) { +#ifdef USE_ELTOPO + result += cloth_collision_response_moving(clmd, collmd, collisions, collisions_index); + result += cloth_edge_collision_response_moving(clmd, collmd, collisions, collisions_index); +#else result += cloth_collision_response_static ( clmd, collmd, collisions, collisions_index ); - +#endif +#ifdef USE_ELTOPO + { +#else // apply impulses in parallel if ( result ) { +#endif for ( i = 0; i < numverts; i++ ) { // calculate "velocities" (just xnew = xold + v; no dt in v) @@ -1518,7 +2372,7 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh==NULL) return 0; - + verts = cloth->verts; numfaces = cloth->numfaces; numverts = cloth->numverts; @@ -1557,6 +2411,7 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl continue; /* move object to position (step) in time */ + collision_move_object ( collmd, step + dt, step ); /* search for overlapping collision pairs */ @@ -1565,7 +2420,8 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl // go to next object if no overlap is there if( result && overlap ) { /* check if collisions really happen (costly near check) */ - cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i], &collisions_index[i], result, overlap); + cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i], + &collisions_index[i], result, overlap, dt/(float)clmd->coll_parms->loop_count); // resolve nearby collisions ret += cloth_bvh_objcollisions_resolve ( clmd, collmd, collisions[i], collisions_index[i]); @@ -1721,5 +2577,5 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl if(collobjs) MEM_freeN(collobjs); - return MIN2 ( ret, 1 ); + return 1|MIN2 ( ret, 1 ); } diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 7f0292b2f22..c3a7b6b204d 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -50,7 +50,7 @@ #include "BKE_global.h" -#define CLOTH_OPENMP_LIMIT 25 +#define CLOTH_OPENMP_LIMIT 512 #ifdef _WIN32 #include <windows.h> @@ -939,7 +939,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z s = dot_lfvector(r, r, numverts); starget = s * sqrt(conjgrad_epsilon); - while((s>starget && conjgrad_loopcount < conjgrad_looplimit)) + while(s>starget && conjgrad_loopcount < conjgrad_looplimit) { // Mul(q,A,d); // q = A*d; mul_bfmatrix_lfvector(q, lA, d); @@ -1749,15 +1749,93 @@ static void simulate_implicit_euler(lfVector *Vnew, lfVector *UNUSED(lX), lfVect del_lfvector(dFdXmV); } +/*computes where the cloth would be if it were subject to perfectly stiff edges + (edge distance constraints) in a lagrangian solver. then add forces to help + guide the implicit solver to that state. this function is called after + collisions*/ +int cloth_calc_helper_forces(Object *ob, ClothModifierData * clmd, float (*initial_cos)[3], float step, float dt) +{ + Cloth *cloth= clmd->clothObject; + float (*cos)[3] = MEM_callocN(sizeof(float)*3*cloth->numverts, "cos cloth_calc_helper_forces"); + float *masses = MEM_callocN(sizeof(float)*cloth->numverts, "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++) { + copy_v3_v3(cos[i], cv->tx); + + if (cv->goal == 1.0f || len_v3v3(initial_cos[i], cv->tx) != 0.0) { + masses[i] = 1e+10; + } else { + masses[i] = cv->mass; + } + } + + steps = 55; + for (i=0; i<steps; i++) { + for (node=cloth->springs; node; node=node->next) { + ClothVertex *cv1, *cv2; + int v1, v2; + float len, c, l, vec[3]; + + spring = node->link; + if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR) + continue; + + v1 = spring->ij; v2 = spring->kl; + cv1 = cloth->verts + v1; + cv2 = cloth->verts + v2; + len = len_v3v3(cos[v1], cos[v2]); + + sub_v3_v3v3(vec, cos[v1], cos[v2]); + normalize_v3(vec); + + c = (len - spring->restlen); + if (c == 0.0) + continue; + + l = c / ((1.0/masses[v1]) + (1.0/masses[v2])); + + mul_v3_fl(vec, -(1.0/masses[v1])*l); + add_v3_v3(cos[v1], vec); + + sub_v3_v3v3(vec, cos[v2], cos[v1]); + normalize_v3(vec); + + mul_v3_fl(vec, -(1.0/masses[v2])*l); + add_v3_v3(cos[v2], vec); + } + } + + cv = cloth->verts; + for (i=0; i<cloth->numverts; i++, cv++) { + float vec[3]; + + /*compute forces*/ + sub_v3_v3v3(vec, cos[i], cv->tx); + mul_v3_fl(vec, cv->mass*dt*20.0); + add_v3_v3(cv->tv, vec); + //copy_v3_v3(cv->tx, cos[i]); + } + + MEM_freeN(cos); + MEM_freeN(masses); + + return 1; +} int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors) { unsigned int i=0; float step=0.0f, tf=clmd->sim_parms->timescale; Cloth *cloth = clmd->clothObject; - ClothVertex *verts = cloth->verts; + ClothVertex *verts = cloth->verts, *cv; unsigned int numverts = cloth->numverts; float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame; float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; + float (*initial_cos)[3] = MEM_callocN(sizeof(float)*3*cloth->numverts, "initial_cos implicit.c"); Implicit_Data *id = cloth->implicit; int do_extra_solve; @@ -1817,15 +1895,26 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase VECCOPY(verts[i].v, verts[i].tv); } + for (i=0, cv=cloth->verts; i<cloth->numverts; i++, cv++) { + copy_v3_v3(initial_cos[i], cv->tx); + } + // call collision function // TODO: check if "step" or "step+dt" is correct - dg 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++) { // correct velocity again, just to be sure we had to change it due to adaptive collisions VECSUB(verts[i].tv, verts[i].tx, id->X[i]); + } + + //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++) + { if(do_extra_solve) { @@ -1886,6 +1975,8 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase } } + MEM_freeN(initial_cos); + return 1; } diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 8937612b41b..756d1501536 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -91,6 +91,11 @@ int isect_line_line_v3(const float v1[3], const float v2[3], int isect_line_line_strict_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float vi[3], float *lambda); +/*if clip is nonzero, will only return true if lambda is >= 0.0 + (i.e. intersection point is along positive d)*/ +int isect_ray_plane_v3(float p1[3], float d[3], float v0[3], + float v1[3], float v2[3], float *lambda, int clip); + /* line/ray triangle */ int isect_line_tri_v3(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *lambda, float uv[2]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 4af56c66dde..afce5a602ed 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -486,7 +486,6 @@ int isect_line_tri_v3(const float p1[3], const float p2[3], const float v0[3], c return 1; } - /* moved from effect.c test if the ray starting at p1 going in d direction intersects the triangle v0..v2 return non zero if it does @@ -527,6 +526,35 @@ int isect_ray_tri_v3(const float p1[3], const float d[3], const float v0[3], con return 1; } +int isect_ray_plane_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, int clip) +{ + float p[3], s[3], e1[3], e2[3], q[3]; + float a, f, u, v; + + sub_v3_v3v3(e1, v1, v0); + sub_v3_v3v3(e2, v2, v0); + + cross_v3_v3v3(p, d, e2); + a = dot_v3v3(e1, p); + /* note: these values were 0.000001 in 2.4x but for projection snapping on + * a human head (1BU==1m), subsurf level 2, this gave many errors - campbell */ + if ((a > -0.00000001f) && (a < 0.00000001f)) return 0; + f = 1.0f/a; + + sub_v3_v3v3(s, p1, v0); + + u = f * dot_v3v3(s, p); + + cross_v3_v3v3(q, s, e1); + + v = f * dot_v3v3(d, q); + + *lambda = f * dot_v3v3(e2, q); + if (clip && (*lambda < 0.0f)) return 0; + + return 1; +} + int isect_ray_tri_epsilon_v3(const float p1[3], const float d[3], const float v0[3], const float v1[3], const float v2[3], float *lambda, float uv[2], const float epsilon) { float p[3], s[3], e1[3], e2[3], q[3]; diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index 1f78366287f..b7a8f21d724 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -96,6 +96,7 @@ typedef struct ClothCollSettings float self_friction; /* Fiction/damping with self contact. */ float friction; /* Friction/damping applied on contact with other object.*/ float selfepsilon; /* for selfcollision */ + float repel_force, distance_repel; int flags; /* collision flags defined in BKE_cloth.h */ short self_loop_count; /* How many iterations for the selfcollision loop */ short loop_count; /* How many iterations for the collision loop. */ diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index a7f308742ac..afd30433c5d 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -428,6 +428,20 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_COLLSETTINGS_FLAG_ENABLED); RNA_def_property_ui_text(prop, "Enable Collision", "Enable collisions with other objects"); RNA_def_property_update(prop, 0, "rna_cloth_update"); + + prop= RNA_def_property(srna, "repel_force", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "repel_force"); + RNA_def_property_range(prop, 0.0f, 20.0f); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Repulsion Force", "Repulsion force to apply on cloth when close to colliding"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + + prop= RNA_def_property(srna, "distance_repel", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "distance_repel"); + RNA_def_property_range(prop, 0.001f, 10.0f); + RNA_def_property_float_default(prop, 0.005f); + RNA_def_property_ui_text(prop, "Repulsion Distance", "Maximum distance to apply repulsion force, must be greater then minimum distance"); + RNA_def_property_update(prop, 0, "rna_cloth_update"); prop= RNA_def_property(srna, "distance_min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "epsilon"); |