=trunk=
Recommitted eltopo collision code (but disabled by default) with Genscher's permission. To use, you need to install liblapack and libblas
This commit is contained in:
parent
7cc98cbb0b
commit
088899236b
|
@ -114,6 +114,7 @@ option(WITH_BUILDINFO "Include extra build details (only disable for develop
|
|||
option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development & for incompatible C++ compilers)" ON)
|
||||
option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke and audio effects)" OFF)
|
||||
option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
|
||||
option(WITH_ELTOPO "Enable Eltopo Continuous Collision Engine" OFF)
|
||||
option(WITH_GAMEENGINE "Enable Game Engine" ON)
|
||||
option(WITH_PLAYER "Build Player" OFF)
|
||||
# (unix defaults to OpenMP On)
|
||||
|
|
|
@ -99,7 +99,7 @@ def validate_arguments(args, bc):
|
|||
'WITH_BF_INTERNATIONAL',
|
||||
'BF_GETTEXT', 'BF_GETTEXT_INC', 'BF_GETTEXT_LIB', 'WITH_BF_GETTEXT_STATIC', 'BF_GETTEXT_LIB_STATIC', 'BF_GETTEXT_LIBPATH',
|
||||
'WITH_BF_ICONV', 'BF_ICONV', 'BF_ICONV_INC', 'BF_ICONV_LIB', 'BF_ICONV_LIBPATH',
|
||||
'WITH_BF_GAMEENGINE', 'WITH_BF_BULLET', 'BF_BULLET', 'BF_BULLET_INC', 'BF_BULLET_LIB',
|
||||
'WITH_BF_GAMEENGINE', 'WITH_BF_BULLET', 'WITH_BF_ELTOPO', 'BF_BULLET', 'BF_BULLET_INC', 'BF_BULLET_LIB',
|
||||
'BF_WINTAB', 'BF_WINTAB_INC',
|
||||
'WITH_BF_FREETYPE', 'BF_FREETYPE', 'BF_FREETYPE_INC', 'BF_FREETYPE_LIB', 'BF_FREETYPE_LIBPATH', 'BF_FREETYPE_LIB_STATIC', 'WITH_BF_FREETYPE_STATIC',
|
||||
'WITH_BF_QUICKTIME', 'BF_QUICKTIME', 'BF_QUICKTIME_INC', 'BF_QUICKTIME_LIB', 'BF_QUICKTIME_LIBPATH',
|
||||
|
@ -365,6 +365,8 @@ def read_opts(env, cfg, args):
|
|||
(BoolVariable('WITH_BF_GAMEENGINE', 'Build with gameengine' , False)),
|
||||
|
||||
(BoolVariable('WITH_BF_BULLET', 'Use Bullet if true', True)),
|
||||
(BoolVariable('WITH_BF_ELTOPO', 'Use Eltopo collision library if true', False)),
|
||||
|
||||
('BF_BULLET', 'Bullet base dir', ''),
|
||||
('BF_BULLET_INC', 'Bullet include path', ''),
|
||||
('BF_BULLET_LIB', 'Bullet library', ''),
|
||||
|
|
|
@ -31,6 +31,10 @@ if(WITH_BULLET)
|
|||
add_subdirectory(bullet2)
|
||||
endif()
|
||||
|
||||
if(WITH_ELTOPO)
|
||||
add_subdirectory(eltopo)
|
||||
endif()
|
||||
|
||||
if(WITH_BINRELOC)
|
||||
add_subdirectory(binreloc)
|
||||
endif()
|
||||
|
|
|
@ -4,6 +4,9 @@ Import('env')
|
|||
|
||||
SConscript(['glew/SConscript'])
|
||||
|
||||
if env['WITH_BF_ELTOPO']:
|
||||
SConscript(['eltopo/SConscript'])
|
||||
|
||||
if env['WITH_BF_BULLET']:
|
||||
SConscript(['bullet2/src/SConscript'])
|
||||
|
||||
|
|
|
@ -157,6 +157,8 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, bpy.types.Panel):
|
|||
col = split.column()
|
||||
col.prop(cloth, "collision_quality", slider=True, text="Quality")
|
||||
col.prop(cloth, "distance_min", slider=True, text="Distance")
|
||||
col.prop(cloth, "repel_force", slider=True, text="Repel")
|
||||
col.prop(cloth, "distance_repel", slider=True, text="Repel Distance")
|
||||
col.prop(cloth, "friction")
|
||||
|
||||
col = split.column()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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,19 +608,807 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
|
|||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//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 )
|
||||
#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, 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;
|
||||
#endif
|
||||
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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -816,6 +816,10 @@ endif()
|
|||
bf_intern_mikktspace
|
||||
)
|
||||
|
||||
if(WITH_ELTOPO)
|
||||
list(APPEND BLENDER_SORTED_LIBS extern_eltopo)
|
||||
endif()
|
||||
|
||||
if(WITH_BUILTIN_GLEW)
|
||||
list(APPEND BLENDER_SORTED_LIBS extern_glew)
|
||||
endif()
|
||||
|
|
Loading…
Reference in New Issue