Collisions: Commit of collision cleanup, put kdop-bvh structure into BLI_kdopbvh (just like kdtree interface now), huge speedup for selfcollisions, also better normal collisions (merge from cloth branch)
This commit is contained in:
@@ -24,14 +24,14 @@
|
|||||||
*
|
*
|
||||||
* The Original Code is: all of this file.
|
* The Original Code is: all of this file.
|
||||||
*
|
*
|
||||||
* Contributor(s): none yet.
|
* Contributor(s): Daniel Genrich
|
||||||
*
|
*
|
||||||
* ***** END GPL LICENSE BLOCK *****
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
*/
|
*/
|
||||||
#ifndef BKE_CLOTH_H
|
#ifndef BKE_CLOTH_H
|
||||||
#define BKE_CLOTH_H
|
#define BKE_CLOTH_H
|
||||||
|
|
||||||
#include "float.h"
|
#include <float.h>
|
||||||
|
|
||||||
#include "BLI_linklist.h"
|
#include "BLI_linklist.h"
|
||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
@@ -102,7 +102,8 @@ typedef struct Cloth
|
|||||||
unsigned char old_solver_type; /* unused, only 1 solver here */
|
unsigned char old_solver_type; /* unused, only 1 solver here */
|
||||||
unsigned char pad2;
|
unsigned char pad2;
|
||||||
short pad3;
|
short pad3;
|
||||||
struct BVH *tree; /* collision tree for this cloth object */
|
struct BVHTree *bvhtree; /* collision tree for this cloth object */
|
||||||
|
struct BVHTree *bvhselftree; /* collision tree for this cloth object */
|
||||||
struct MFace *mfaces;
|
struct MFace *mfaces;
|
||||||
struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */
|
struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */
|
||||||
struct Implicit_Data *implicitEM; /* our implicit solver connects to this pointer */
|
struct Implicit_Data *implicitEM; /* our implicit solver connects to this pointer */
|
||||||
@@ -171,17 +172,10 @@ ClothSpring;
|
|||||||
/* These are the bits used in SimSettings.flags. */
|
/* These are the bits used in SimSettings.flags. */
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
//CLOTH_SIMSETTINGS_FLAG_RESET = ( 1 << 1 ), // The CM object requires a reinitializaiton.
|
|
||||||
CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ),// object is only collision object, no cloth simulation is done
|
CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ),// object is only collision object, no cloth simulation is done
|
||||||
CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled
|
CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled
|
||||||
CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled
|
CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled
|
||||||
//CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT = ( 1 << 5 ), // true if tearing is enabled
|
|
||||||
//CLOTH_SIMSETTINGS_FLAG_EDITMODE = ( 1 << 6 ), // are we in editmode? -several things disabled
|
|
||||||
//CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE = ( 1 << 7 ), /* force cache freeing */
|
|
||||||
CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */
|
CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */
|
||||||
//CLOTH_SIMSETTINGS_FLAG_LOADED = ( 1 << 9 ), /* did we just got load? */
|
|
||||||
//CLOTH_SIMSETTINGS_FLAG_AUTOPROTECT = ( 1 << 10 ), /* is autoprotect enabled? */
|
|
||||||
//CLOTH_SIMSETTINGS_FLAG_CCACHE_OUTDATED = (1 << 11), /* while protected, did cache get outdated? */
|
|
||||||
CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12) /* edit cache in editmode */
|
CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12) /* edit cache in editmode */
|
||||||
} CLOTH_SIMSETTINGS_FLAGS;
|
} CLOTH_SIMSETTINGS_FLAGS;
|
||||||
|
|
||||||
@@ -208,6 +202,7 @@ typedef enum
|
|||||||
CLOTH_SPRING_FLAG_NEEDED = ( 1 << 2 ), // springs has values to be applied
|
CLOTH_SPRING_FLAG_NEEDED = ( 1 << 2 ), // springs has values to be applied
|
||||||
} CLOTH_SPRINGS_FLAGS;
|
} CLOTH_SPRINGS_FLAGS;
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
// collision.c
|
// collision.c
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
@@ -246,7 +241,8 @@ DerivedMesh *clothModifier_do ( ClothModifierData *clmd,Object *ob, DerivedMesh
|
|||||||
void cloth_update_normals ( ClothVertex *verts, int nVerts, MFace *face, int totface );
|
void cloth_update_normals ( ClothVertex *verts, int nVerts, MFace *face, int totface );
|
||||||
|
|
||||||
// needed for collision.c
|
// needed for collision.c
|
||||||
void bvh_update_from_cloth ( ClothModifierData *clmd, int moving );
|
void bvhtree_update_from_cloth ( ClothModifierData *clmd, int moving );
|
||||||
|
void bvhselftree_update_from_cloth ( ClothModifierData *clmd, int moving );
|
||||||
|
|
||||||
// needed for editmesh.c
|
// needed for editmesh.c
|
||||||
void cloth_write_cache ( Object *ob, ClothModifierData *clmd, float framenr );
|
void cloth_write_cache ( Object *ob, ClothModifierData *clmd, float framenr );
|
||||||
@@ -261,11 +257,6 @@ int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned in
|
|||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
/* Typedefs for function pointers we need for solvers and collision detection. */
|
|
||||||
typedef void ( *CM_COLLISION_SELF ) ( ClothModifierData *clmd, int step );
|
|
||||||
typedef void ( *CM_COLLISION_OBJ ) ( ClothModifierData *clmd, int step, CM_COLLISION_RESPONSE collision_response );
|
|
||||||
|
|
||||||
|
|
||||||
/* This enum provides the IDs for our solvers. */
|
/* This enum provides the IDs for our solvers. */
|
||||||
// only one available in the moment
|
// only one available in the moment
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -286,15 +277,6 @@ typedef struct
|
|||||||
}
|
}
|
||||||
CM_SOLVER_DEF;
|
CM_SOLVER_DEF;
|
||||||
|
|
||||||
/* used for caching in implicit.c */
|
|
||||||
typedef struct Frame
|
|
||||||
{
|
|
||||||
ClothVertex *verts;
|
|
||||||
ClothSpring *springs;
|
|
||||||
unsigned int numverts, numsprings;
|
|
||||||
float time; /* we need float since we want to support sub-frames */
|
|
||||||
}
|
|
||||||
Frame;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
*
|
*
|
||||||
* The Original Code is: all of this file.
|
* The Original Code is: all of this file.
|
||||||
*
|
*
|
||||||
* Contributor(s): none yet.
|
* Contributor(s): Daniel Genrich
|
||||||
*
|
*
|
||||||
* ***** END GPL LICENSE BLOCK *****
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
*/
|
*/
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
#define BKE_COLLISIONS_H
|
#define BKE_COLLISIONS_H
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "float.h"
|
#include <float.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -47,68 +47,27 @@
|
|||||||
#include "DNA_modifier_types.h"
|
#include "DNA_modifier_types.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
|
||||||
|
#include "BLI_kdopbvh.h"
|
||||||
|
|
||||||
struct Object;
|
struct Object;
|
||||||
struct Cloth;
|
struct Cloth;
|
||||||
struct MFace;
|
struct MFace;
|
||||||
struct DerivedMesh;
|
struct DerivedMesh;
|
||||||
struct ClothModifierData;
|
struct ClothModifierData;
|
||||||
struct CollisionTree;
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// used in kdop.c and collision.c
|
// used for collisions in collision.c
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
typedef struct CollisionTree
|
|
||||||
|
/* COLLISION FLAGS */
|
||||||
|
typedef enum
|
||||||
{
|
{
|
||||||
struct CollisionTree *nodes[4]; // 4 children --> quad-tree
|
COLLISION_IN_FUTURE = ( 1 << 1 ),
|
||||||
struct CollisionTree *parent;
|
} COLLISION_FLAGS;
|
||||||
struct CollisionTree *nextLeaf;
|
|
||||||
struct CollisionTree *prevLeaf;
|
|
||||||
float bv[26]; // Bounding volume of all nodes / we have 7 axes on a 14-DOP
|
|
||||||
unsigned int tri_index; // this saves the index of the face
|
|
||||||
// int point_index[4]; // supports up to 4 points in a leaf
|
|
||||||
int count_nodes; // how many nodes are used
|
|
||||||
int traversed; // how many nodes already traversed until this level?
|
|
||||||
int isleaf;
|
|
||||||
float alpha; /* for selfcollision */
|
|
||||||
float normal[3]; /* for selfcollision */
|
|
||||||
}
|
|
||||||
CollisionTree;
|
|
||||||
|
|
||||||
typedef struct BVH
|
|
||||||
{
|
|
||||||
unsigned int numfaces;
|
|
||||||
unsigned int numverts;
|
|
||||||
MVert *current_x; // e.g. txold in clothvertex
|
|
||||||
MVert *current_xold; // e.g. tx in clothvertex
|
|
||||||
MFace *mfaces; // just a pointer to the original datastructure
|
|
||||||
struct LinkNode *tree;
|
|
||||||
CollisionTree *root; // TODO: saving the root --> is this really needed? YES!
|
|
||||||
CollisionTree *leaf_tree; /* Tail of the leaf linked list. */
|
|
||||||
CollisionTree *leaf_root; /* Head of the leaf linked list. */
|
|
||||||
float epsilon; /* epslion is used for inflation of the k-dop */
|
|
||||||
int flags; /* bvhFlags */
|
|
||||||
}
|
|
||||||
BVH;
|
|
||||||
////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////
|
|
||||||
// kdop.c
|
|
||||||
////////////////////////////////////////
|
|
||||||
|
|
||||||
// needed for collision.c
|
|
||||||
typedef void ( *CM_COLLISION_RESPONSE ) ( ModifierData *md1, ModifierData *md2, CollisionTree *tree1, CollisionTree *tree2 );
|
|
||||||
|
|
||||||
// needed for collision.c
|
|
||||||
int bvh_traverse ( ModifierData * md1, ModifierData * md2, CollisionTree * tree1, CollisionTree * tree2, float step, CM_COLLISION_RESPONSE collision_response, int selfcollision);
|
|
||||||
|
|
||||||
////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// used for collisions in kdop.c and also collision.c
|
// used for collisions in collision.c
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
/* used for collisions in collision.c */
|
/* used for collisions in collision.c */
|
||||||
typedef struct CollPair
|
typedef struct CollPair
|
||||||
@@ -119,10 +78,10 @@ typedef struct CollPair
|
|||||||
float normal[3];
|
float normal[3];
|
||||||
float vector[3]; // unnormalized collision vector: p2-p1
|
float vector[3]; // unnormalized collision vector: p2-p1
|
||||||
float pa[3], pb[3]; // collision point p1 on face1, p2 on face2
|
float pa[3], pb[3]; // collision point p1 on face1, p2 on face2
|
||||||
int lastsign; // indicates if the distance sign has changed, unused itm
|
int flag;
|
||||||
float time; // collision time, from 0 up to 1
|
float time; // collision time, from 0 up to 1
|
||||||
unsigned int ap1, ap2, ap3, bp1, bp2, bp3;
|
int ap1, ap2, ap3, bp1, bp2, bp3;
|
||||||
unsigned int pointsb[4];
|
int pointsb[4];
|
||||||
}
|
}
|
||||||
CollPair;
|
CollPair;
|
||||||
|
|
||||||
@@ -157,23 +116,6 @@ FaceCollPair;
|
|||||||
// forward declarations
|
// forward declarations
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
|
|
||||||
// NOTICE: mvert-routines for building + update the BVH are the most native ones
|
|
||||||
|
|
||||||
// builds bounding volume hierarchy
|
|
||||||
void bvh_build (BVH *bvh);
|
|
||||||
BVH *bvh_build_from_mvert (MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon);
|
|
||||||
|
|
||||||
// frees the same
|
|
||||||
void bvh_free ( BVH * bvh );
|
|
||||||
|
|
||||||
// checks two bounding volume hierarchies for potential collisions and returns some list with those
|
|
||||||
|
|
||||||
|
|
||||||
// update bounding volumes, needs updated positions in bvh->current_xold (static)
|
|
||||||
// and also bvh->current_x if moving==1
|
|
||||||
void bvh_update_from_mvert(BVH * bvh, MVert *x, unsigned int numverts, MVert *xnew, int moving);
|
|
||||||
void bvh_update(BVH * bvh, int moving);
|
|
||||||
|
|
||||||
LinkNode *BLI_linklist_append_fast ( LinkNode **listp, void *ptr );
|
LinkNode *BLI_linklist_append_fast ( LinkNode **listp, void *ptr );
|
||||||
|
|
||||||
// move Collision modifier object inter-frame with step = [0,1]
|
// move Collision modifier object inter-frame with step = [0,1]
|
||||||
|
|||||||
@@ -45,6 +45,8 @@
|
|||||||
|
|
||||||
#include "BKE_pointcache.h"
|
#include "BKE_pointcache.h"
|
||||||
|
|
||||||
|
#include "BLI_kdopbvh.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
void tstart ( void )
|
void tstart ( void )
|
||||||
{}
|
{}
|
||||||
@@ -151,13 +153,14 @@ void cloth_init ( ClothModifierData *clmd )
|
|||||||
clmd->sim_parms->goalfrict = 0.0f;
|
clmd->sim_parms->goalfrict = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon)
|
||||||
BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon)
|
|
||||||
{
|
{
|
||||||
unsigned int i = 0;
|
int i;
|
||||||
BVH *bvh=NULL;
|
BVHTree *bvhtree;
|
||||||
Cloth *cloth = clmd->clothObject;
|
Cloth *cloth = clmd->clothObject;
|
||||||
ClothVertex *verts = NULL;
|
ClothVertex *verts;
|
||||||
|
MFace *mfaces;
|
||||||
|
float co[12];
|
||||||
|
|
||||||
if(!clmd)
|
if(!clmd)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -168,69 +171,171 @@ BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
verts = cloth->verts;
|
verts = cloth->verts;
|
||||||
|
mfaces = cloth->mfaces;
|
||||||
|
|
||||||
|
// in the moment, return zero if no faces there
|
||||||
|
if(!cloth->numverts)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// create quadtree with k=26
|
||||||
|
bvhtree = BLI_bvhtree_new(cloth->numverts, epsilon, 4, 6);
|
||||||
|
|
||||||
|
// fill tree
|
||||||
|
for(i = 0; i < cloth->numverts; i++, verts++)
|
||||||
|
{
|
||||||
|
VECCOPY(&co[0*3], verts->xold);
|
||||||
|
|
||||||
|
BLI_bvhtree_insert(bvhtree, i, co, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// balance tree
|
||||||
|
BLI_bvhtree_balance(bvhtree);
|
||||||
|
|
||||||
|
return bvhtree;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
BVHTree *bvhtree;
|
||||||
|
Cloth *cloth = clmd->clothObject;
|
||||||
|
ClothVertex *verts;
|
||||||
|
MFace *mfaces;
|
||||||
|
float co[12];
|
||||||
|
|
||||||
|
if(!clmd)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cloth = clmd->clothObject;
|
||||||
|
|
||||||
|
if(!cloth)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
verts = cloth->verts;
|
||||||
|
mfaces = cloth->mfaces;
|
||||||
|
|
||||||
// in the moment, return zero if no faces there
|
// in the moment, return zero if no faces there
|
||||||
if(!cloth->numfaces)
|
if(!cloth->numfaces)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
bvh = MEM_callocN(sizeof(BVH), "BVH");
|
// create quadtree with k=26
|
||||||
if (bvh == NULL)
|
bvhtree = BLI_bvhtree_new(cloth->numfaces, epsilon, 4, 26);
|
||||||
|
|
||||||
|
// fill tree
|
||||||
|
for(i = 0; i < cloth->numfaces; i++, mfaces++)
|
||||||
{
|
{
|
||||||
printf("bvh: Out of memory.\n");
|
VECCOPY(&co[0*3], verts[mfaces->v1].xold);
|
||||||
return NULL;
|
VECCOPY(&co[1*3], verts[mfaces->v2].xold);
|
||||||
|
VECCOPY(&co[2*3], verts[mfaces->v3].xold);
|
||||||
|
|
||||||
|
if(mfaces->v4)
|
||||||
|
VECCOPY(&co[3*3], verts[mfaces->v4].xold);
|
||||||
|
|
||||||
|
BLI_bvhtree_insert(bvhtree, i, co, (mfaces->v4 ? 4 : 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// springs = cloth->springs;
|
// balance tree
|
||||||
// numsprings = cloth->numsprings;
|
BLI_bvhtree_balance(bvhtree);
|
||||||
|
|
||||||
bvh->epsilon = epsilon;
|
return bvhtree;
|
||||||
bvh->numfaces = cloth->numfaces;
|
|
||||||
bvh->mfaces = cloth->mfaces;
|
|
||||||
|
|
||||||
bvh->numverts = cloth->numverts;
|
|
||||||
|
|
||||||
bvh->current_x = MEM_callocN ( sizeof ( MVert ) * bvh->numverts, "bvh->current_x" );
|
|
||||||
|
|
||||||
if (bvh->current_x == NULL)
|
|
||||||
{
|
|
||||||
printf("bvh: Out of memory.\n");
|
|
||||||
MEM_freeN(bvh);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < bvh->numverts; i++)
|
void bvhtree_update_from_cloth(ClothModifierData *clmd, int moving)
|
||||||
{
|
|
||||||
VECCOPY(bvh->current_x[i].co, verts[i].tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bvh_build (bvh);
|
|
||||||
|
|
||||||
return bvh;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bvh_update_from_cloth(ClothModifierData *clmd, int moving)
|
|
||||||
{
|
{
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
Cloth *cloth = clmd->clothObject;
|
Cloth *cloth = clmd->clothObject;
|
||||||
BVH *bvh = cloth->tree;
|
BVHTree *bvhtree = cloth->bvhtree;
|
||||||
ClothVertex *verts = cloth->verts;
|
ClothVertex *verts = cloth->verts;
|
||||||
|
MFace *mfaces;
|
||||||
|
float co[12], co_moving[12];
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if(!bvh)
|
if(!bvhtree)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(cloth->numverts!=bvh->numverts)
|
mfaces = cloth->mfaces;
|
||||||
return;
|
|
||||||
|
|
||||||
if(cloth->verts)
|
// update vertex position in bvh tree
|
||||||
|
if(verts && mfaces)
|
||||||
{
|
{
|
||||||
for(i = 0; i < bvh->numverts; i++)
|
for(i = 0; i < cloth->numfaces; i++, mfaces++)
|
||||||
{
|
{
|
||||||
VECCOPY(bvh->current_x[i].co, verts[i].tx);
|
VECCOPY(&co[0*3], verts[mfaces->v1].txold);
|
||||||
VECCOPY(bvh->current_xold[i].co, verts[i].txold);
|
VECCOPY(&co[1*3], verts[mfaces->v2].txold);
|
||||||
|
VECCOPY(&co[2*3], verts[mfaces->v3].txold);
|
||||||
|
|
||||||
|
if(mfaces->v4)
|
||||||
|
VECCOPY(&co[3*3], verts[mfaces->v4].txold);
|
||||||
|
|
||||||
|
// copy new locations into array
|
||||||
|
if(moving)
|
||||||
|
{
|
||||||
|
// update moving positions
|
||||||
|
VECCOPY(&co_moving[0*3], verts[mfaces->v1].tx);
|
||||||
|
VECCOPY(&co_moving[1*3], verts[mfaces->v2].tx);
|
||||||
|
VECCOPY(&co_moving[2*3], verts[mfaces->v3].tx);
|
||||||
|
|
||||||
|
if(mfaces->v4)
|
||||||
|
VECCOPY(&co_moving[3*3], verts[mfaces->v4].tx);
|
||||||
|
|
||||||
|
ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, (mfaces->v4 ? 4 : 3));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, (mfaces->v4 ? 4 : 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if tree is already full
|
||||||
|
if(!ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_bvhtree_update_tree(bvhtree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bvh_update(bvh, moving);
|
void bvhselftree_update_from_cloth(ClothModifierData *clmd, int moving)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
Cloth *cloth = clmd->clothObject;
|
||||||
|
BVHTree *bvhtree = cloth->bvhselftree;
|
||||||
|
ClothVertex *verts = cloth->verts;
|
||||||
|
MFace *mfaces;
|
||||||
|
float co[12], co_moving[12];
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if(!bvhtree)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mfaces = cloth->mfaces;
|
||||||
|
|
||||||
|
// update vertex position in bvh tree
|
||||||
|
if(verts && mfaces)
|
||||||
|
{
|
||||||
|
for(i = 0; i < cloth->numverts; i++, verts++)
|
||||||
|
{
|
||||||
|
VECCOPY(&co[0*3], verts->txold);
|
||||||
|
|
||||||
|
// copy new locations into array
|
||||||
|
if(moving)
|
||||||
|
{
|
||||||
|
// update moving positions
|
||||||
|
VECCOPY(&co_moving[0*3], verts->tx);
|
||||||
|
|
||||||
|
ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if tree is already full
|
||||||
|
if(!ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_bvhtree_update_tree(bvhtree);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int modifiers_indexInObject(Object *ob, ModifierData *md_seek);
|
int modifiers_indexInObject(Object *ob, ModifierData *md_seek);
|
||||||
@@ -541,8 +646,11 @@ void cloth_free_modifier ( Object *ob, ClothModifierData *clmd )
|
|||||||
cloth->numsprings = 0;
|
cloth->numsprings = 0;
|
||||||
|
|
||||||
// free BVH collision tree
|
// free BVH collision tree
|
||||||
if ( cloth->tree )
|
if ( cloth->bvhtree )
|
||||||
bvh_free ( ( BVH * ) cloth->tree );
|
BLI_bvhtree_free ( cloth->bvhtree );
|
||||||
|
|
||||||
|
if ( cloth->bvhselftree )
|
||||||
|
BLI_bvhtree_free ( cloth->bvhselftree );
|
||||||
|
|
||||||
// we save our faces for collision objects
|
// we save our faces for collision objects
|
||||||
if ( cloth->mfaces )
|
if ( cloth->mfaces )
|
||||||
@@ -611,8 +719,11 @@ void cloth_free_modifier_extern ( ClothModifierData *clmd )
|
|||||||
cloth->numsprings = 0;
|
cloth->numsprings = 0;
|
||||||
|
|
||||||
// free BVH collision tree
|
// free BVH collision tree
|
||||||
if ( cloth->tree )
|
if ( cloth->bvhtree )
|
||||||
bvh_free ( ( BVH * ) cloth->tree );
|
BLI_bvhtree_free ( cloth->bvhtree );
|
||||||
|
|
||||||
|
if ( cloth->bvhselftree )
|
||||||
|
BLI_bvhtree_free ( cloth->bvhselftree );
|
||||||
|
|
||||||
// we save our faces for collision objects
|
// we save our faces for collision objects
|
||||||
if ( cloth->mfaces )
|
if ( cloth->mfaces )
|
||||||
@@ -751,6 +862,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
|
|||||||
ClothVertex *verts = NULL;
|
ClothVertex *verts = NULL;
|
||||||
float tnull[3] = {0,0,0};
|
float tnull[3] = {0,0,0};
|
||||||
Cloth *cloth = NULL;
|
Cloth *cloth = NULL;
|
||||||
|
float maxdist = 0;
|
||||||
|
|
||||||
// If we have a clothObject, free it.
|
// If we have a clothObject, free it.
|
||||||
if ( clmd->clothObject != NULL )
|
if ( clmd->clothObject != NULL )
|
||||||
@@ -810,6 +922,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
|
|||||||
VECCOPY ( verts->xold, verts->x );
|
VECCOPY ( verts->xold, verts->x );
|
||||||
VECCOPY ( verts->xconst, verts->x );
|
VECCOPY ( verts->xconst, verts->x );
|
||||||
VECCOPY ( verts->txold, verts->x );
|
VECCOPY ( verts->txold, verts->x );
|
||||||
|
VECCOPY ( verts->tx, verts->x );
|
||||||
VecMulf ( verts->v, 0.0f );
|
VecMulf ( verts->v, 0.0f );
|
||||||
|
|
||||||
verts->impulse_count = 0;
|
verts->impulse_count = 0;
|
||||||
@@ -820,7 +933,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
|
|||||||
// has to be happen before springs are build!
|
// has to be happen before springs are build!
|
||||||
cloth_apply_vgroup (clmd, dm);
|
cloth_apply_vgroup (clmd, dm);
|
||||||
|
|
||||||
|
|
||||||
if ( !cloth_build_springs ( clmd, dm ) )
|
if ( !cloth_build_springs ( clmd, dm ) )
|
||||||
{
|
{
|
||||||
cloth_free_modifier ( ob, clmd );
|
cloth_free_modifier ( ob, clmd );
|
||||||
@@ -845,12 +957,18 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
|
|||||||
if(!first)
|
if(!first)
|
||||||
implicit_set_positions(clmd);
|
implicit_set_positions(clmd);
|
||||||
|
|
||||||
clmd->clothObject->tree = bvh_build_from_cloth ( clmd, clmd->coll_parms->epsilon );
|
clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, clmd->coll_parms->epsilon );
|
||||||
|
|
||||||
|
for(i = 0; i < dm->getNumVerts(dm); i++)
|
||||||
|
{
|
||||||
|
maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
|
static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
|
||||||
{
|
{
|
||||||
unsigned int numverts = dm->getNumVerts ( dm );
|
unsigned int numverts = dm->getNumVerts ( dm );
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,860 +0,0 @@
|
|||||||
/* kdop.c
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*
|
|
||||||
* The Original Code is Copyright (C) Blender Foundation
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* The Original Code is: all of this file.
|
|
||||||
*
|
|
||||||
* Contributor(s): none yet.
|
|
||||||
*
|
|
||||||
* ***** END GPL LICENSE BLOCK *****
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
|
||||||
|
|
||||||
#include "BKE_cloth.h"
|
|
||||||
|
|
||||||
#include "DNA_cloth_types.h"
|
|
||||||
#include "DNA_mesh_types.h"
|
|
||||||
#include "DNA_scene_types.h"
|
|
||||||
|
|
||||||
#include "BKE_deform.h"
|
|
||||||
#include "BKE_DerivedMesh.h"
|
|
||||||
#include "BKE_cdderivedmesh.h"
|
|
||||||
#include "BKE_effect.h"
|
|
||||||
#include "BKE_global.h"
|
|
||||||
#include "BKE_object.h"
|
|
||||||
#include "BKE_modifier.h"
|
|
||||||
#include "BKE_utildefines.h"
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#include <omp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
// Additional fastened appending function
|
|
||||||
// It uses the link to the last inserted node as start value
|
|
||||||
// for searching the end of the list
|
|
||||||
// NEW: in compare to the original function, this one returns
|
|
||||||
// the reference to the last inserted node
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
LinkNode *BLI_linklist_append_fast(LinkNode **listp, void *ptr) {
|
|
||||||
LinkNode *nlink= MEM_mallocN(sizeof(*nlink), "nlink");
|
|
||||||
LinkNode *node = *listp;
|
|
||||||
|
|
||||||
nlink->link = ptr;
|
|
||||||
nlink->next = NULL;
|
|
||||||
|
|
||||||
if(node == NULL){
|
|
||||||
*listp = nlink;
|
|
||||||
} else {
|
|
||||||
while(node->next != NULL){
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
node->next = nlink;
|
|
||||||
}
|
|
||||||
return nlink;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
// Bounding Volume Hierarchy Definition
|
|
||||||
//
|
|
||||||
// Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below
|
|
||||||
// Notes: You have to choose the type at compile time ITM
|
|
||||||
// Notes: You can choose the tree type --> binary, quad, octree, choose below
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static float KDOP_AXES[13][3] =
|
|
||||||
{ {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0},
|
|
||||||
{1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0},
|
|
||||||
{0, 1.0, -1.0}
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////// choose bounding volume here! /////////////
|
|
||||||
|
|
||||||
#define KDOP_26
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef KDOP_26
|
|
||||||
#define KDOP_END 13
|
|
||||||
#define KDOP_START 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef KDOP_18
|
|
||||||
#define KDOP_END 13
|
|
||||||
#define KDOP_START 7
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef KDOP_14
|
|
||||||
#define KDOP_END 7
|
|
||||||
#define KDOP_START 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// this is basicly some AABB
|
|
||||||
#ifdef KDOP_8
|
|
||||||
#define KDOP_END 4
|
|
||||||
#define KDOP_START 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// this is basicly some OBB
|
|
||||||
#ifdef KDOP_6
|
|
||||||
#define KDOP_END 3
|
|
||||||
#define KDOP_START 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Introsort
|
|
||||||
// with permission deriven from the following Java code:
|
|
||||||
// http://ralphunden.net/content/tutorials/a-guide-to-introsort/
|
|
||||||
// and he derived it from the SUN STL
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
static int size_threshold = 16;
|
|
||||||
/*
|
|
||||||
* Common methods for all algorithms
|
|
||||||
*/
|
|
||||||
DO_INLINE void bvh_exchange(CollisionTree **a, int i, int j)
|
|
||||||
{
|
|
||||||
CollisionTree *t=a[i];
|
|
||||||
a[i]=a[j];
|
|
||||||
a[j]=t;
|
|
||||||
}
|
|
||||||
DO_INLINE int floor_lg(int a)
|
|
||||||
{
|
|
||||||
return (int)(floor(log(a)/log(2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insertion sort algorithm
|
|
||||||
*/
|
|
||||||
void bvh_insertionsort(CollisionTree **a, int lo, int hi, int axis)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
CollisionTree *t;
|
|
||||||
for (i=lo; i < hi; i++)
|
|
||||||
{
|
|
||||||
j=i;
|
|
||||||
t = a[i];
|
|
||||||
while((j!=lo) && (t->bv[axis] < (a[j-1])->bv[axis]))
|
|
||||||
{
|
|
||||||
a[j] = a[j-1];
|
|
||||||
j--;
|
|
||||||
}
|
|
||||||
a[j] = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bvh_partition(CollisionTree **a, int lo, int hi, CollisionTree * x, int axis)
|
|
||||||
{
|
|
||||||
int i=lo, j=hi;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
while ((a[i])->bv[axis] < x->bv[axis]) i++;
|
|
||||||
j=j-1;
|
|
||||||
while (x->bv[axis] < (a[j])->bv[axis]) j=j-1;
|
|
||||||
if(!(i < j))
|
|
||||||
return i;
|
|
||||||
bvh_exchange(a, i,j);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Heapsort algorithm
|
|
||||||
*/
|
|
||||||
static void bvh_downheap(CollisionTree **a, int i, int n, int lo, int axis)
|
|
||||||
{
|
|
||||||
CollisionTree * d = a[lo+i-1];
|
|
||||||
int child;
|
|
||||||
while (i<=n/2)
|
|
||||||
{
|
|
||||||
child = 2*i;
|
|
||||||
if ((child < n) && ((a[lo+child-1])->bv[axis] < (a[lo+child])->bv[axis]))
|
|
||||||
{
|
|
||||||
child++;
|
|
||||||
}
|
|
||||||
if (!(d->bv[axis] < (a[lo+child-1])->bv[axis])) break;
|
|
||||||
a[lo+i-1] = a[lo+child-1];
|
|
||||||
i = child;
|
|
||||||
}
|
|
||||||
a[lo+i-1] = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bvh_heapsort(CollisionTree **a, int lo, int hi, int axis)
|
|
||||||
{
|
|
||||||
int n = hi-lo, i;
|
|
||||||
for (i=n/2; i>=1; i=i-1)
|
|
||||||
{
|
|
||||||
bvh_downheap(a, i,n,lo, axis);
|
|
||||||
}
|
|
||||||
for (i=n; i>1; i=i-1)
|
|
||||||
{
|
|
||||||
bvh_exchange(a, lo,lo+i-1);
|
|
||||||
bvh_downheap(a, 1,i-1,lo, axis);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CollisionTree *bvh_medianof3(CollisionTree **a, int lo, int mid, int hi, int axis) // returns Sortable
|
|
||||||
{
|
|
||||||
if ((a[mid])->bv[axis] < (a[lo])->bv[axis])
|
|
||||||
{
|
|
||||||
if ((a[hi])->bv[axis] < (a[mid])->bv[axis])
|
|
||||||
return a[mid];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((a[hi])->bv[axis] < (a[lo])->bv[axis])
|
|
||||||
return a[hi];
|
|
||||||
else
|
|
||||||
return a[lo];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((a[hi])->bv[axis] < (a[mid])->bv[axis])
|
|
||||||
{
|
|
||||||
if ((a[hi])->bv[axis] < (a[lo])->bv[axis])
|
|
||||||
return a[lo];
|
|
||||||
else
|
|
||||||
return a[hi];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return a[mid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Quicksort algorithm modified for Introsort
|
|
||||||
*/
|
|
||||||
void bvh_introsort_loop (CollisionTree **a, int lo, int hi, int depth_limit, int axis)
|
|
||||||
{
|
|
||||||
int p;
|
|
||||||
|
|
||||||
while (hi-lo > size_threshold)
|
|
||||||
{
|
|
||||||
if (depth_limit == 0)
|
|
||||||
{
|
|
||||||
bvh_heapsort(a, lo, hi, axis);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
depth_limit=depth_limit-1;
|
|
||||||
p=bvh_partition(a, lo, hi, bvh_medianof3(a, lo, lo+((hi-lo)/2)+1, hi-1, axis), axis);
|
|
||||||
bvh_introsort_loop(a, p, hi, depth_limit, axis);
|
|
||||||
hi=p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DO_INLINE void bvh_sort(CollisionTree **a0, int begin, int end, int axis)
|
|
||||||
{
|
|
||||||
if (begin < end)
|
|
||||||
{
|
|
||||||
CollisionTree **a=a0;
|
|
||||||
bvh_introsort_loop(a, begin, end, 2*floor_lg(end-begin), axis);
|
|
||||||
bvh_insertionsort(a, begin, end, axis);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DO_INLINE void bvh_sort_along_axis(CollisionTree **face_list, int start, int end, int axis)
|
|
||||||
{
|
|
||||||
bvh_sort(face_list, start, end, axis);
|
|
||||||
}
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void bvh_free(BVH * bvh)
|
|
||||||
{
|
|
||||||
LinkNode *search = NULL;
|
|
||||||
CollisionTree *tree = NULL;
|
|
||||||
|
|
||||||
if (bvh)
|
|
||||||
{
|
|
||||||
|
|
||||||
search = bvh->tree;
|
|
||||||
|
|
||||||
while(search)
|
|
||||||
{
|
|
||||||
LinkNode *next= search->next;
|
|
||||||
tree = search->link;
|
|
||||||
|
|
||||||
MEM_freeN(tree);
|
|
||||||
|
|
||||||
search = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
BLI_linklist_free(bvh->tree,NULL);
|
|
||||||
bvh->tree = NULL;
|
|
||||||
|
|
||||||
if(bvh->current_x)
|
|
||||||
MEM_freeN(bvh->current_x);
|
|
||||||
if(bvh->current_xold)
|
|
||||||
MEM_freeN(bvh->current_xold);
|
|
||||||
|
|
||||||
MEM_freeN(bvh);
|
|
||||||
bvh = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only supports x,y,z axis in the moment
|
|
||||||
// but we should use a plain and simple function here for speed sake
|
|
||||||
DO_INLINE int bvh_largest_axis(float *bv)
|
|
||||||
{
|
|
||||||
float middle_point[3];
|
|
||||||
|
|
||||||
middle_point[0] = (bv[1]) - (bv[0]); // x axis
|
|
||||||
middle_point[1] = (bv[3]) - (bv[2]); // y axis
|
|
||||||
middle_point[2] = (bv[5]) - (bv[4]); // z axis
|
|
||||||
if (middle_point[0] > middle_point[1])
|
|
||||||
{
|
|
||||||
if (middle_point[0] > middle_point[2])
|
|
||||||
return 1; // max x axis
|
|
||||||
else
|
|
||||||
return 5; // max z axis
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (middle_point[1] > middle_point[2])
|
|
||||||
return 3; // max y axis
|
|
||||||
else
|
|
||||||
return 5; // max z axis
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// depends on the fact that the BVH's for each face is already build
|
|
||||||
DO_INLINE void bvh_calc_DOP_hull_from_faces(BVH * bvh, CollisionTree **tri, int numfaces, float *bv)
|
|
||||||
{
|
|
||||||
float newmin,newmax;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
if(numfaces >0)
|
|
||||||
{
|
|
||||||
// for all Axes.
|
|
||||||
for (i = KDOP_START; i < KDOP_END; i++)
|
|
||||||
{
|
|
||||||
bv[(2 * i)] = (tri [0])->bv[(2 * i)];
|
|
||||||
bv[(2 * i) + 1] = (tri [0])->bv[(2 * i) + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < numfaces; j++)
|
|
||||||
{
|
|
||||||
// for all Axes.
|
|
||||||
for (i = KDOP_START; i < KDOP_END; i++)
|
|
||||||
{
|
|
||||||
newmin = (tri [j])->bv[(2 * i)];
|
|
||||||
if ((newmin < bv[(2 * i)]))
|
|
||||||
{
|
|
||||||
bv[(2 * i)] = newmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
newmax = (tri [j])->bv[(2 * i) + 1];
|
|
||||||
if ((newmax > bv[(2 * i) + 1]))
|
|
||||||
{
|
|
||||||
bv[(2 * i) + 1] = newmax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DO_INLINE void bvh_calc_DOP_hull_static(BVH * bvh, CollisionTree **tri, int numfaces, float *bv, CollisionTree *tree)
|
|
||||||
{
|
|
||||||
MFace *tempMFace = bvh->mfaces;
|
|
||||||
float *tempBV = bv;
|
|
||||||
float newminmax;
|
|
||||||
int i, j, k;
|
|
||||||
|
|
||||||
for (j = 0; j < numfaces; j++)
|
|
||||||
{
|
|
||||||
tempMFace = bvh->mfaces + (tri [j])->tri_index;
|
|
||||||
// 3 or 4 vertices per face.
|
|
||||||
for (k = 0; k < 4; k++)
|
|
||||||
{
|
|
||||||
int temp = 0;
|
|
||||||
// If this is a triangle.
|
|
||||||
if (k == 3 && !tempMFace->v4)
|
|
||||||
continue;
|
|
||||||
// TODO: other name for "temp" this gets all vertices of a face
|
|
||||||
if (k == 0)
|
|
||||||
temp = tempMFace->v1;
|
|
||||||
else if (k == 1)
|
|
||||||
temp = tempMFace->v2;
|
|
||||||
else if (k == 2)
|
|
||||||
temp = tempMFace->v3;
|
|
||||||
else if (k == 3)
|
|
||||||
temp = tempMFace->v4;
|
|
||||||
// for all Axes.
|
|
||||||
for (i = KDOP_START; i < KDOP_END; i++)
|
|
||||||
{
|
|
||||||
newminmax = INPR(bvh->current_xold[temp].co, KDOP_AXES[i]);
|
|
||||||
if ((newminmax < tempBV[(2 * i)]) || (k == 0 && j == 0))
|
|
||||||
tempBV[(2 * i)] = newminmax;
|
|
||||||
if ((newminmax > tempBV[(2 * i) + 1])|| (k == 0 && j == 0))
|
|
||||||
tempBV[(2 * i) + 1] = newminmax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate normal of this face */
|
|
||||||
/* (code copied from cdderivedmesh.c) */
|
|
||||||
/*
|
|
||||||
if(tempMFace->v4)
|
|
||||||
CalcNormFloat4(bvh->current_xold[tempMFace->v1].co, bvh->current_xold[tempMFace->v2].co,
|
|
||||||
bvh->current_xold[tempMFace->v3].co, bvh->current_xold[tempMFace->v4].co, tree->normal);
|
|
||||||
else
|
|
||||||
CalcNormFloat(bvh->current_xold[tempMFace->v1].co, bvh->current_xold[tempMFace->v2].co,
|
|
||||||
bvh->current_xold[tempMFace->v3].co, tree->normal);
|
|
||||||
|
|
||||||
tree->alpha = 0;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DO_INLINE void bvh_calc_DOP_hull_moving(BVH * bvh, CollisionTree **tri, int numfaces, float *bv, CollisionTree *tree)
|
|
||||||
{
|
|
||||||
MFace *tempMFace = bvh->mfaces;
|
|
||||||
float *tempBV = bv;
|
|
||||||
float newminmax;
|
|
||||||
int i, j, k;
|
|
||||||
|
|
||||||
/* TODO: calculate normals */
|
|
||||||
|
|
||||||
for (j = 0; j < numfaces; j++)
|
|
||||||
{
|
|
||||||
tempMFace = bvh->mfaces + (tri [j])->tri_index;
|
|
||||||
// 3 or 4 vertices per face.
|
|
||||||
for (k = 0; k < 4; k++)
|
|
||||||
{
|
|
||||||
int temp = 0;
|
|
||||||
// If this is a triangle.
|
|
||||||
if (k == 3 && !tempMFace->v4)
|
|
||||||
continue;
|
|
||||||
// TODO: other name for "temp" this gets all vertices of a face
|
|
||||||
if (k == 0)
|
|
||||||
temp = tempMFace->v1;
|
|
||||||
else if (k == 1)
|
|
||||||
temp = tempMFace->v2;
|
|
||||||
else if (k == 2)
|
|
||||||
temp = tempMFace->v3;
|
|
||||||
else if (k == 3)
|
|
||||||
temp = tempMFace->v4;
|
|
||||||
// for all Axes.
|
|
||||||
for (i = KDOP_START; i < KDOP_END; i++)
|
|
||||||
{
|
|
||||||
newminmax = INPR(bvh->current_xold[temp].co, KDOP_AXES[i]);
|
|
||||||
if ((newminmax < tempBV[(2 * i)]) || (k == 0 && j == 0))
|
|
||||||
tempBV[(2 * i)] = newminmax;
|
|
||||||
if ((newminmax > tempBV[(2 * i) + 1])|| (k == 0 && j == 0))
|
|
||||||
tempBV[(2 * i) + 1] = newminmax;
|
|
||||||
|
|
||||||
newminmax = INPR(bvh->current_x[temp].co, KDOP_AXES[i]);
|
|
||||||
if ((newminmax < tempBV[(2 * i)]) || (k == 0 && j == 0))
|
|
||||||
tempBV[(2 * i)] = newminmax;
|
|
||||||
if ((newminmax > tempBV[(2 * i) + 1])|| (k == 0 && j == 0))
|
|
||||||
tempBV[(2 * i) + 1] = newminmax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bvh_div_env_node(BVH *bvh, CollisionTree *tree, CollisionTree **face_list, unsigned int start, unsigned int end, int lastaxis, LinkNode *nlink)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
CollisionTree *newtree = NULL;
|
|
||||||
int laxis = 0, max_nodes=4;
|
|
||||||
unsigned int tstart, tend;
|
|
||||||
LinkNode *nlink1 = nlink;
|
|
||||||
LinkNode *tnlink;
|
|
||||||
tree->traversed = 0;
|
|
||||||
// Determine which axis to split along
|
|
||||||
laxis = bvh_largest_axis(tree->bv);
|
|
||||||
|
|
||||||
// Sort along longest axis
|
|
||||||
if(laxis!=lastaxis)
|
|
||||||
bvh_sort_along_axis(face_list, start, end, laxis);
|
|
||||||
|
|
||||||
// maximum is 4 since we have a quad tree
|
|
||||||
max_nodes = MIN2((end-start + 1 ),4);
|
|
||||||
|
|
||||||
for (i = 0; i < max_nodes; i++)
|
|
||||||
{
|
|
||||||
tree->count_nodes++;
|
|
||||||
|
|
||||||
if(end-start+1 > 4)
|
|
||||||
{
|
|
||||||
int quarter = ((float)((float)(end - start + 1) / 4.0f));
|
|
||||||
tstart = start + i * quarter;
|
|
||||||
tend = tstart + quarter - 1;
|
|
||||||
|
|
||||||
// be sure that we get all faces
|
|
||||||
if(i==3)
|
|
||||||
{
|
|
||||||
tend = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tend = tstart = start + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build tree until 4 node left.
|
|
||||||
if ((tend-tstart + 1 ) > 1)
|
|
||||||
{
|
|
||||||
newtree = (CollisionTree *)MEM_callocN(sizeof(CollisionTree), "CollisionTree");
|
|
||||||
tnlink = BLI_linklist_append_fast(&nlink1->next, newtree);
|
|
||||||
|
|
||||||
newtree->nodes[0] = newtree->nodes[1] = newtree->nodes[2] = newtree->nodes[3] = NULL;
|
|
||||||
newtree->count_nodes = 0;
|
|
||||||
newtree->parent = tree;
|
|
||||||
newtree->isleaf = 0;
|
|
||||||
|
|
||||||
tree->nodes[i] = newtree;
|
|
||||||
|
|
||||||
nlink1 = tnlink;
|
|
||||||
|
|
||||||
bvh_calc_DOP_hull_from_faces(bvh, &face_list[tstart], tend-tstart + 1, tree->nodes[i]->bv);
|
|
||||||
|
|
||||||
bvh_div_env_node(bvh, tree->nodes[i], face_list, tstart, tend, laxis, nlink1);
|
|
||||||
}
|
|
||||||
else // ok, we have 1 left for this node
|
|
||||||
{
|
|
||||||
CollisionTree *tnode = face_list[tstart];
|
|
||||||
tree->nodes[i] = tnode;
|
|
||||||
tree->nodes[i]->parent = tree;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* function cannot be directly called - needs alloced bvh */
|
|
||||||
void bvh_build (BVH *bvh)
|
|
||||||
{
|
|
||||||
unsigned int i = 0, j = 0, k = 0;
|
|
||||||
CollisionTree **face_list=NULL;
|
|
||||||
CollisionTree *tree=NULL;
|
|
||||||
LinkNode *nlink = NULL;
|
|
||||||
|
|
||||||
bvh->flags = 0;
|
|
||||||
bvh->leaf_tree = NULL;
|
|
||||||
bvh->leaf_root = NULL;
|
|
||||||
bvh->tree = NULL;
|
|
||||||
|
|
||||||
if(!bvh->current_x)
|
|
||||||
{
|
|
||||||
bvh_free(bvh);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bvh->current_xold = MEM_dupallocN(bvh->current_x);
|
|
||||||
|
|
||||||
tree = (CollisionTree *)MEM_callocN(sizeof(CollisionTree), "CollisionTree");
|
|
||||||
|
|
||||||
if (tree == NULL)
|
|
||||||
{
|
|
||||||
printf("bvh_build: Out of memory for nodes.\n");
|
|
||||||
bvh_free(bvh);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BLI_linklist_append(&bvh->tree, tree);
|
|
||||||
|
|
||||||
nlink = bvh->tree;
|
|
||||||
|
|
||||||
bvh->root = bvh->tree->link;
|
|
||||||
bvh->root->isleaf = 0;
|
|
||||||
bvh->root->parent = NULL;
|
|
||||||
bvh->root->nodes[0] = bvh->root->nodes[1] = bvh->root->nodes[1] = bvh->root->nodes[3] = NULL;
|
|
||||||
|
|
||||||
if(bvh->numfaces<=1)
|
|
||||||
{
|
|
||||||
bvh->root->tri_index = 0; // Why that? --> only one face there
|
|
||||||
bvh->root->isleaf = 1;
|
|
||||||
bvh->root->traversed = 0;
|
|
||||||
bvh->root->count_nodes = 0;
|
|
||||||
bvh->leaf_root = bvh->root;
|
|
||||||
bvh->leaf_tree = bvh->root;
|
|
||||||
bvh->root->nextLeaf = NULL;
|
|
||||||
bvh->root->prevLeaf = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// create face boxes
|
|
||||||
face_list = MEM_callocN (bvh->numfaces * sizeof (CollisionTree *), "CollisionTree");
|
|
||||||
if (face_list == NULL)
|
|
||||||
{
|
|
||||||
printf("bvh_build: Out of memory for face_list.\n");
|
|
||||||
bvh_free(bvh);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create face boxes
|
|
||||||
for(i = 0, k = 0; i < bvh->numfaces; i++)
|
|
||||||
{
|
|
||||||
LinkNode *tnlink;
|
|
||||||
|
|
||||||
tree = (CollisionTree *)MEM_callocN(sizeof(CollisionTree), "CollisionTree");
|
|
||||||
// TODO: check succesfull alloc
|
|
||||||
|
|
||||||
tnlink = BLI_linklist_append_fast(&nlink->next, tree);
|
|
||||||
|
|
||||||
face_list[i] = tree;
|
|
||||||
tree->tri_index = i;
|
|
||||||
tree->isleaf = 1;
|
|
||||||
tree->nextLeaf = NULL;
|
|
||||||
tree->prevLeaf = bvh->leaf_tree;
|
|
||||||
tree->parent = NULL;
|
|
||||||
tree->count_nodes = 0;
|
|
||||||
|
|
||||||
if(i==0)
|
|
||||||
{
|
|
||||||
bvh->leaf_tree = bvh->leaf_root = tree;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bvh->leaf_tree->nextLeaf = tree;
|
|
||||||
bvh->leaf_tree = bvh->leaf_tree->nextLeaf;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree->nodes[0] = tree->nodes[1] = tree->nodes[2] = tree->nodes[3] = NULL;
|
|
||||||
|
|
||||||
bvh_calc_DOP_hull_static(bvh, &face_list[i], 1, tree->bv, tree);
|
|
||||||
|
|
||||||
// inflate the bv with some epsilon
|
|
||||||
for (j = KDOP_START; j < KDOP_END; j++)
|
|
||||||
{
|
|
||||||
tree->bv[(2 * j)] -= bvh->epsilon; // minimum
|
|
||||||
tree->bv[(2 * j) + 1] += bvh->epsilon; // maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
nlink = tnlink;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build root bvh
|
|
||||||
bvh_calc_DOP_hull_from_faces(bvh, face_list, bvh->numfaces, bvh->root->bv);
|
|
||||||
|
|
||||||
// This is the traversal function.
|
|
||||||
bvh_div_env_node(bvh, bvh->root, face_list, 0, bvh->numfaces-1, 0, nlink);
|
|
||||||
if (face_list)
|
|
||||||
MEM_freeN(face_list);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// bvh_overlap - is it possbile for 2 bv's to collide ?
|
|
||||||
DO_INLINE int bvh_overlap(float *bv1, float *bv2)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
for (i = KDOP_START; i < KDOP_END; i++)
|
|
||||||
{
|
|
||||||
// Minimum test.
|
|
||||||
if (bv1[(2 * i)] > bv2[(2 * i) + 1])
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// Maxiumum test.
|
|
||||||
if (bv2[(2 * i)] > bv1[(2 * i) + 1])
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bvh_overlap_self - is it possbile for 2 bv's to selfcollide ?
|
|
||||||
DO_INLINE int bvh_overlap_self(CollisionTree * tree1, CollisionTree * tree2)
|
|
||||||
{
|
|
||||||
// printf("overlap: %f, q: %f\n", (saacos(INPR(tree1->normal, tree2->normal)) / 2.0)+MAX2(tree1->alpha, tree2->alpha), saacos(INPR(tree1->normal, tree2->normal)));
|
|
||||||
|
|
||||||
if((saacos(INPR(tree1->normal, tree2->normal)) / 2.0)+MAX2(tree1->alpha, tree2->alpha) > M_PI)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bvh_traverse - traverse two bvh trees looking for potential collisions.
|
|
||||||
*
|
|
||||||
* max collisions are n*n collisions --> every triangle collide with
|
|
||||||
* every other triangle that doesn't require any realloc, but uses
|
|
||||||
* much memory
|
|
||||||
*/
|
|
||||||
int bvh_traverse ( ModifierData * md1, ModifierData * md2, CollisionTree * tree1, CollisionTree * tree2, float step, CM_COLLISION_RESPONSE collision_response, int selfcollision)
|
|
||||||
{
|
|
||||||
int i = 0, ret=0, overlap = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Shouldn't be possible
|
|
||||||
if(!tree1 || !tree2)
|
|
||||||
{
|
|
||||||
printf("Error: no tree there\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(selfcollision)
|
|
||||||
overlap = bvh_overlap_self(tree1, tree2);
|
|
||||||
else
|
|
||||||
overlap = bvh_overlap(tree1->bv, tree2->bv);
|
|
||||||
|
|
||||||
if (overlap)
|
|
||||||
{
|
|
||||||
// Check if this node in the first tree is a leaf
|
|
||||||
if (tree1->isleaf)
|
|
||||||
{
|
|
||||||
// Check if this node in the second tree a leaf
|
|
||||||
if (tree2->isleaf)
|
|
||||||
{
|
|
||||||
// Provide the collision response.
|
|
||||||
|
|
||||||
if(collision_response)
|
|
||||||
collision_response (md1, md2, tree1, tree2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Process the quad tree.
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
// Only traverse nodes that exist.
|
|
||||||
if (tree2->nodes[i] && bvh_traverse (md1, md2, tree1, tree2->nodes[i], step, collision_response, selfcollision))
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Process the quad tree.
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
// Only traverse nodes that exist.
|
|
||||||
if (tree1->nodes [i] && bvh_traverse (md1, md2, tree1->nodes[i], tree2, step, collision_response, selfcollision))
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
// bottom up update of bvh tree:
|
|
||||||
// join the 4 children here
|
|
||||||
void bvh_join(CollisionTree *tree)
|
|
||||||
{
|
|
||||||
int i = 0, j = 0;
|
|
||||||
float max = 0;
|
|
||||||
|
|
||||||
if (!tree)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
if (tree->nodes[i])
|
|
||||||
{
|
|
||||||
for (j = KDOP_START; j < KDOP_END; j++)
|
|
||||||
{
|
|
||||||
// update minimum
|
|
||||||
if ((tree->nodes[i]->bv[(2 * j)] < tree->bv[(2 * j)]) || (i == 0))
|
|
||||||
{
|
|
||||||
tree->bv[(2 * j)] = tree->nodes[i]->bv[(2 * j)];
|
|
||||||
}
|
|
||||||
// update maximum
|
|
||||||
if ((tree->nodes[i]->bv[(2 * j) + 1] > tree->bv[(2 * j) + 1])|| (i == 0))
|
|
||||||
{
|
|
||||||
tree->bv[(2 * j) + 1] = tree->nodes[i]->bv[(2 * j) + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* for selfcollisions */
|
|
||||||
/*
|
|
||||||
if(!i)
|
|
||||||
{
|
|
||||||
tree->alpha = tree->nodes[i]->alpha;
|
|
||||||
VECCOPY(tree->normal, tree->nodes[i]->normal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tree->alpha += saacos(INPR(tree->normal, tree->nodes[i]->normal)) / 2.0;
|
|
||||||
VECADD(tree->normal, tree->normal, tree->nodes[i]->normal);
|
|
||||||
VecMulf(tree->normal, 0.5);
|
|
||||||
max = MAX2(max, tree->nodes[i]->alpha);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree->alpha += max;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update static bvh
|
|
||||||
/* you have to update the bvh position before calling this function */
|
|
||||||
void bvh_update(BVH * bvh, int moving)
|
|
||||||
{
|
|
||||||
CollisionTree *leaf, *parent;
|
|
||||||
int traversecheck = 1; // if this is zero we don't go further
|
|
||||||
unsigned int j = 0;
|
|
||||||
|
|
||||||
for (leaf = bvh->leaf_root; leaf; leaf = leaf->nextLeaf)
|
|
||||||
{
|
|
||||||
traversecheck = 1;
|
|
||||||
if ((leaf->parent) && (leaf->parent->traversed == leaf->parent->count_nodes))
|
|
||||||
{
|
|
||||||
leaf->parent->traversed = 0;
|
|
||||||
}
|
|
||||||
if(!moving)
|
|
||||||
bvh_calc_DOP_hull_static(bvh, &leaf, 1, leaf->bv, leaf);
|
|
||||||
else
|
|
||||||
bvh_calc_DOP_hull_moving(bvh, &leaf, 1, leaf->bv, leaf);
|
|
||||||
|
|
||||||
// inflate the bv with some epsilon
|
|
||||||
for (j = KDOP_START; j < KDOP_END; j++)
|
|
||||||
{
|
|
||||||
leaf->bv[(2 * j)] -= bvh->epsilon; // minimum
|
|
||||||
leaf->bv[(2 * j) + 1] += bvh->epsilon; // maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
for (parent = leaf->parent; parent; parent = parent->parent)
|
|
||||||
{
|
|
||||||
if (traversecheck)
|
|
||||||
{
|
|
||||||
parent->traversed++; // we tried to go up in hierarchy
|
|
||||||
if (parent->traversed < parent->count_nodes)
|
|
||||||
{
|
|
||||||
traversecheck = 0;
|
|
||||||
|
|
||||||
if (parent->parent)
|
|
||||||
{
|
|
||||||
if (parent->parent->traversed == parent->parent->count_nodes)
|
|
||||||
{
|
|
||||||
parent->parent->traversed = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break; // we do not need to check further
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bvh_join(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
#include "BLI_arithb.h"
|
#include "BLI_arithb.h"
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
|
#include "BLI_kdopbvh.h"
|
||||||
#include "BLI_kdtree.h"
|
#include "BLI_kdtree.h"
|
||||||
#include "BLI_linklist.h"
|
#include "BLI_linklist.h"
|
||||||
#include "BLI_rand.h"
|
#include "BLI_rand.h"
|
||||||
@@ -5193,7 +5194,7 @@ static void collisionModifier_initData(ModifierData *md)
|
|||||||
collmd->current_v = NULL;
|
collmd->current_v = NULL;
|
||||||
collmd->time = -1;
|
collmd->time = -1;
|
||||||
collmd->numverts = 0;
|
collmd->numverts = 0;
|
||||||
collmd->bvh = NULL;
|
collmd->bvhtree = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void collisionModifier_freeData(ModifierData *md)
|
static void collisionModifier_freeData(ModifierData *md)
|
||||||
@@ -5202,8 +5203,8 @@ static void collisionModifier_freeData(ModifierData *md)
|
|||||||
|
|
||||||
if (collmd)
|
if (collmd)
|
||||||
{
|
{
|
||||||
if(collmd->bvh)
|
if(collmd->bvhtree)
|
||||||
bvh_free(collmd->bvh);
|
BLI_bvhtree_free(collmd->bvhtree);
|
||||||
if(collmd->x)
|
if(collmd->x)
|
||||||
MEM_freeN(collmd->x);
|
MEM_freeN(collmd->x);
|
||||||
if(collmd->xnew)
|
if(collmd->xnew)
|
||||||
@@ -5214,7 +5215,6 @@ static void collisionModifier_freeData(ModifierData *md)
|
|||||||
MEM_freeN(collmd->current_xnew);
|
MEM_freeN(collmd->current_xnew);
|
||||||
if(collmd->current_v)
|
if(collmd->current_v)
|
||||||
MEM_freeN(collmd->current_v);
|
MEM_freeN(collmd->current_v);
|
||||||
|
|
||||||
if(collmd->mfaces)
|
if(collmd->mfaces)
|
||||||
MEM_freeN(collmd->mfaces);
|
MEM_freeN(collmd->mfaces);
|
||||||
|
|
||||||
@@ -5225,7 +5225,7 @@ static void collisionModifier_freeData(ModifierData *md)
|
|||||||
collmd->current_v = NULL;
|
collmd->current_v = NULL;
|
||||||
collmd->time = -1;
|
collmd->time = -1;
|
||||||
collmd->numverts = 0;
|
collmd->numverts = 0;
|
||||||
collmd->bvh = NULL;
|
collmd->bvhtree = NULL;
|
||||||
collmd->mfaces = NULL;
|
collmd->mfaces = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5293,9 +5293,8 @@ static void collisionModifier_deformVerts(
|
|||||||
collmd->mfaces = dm->dupFaceArray(dm);
|
collmd->mfaces = dm->dupFaceArray(dm);
|
||||||
collmd->numfaces = dm->getNumFaces(dm);
|
collmd->numfaces = dm->getNumFaces(dm);
|
||||||
|
|
||||||
// TODO: epsilon
|
|
||||||
// create bounding box hierarchy
|
// create bounding box hierarchy
|
||||||
collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft);
|
collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft);
|
||||||
|
|
||||||
collmd->time = current_time;
|
collmd->time = current_time;
|
||||||
}
|
}
|
||||||
@@ -5318,25 +5317,25 @@ static void collisionModifier_deformVerts(
|
|||||||
memcpy(collmd->current_x, collmd->x, numverts*sizeof(MVert));
|
memcpy(collmd->current_x, collmd->x, numverts*sizeof(MVert));
|
||||||
|
|
||||||
/* check if GUI setting has changed for bvh */
|
/* check if GUI setting has changed for bvh */
|
||||||
if(collmd->bvh)
|
if(collmd->bvhtree)
|
||||||
{
|
{
|
||||||
if(ob->pd->pdef_sboft != collmd->bvh->epsilon)
|
if(ob->pd->pdef_sboft != BLI_bvhtree_getepsilon(collmd->bvhtree))
|
||||||
{
|
{
|
||||||
bvh_free(collmd->bvh);
|
BLI_bvhtree_free(collmd->bvhtree);
|
||||||
collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
|
collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* happens on file load (ONLY when i decomment changes in readfile.c */
|
/* happens on file load (ONLY when i decomment changes in readfile.c) */
|
||||||
if(!collmd->bvh)
|
if(!collmd->bvhtree)
|
||||||
{
|
{
|
||||||
collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
|
collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// recalc static bounding boxes
|
// recalc static bounding boxes
|
||||||
bvh_update_from_mvert(collmd->bvh, collmd->current_x, numverts, NULL, 0);
|
bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
collmd->time = current_time;
|
collmd->time = current_time;
|
||||||
|
|||||||
60
source/blender/blenlib/BLI_kdopbvh.h
Normal file
60
source/blender/blenlib/BLI_kdopbvh.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2006 by NaN Holding BV.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* The Original Code is: all of this file.
|
||||||
|
*
|
||||||
|
* Contributor(s): Daniel Genrich, Andre Pinto
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef BLI_KDOPBVH_H
|
||||||
|
#define BLI_KDOPBVH_H
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
struct BVHTree;
|
||||||
|
typedef struct BVHTree BVHTree;
|
||||||
|
|
||||||
|
typedef struct BVHTreeOverlap {
|
||||||
|
int indexA;
|
||||||
|
int indexB;
|
||||||
|
} BVHTreeOverlap;
|
||||||
|
|
||||||
|
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
|
||||||
|
void BLI_bvhtree_free(BVHTree *tree);
|
||||||
|
|
||||||
|
/* construct: first insert points, then call balance */
|
||||||
|
int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints);
|
||||||
|
void BLI_bvhtree_balance(BVHTree *tree);
|
||||||
|
|
||||||
|
/* update: first update points/nodes, then call update_tree to refit the bounding volumes */
|
||||||
|
int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints);
|
||||||
|
void BLI_bvhtree_update_tree(BVHTree *tree);
|
||||||
|
|
||||||
|
/* collision/overlap: check two trees if they overlap, alloc's *overlap with length of the int return value */
|
||||||
|
BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result);
|
||||||
|
|
||||||
|
float BLI_bvhtree_getepsilon(BVHTree *tree);
|
||||||
|
|
||||||
|
#endif // BLI_KDOPBVH_H
|
||||||
|
|
||||||
811
source/blender/blenlib/intern/BLI_kdopbvh.c
Normal file
811
source/blender/blenlib/intern/BLI_kdopbvh.c
Normal file
@@ -0,0 +1,811 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2006 by NaN Holding BV.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* The Original Code is: all of this file.
|
||||||
|
*
|
||||||
|
* Contributor(s): Daniel Genrich, Andre Pinto
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "math.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "BKE_utildefines.h"
|
||||||
|
|
||||||
|
#include "BLI_kdopbvh.h"
|
||||||
|
#include "BLI_arithb.h"
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
#include <omp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct BVHNode
|
||||||
|
{
|
||||||
|
struct BVHNode **children; // max 8 children
|
||||||
|
struct BVHNode *parent; // needed for bottom - top update
|
||||||
|
float *bv; // Bounding volume of all nodes, max 13 axis
|
||||||
|
int index; /* face, edge, vertex index */
|
||||||
|
char totnode; // how many nodes are used, used for speedup
|
||||||
|
char traversed; // how many nodes already traversed until this level?
|
||||||
|
char main_axis;
|
||||||
|
} BVHNode;
|
||||||
|
|
||||||
|
struct BVHTree
|
||||||
|
{
|
||||||
|
BVHNode **nodes;
|
||||||
|
BVHNode *nodearray; /* pre-alloc branch nodes */
|
||||||
|
BVHNode **nodechild; // pre-alloc childs for nodes
|
||||||
|
float *nodebv; // pre-alloc bounding-volumes for nodes
|
||||||
|
float epsilon; /* epslion is used for inflation of the k-dop */
|
||||||
|
int totleaf; // leafs
|
||||||
|
int totbranch;
|
||||||
|
char tree_type; // type of tree (4 => quadtree)
|
||||||
|
char axis; // kdop type (6 => OBB, 7 => AABB, ...)
|
||||||
|
char start_axis, stop_axis; // KDOP_AXES array indices according to axis
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct BVHOverlapData
|
||||||
|
{
|
||||||
|
BVHTree *tree1, *tree2;
|
||||||
|
BVHTreeOverlap *overlap;
|
||||||
|
int i, max_overlap; /* i is number of overlaps */
|
||||||
|
} BVHOverlapData;
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Bounding Volume Hierarchy Definition
|
||||||
|
//
|
||||||
|
// Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below
|
||||||
|
// Notes: You have to choose the type at compile time ITM
|
||||||
|
// Notes: You can choose the tree type --> binary, quad, octree, choose below
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static float KDOP_AXES[13][3] =
|
||||||
|
{ {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0},
|
||||||
|
{1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0},
|
||||||
|
{0, 1.0, -1.0}
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introsort
|
||||||
|
// with permission deriven from the following Java code:
|
||||||
|
// http://ralphunden.net/content/tutorials/a-guide-to-introsort/
|
||||||
|
// and he derived it from the SUN STL
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static int size_threshold = 16;
|
||||||
|
/*
|
||||||
|
* Common methods for all algorithms
|
||||||
|
*/
|
||||||
|
static int floor_lg(int a)
|
||||||
|
{
|
||||||
|
return (int)(floor(log(a)/log(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insertion sort algorithm
|
||||||
|
*/
|
||||||
|
static void bvh_insertionsort(BVHNode **a, int lo, int hi, int axis)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
BVHNode *t;
|
||||||
|
for (i=lo; i < hi; i++)
|
||||||
|
{
|
||||||
|
j=i;
|
||||||
|
t = a[i];
|
||||||
|
while((j!=lo) && (t->bv[axis] < (a[j-1])->bv[axis]))
|
||||||
|
{
|
||||||
|
a[j] = a[j-1];
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
a[j] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bvh_partition(BVHNode **a, int lo, int hi, BVHNode * x, int axis)
|
||||||
|
{
|
||||||
|
int i=lo, j=hi;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
while ((a[i])->bv[axis] < x->bv[axis]) i++;
|
||||||
|
j--;
|
||||||
|
while (x->bv[axis] < (a[j])->bv[axis]) j--;
|
||||||
|
if(!(i < j))
|
||||||
|
return i;
|
||||||
|
SWAP( BVHNode* , a[i], a[j]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Heapsort algorithm
|
||||||
|
*/
|
||||||
|
static void bvh_downheap(BVHNode **a, int i, int n, int lo, int axis)
|
||||||
|
{
|
||||||
|
BVHNode * d = a[lo+i-1];
|
||||||
|
int child;
|
||||||
|
while (i<=n/2)
|
||||||
|
{
|
||||||
|
child = 2*i;
|
||||||
|
if ((child < n) && ((a[lo+child-1])->bv[axis] < (a[lo+child])->bv[axis]))
|
||||||
|
{
|
||||||
|
child++;
|
||||||
|
}
|
||||||
|
if (!(d->bv[axis] < (a[lo+child-1])->bv[axis])) break;
|
||||||
|
a[lo+i-1] = a[lo+child-1];
|
||||||
|
i = child;
|
||||||
|
}
|
||||||
|
a[lo+i-1] = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bvh_heapsort(BVHNode **a, int lo, int hi, int axis)
|
||||||
|
{
|
||||||
|
int n = hi-lo, i;
|
||||||
|
for (i=n/2; i>=1; i=i-1)
|
||||||
|
{
|
||||||
|
bvh_downheap(a, i,n,lo, axis);
|
||||||
|
}
|
||||||
|
for (i=n; i>1; i=i-1)
|
||||||
|
{
|
||||||
|
SWAP(BVHNode*, a[lo],a[lo+i-1]);
|
||||||
|
bvh_downheap(a, 1,i-1,lo, axis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BVHNode *bvh_medianof3(BVHNode **a, int lo, int mid, int hi, int axis) // returns Sortable
|
||||||
|
{
|
||||||
|
if ((a[mid])->bv[axis] < (a[lo])->bv[axis])
|
||||||
|
{
|
||||||
|
if ((a[hi])->bv[axis] < (a[mid])->bv[axis])
|
||||||
|
return a[mid];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((a[hi])->bv[axis] < (a[lo])->bv[axis])
|
||||||
|
return a[hi];
|
||||||
|
else
|
||||||
|
return a[lo];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((a[hi])->bv[axis] < (a[mid])->bv[axis])
|
||||||
|
{
|
||||||
|
if ((a[hi])->bv[axis] < (a[lo])->bv[axis])
|
||||||
|
return a[lo];
|
||||||
|
else
|
||||||
|
return a[hi];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return a[mid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Quicksort algorithm modified for Introsort
|
||||||
|
*/
|
||||||
|
static void bvh_introsort_loop (BVHNode **a, int lo, int hi, int depth_limit, int axis)
|
||||||
|
{
|
||||||
|
int p;
|
||||||
|
|
||||||
|
while (hi-lo > size_threshold)
|
||||||
|
{
|
||||||
|
if (depth_limit == 0)
|
||||||
|
{
|
||||||
|
bvh_heapsort(a, lo, hi, axis);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
depth_limit=depth_limit-1;
|
||||||
|
p=bvh_partition(a, lo, hi, bvh_medianof3(a, lo, lo+((hi-lo)/2)+1, hi-1, axis), axis);
|
||||||
|
bvh_introsort_loop(a, p, hi, depth_limit, axis);
|
||||||
|
hi=p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort(BVHNode **a0, int begin, int end, int axis)
|
||||||
|
{
|
||||||
|
if (begin < end)
|
||||||
|
{
|
||||||
|
BVHNode **a=a0;
|
||||||
|
bvh_introsort_loop(a, begin, end, 2*floor_lg(end-begin), axis);
|
||||||
|
bvh_insertionsort(a, begin, end, axis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void sort_along_axis(BVHTree *tree, int start, int end, int axis)
|
||||||
|
{
|
||||||
|
sort(tree->nodes, start, end, axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
//after a call to this function you can expect one of:
|
||||||
|
// every node to left of a[n] are smaller or equal to it
|
||||||
|
// every node to the right of a[n] are greater or equal to it
|
||||||
|
int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis){
|
||||||
|
int begin = _begin, end = _end, cut;
|
||||||
|
int i;
|
||||||
|
while(end-begin > 3)
|
||||||
|
{
|
||||||
|
cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin+end)/2, end-1, axis), axis );
|
||||||
|
if(cut <= n)
|
||||||
|
begin = cut;
|
||||||
|
else
|
||||||
|
end = cut;
|
||||||
|
}
|
||||||
|
bvh_insertionsort(a, begin, end, axis);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void BLI_bvhtree_free(BVHTree *tree)
|
||||||
|
{
|
||||||
|
if(tree)
|
||||||
|
{
|
||||||
|
MEM_freeN(tree->nodes);
|
||||||
|
MEM_freeN(tree->nodearray);
|
||||||
|
MEM_freeN(tree->nodebv);
|
||||||
|
MEM_freeN(tree->nodechild);
|
||||||
|
MEM_freeN(tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||||
|
{
|
||||||
|
BVHTree *tree;
|
||||||
|
int numbranches=0, i;
|
||||||
|
|
||||||
|
// only support up to octree
|
||||||
|
if(tree_type > 8)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree");
|
||||||
|
|
||||||
|
if(tree)
|
||||||
|
{
|
||||||
|
tree->epsilon = epsilon;
|
||||||
|
tree->tree_type = tree_type;
|
||||||
|
tree->axis = axis;
|
||||||
|
|
||||||
|
if(axis == 26)
|
||||||
|
{
|
||||||
|
tree->start_axis = 0;
|
||||||
|
tree->stop_axis = 13;
|
||||||
|
}
|
||||||
|
else if(axis == 18)
|
||||||
|
{
|
||||||
|
tree->start_axis = 7;
|
||||||
|
tree->stop_axis = 13;
|
||||||
|
}
|
||||||
|
else if(axis == 14)
|
||||||
|
{
|
||||||
|
tree->start_axis = 0;
|
||||||
|
tree->stop_axis = 7;
|
||||||
|
}
|
||||||
|
else if(axis == 8) // AABB
|
||||||
|
{
|
||||||
|
tree->start_axis = 0;
|
||||||
|
tree->stop_axis = 4;
|
||||||
|
}
|
||||||
|
else if(axis == 6) // OBB
|
||||||
|
{
|
||||||
|
tree->start_axis = 0;
|
||||||
|
tree->stop_axis = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MEM_freeN(tree);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// calculate max number of branches, our bvh kdop is "almost perfect"
|
||||||
|
for(i = 1; i <= (int)ceil((float)((float)log(maxsize)/(float)log(tree_type))); i++)
|
||||||
|
numbranches += (pow(tree_type, i) / tree_type);
|
||||||
|
|
||||||
|
tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*(numbranches+maxsize + tree_type), "BVHNodes");
|
||||||
|
|
||||||
|
if(!tree->nodes)
|
||||||
|
{
|
||||||
|
MEM_freeN(tree);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * (numbranches+maxsize + tree_type), "BVHNodeBV");
|
||||||
|
if(!tree->nodebv)
|
||||||
|
{
|
||||||
|
MEM_freeN(tree->nodes);
|
||||||
|
MEM_freeN(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->nodechild = (BVHNode**)MEM_callocN(sizeof(BVHNode*) * tree_type * (numbranches+maxsize + tree_type), "BVHNodeBV");
|
||||||
|
if(!tree->nodechild)
|
||||||
|
{
|
||||||
|
MEM_freeN(tree->nodebv);
|
||||||
|
MEM_freeN(tree->nodes);
|
||||||
|
MEM_freeN(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)*(numbranches+maxsize + tree_type), "BVHNodeArray");
|
||||||
|
|
||||||
|
if(!tree->nodearray)
|
||||||
|
{
|
||||||
|
MEM_freeN(tree->nodechild);
|
||||||
|
MEM_freeN(tree->nodebv);
|
||||||
|
MEM_freeN(tree->nodes);
|
||||||
|
MEM_freeN(tree);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//link the dynamic bv and child links
|
||||||
|
for(i=0; i< numbranches+maxsize + tree_type; i++)
|
||||||
|
{
|
||||||
|
tree->nodearray[i].bv = tree->nodebv + i * axis;
|
||||||
|
tree->nodearray[i].children = tree->nodechild + i * tree_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoints, int moving)
|
||||||
|
{
|
||||||
|
float newminmax;
|
||||||
|
int i, k;
|
||||||
|
|
||||||
|
// don't init boudings for the moving case
|
||||||
|
if(!moving)
|
||||||
|
{
|
||||||
|
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||||
|
{
|
||||||
|
node->bv[2*i] = FLT_MAX;
|
||||||
|
node->bv[2*i + 1] = -FLT_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(k = 0; k < numpoints; k++)
|
||||||
|
{
|
||||||
|
// for all Axes.
|
||||||
|
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||||
|
{
|
||||||
|
newminmax = INPR(&co[k * 3], KDOP_AXES[i]);
|
||||||
|
if (newminmax < node->bv[2 * i])
|
||||||
|
node->bv[2 * i] = newminmax;
|
||||||
|
if (newminmax > node->bv[(2 * i) + 1])
|
||||||
|
node->bv[(2 * i) + 1] = newminmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// depends on the fact that the BVH's for each face is already build
|
||||||
|
static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end)
|
||||||
|
{
|
||||||
|
float newmin,newmax;
|
||||||
|
int i, j;
|
||||||
|
float *bv = node->bv;
|
||||||
|
|
||||||
|
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||||
|
{
|
||||||
|
bv[2*i] = FLT_MAX;
|
||||||
|
bv[2*i + 1] = -FLT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = start; j < end; j++)
|
||||||
|
{
|
||||||
|
// for all Axes.
|
||||||
|
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||||
|
{
|
||||||
|
newmin = tree->nodes[j]->bv[(2 * i)];
|
||||||
|
if ((newmin < bv[(2 * i)]))
|
||||||
|
bv[(2 * i)] = newmin;
|
||||||
|
|
||||||
|
newmax = tree->nodes[j]->bv[(2 * i) + 1];
|
||||||
|
if ((newmax > bv[(2 * i) + 1]))
|
||||||
|
bv[(2 * i) + 1] = newmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints)
|
||||||
|
{
|
||||||
|
BVHNode *node= NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// insert should only possible as long as tree->totbranch is 0
|
||||||
|
if(tree->totbranch > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// TODO check if have enough nodes in array
|
||||||
|
|
||||||
|
node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||||
|
tree->totleaf++;
|
||||||
|
|
||||||
|
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||||
|
|
||||||
|
// inflate the bv with some epsilon
|
||||||
|
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||||
|
{
|
||||||
|
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||||
|
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||||
|
}
|
||||||
|
|
||||||
|
node->index= index;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only supports x,y,z axis in the moment
|
||||||
|
// but we should use a plain and simple function here for speed sake
|
||||||
|
static char get_largest_axis(float *bv)
|
||||||
|
{
|
||||||
|
float middle_point[3];
|
||||||
|
|
||||||
|
middle_point[0] = (bv[1]) - (bv[0]); // x axis
|
||||||
|
middle_point[1] = (bv[3]) - (bv[2]); // y axis
|
||||||
|
middle_point[2] = (bv[5]) - (bv[4]); // z axis
|
||||||
|
if (middle_point[0] > middle_point[1])
|
||||||
|
{
|
||||||
|
if (middle_point[0] > middle_point[2])
|
||||||
|
return 1; // max x axis
|
||||||
|
else
|
||||||
|
return 5; // max z axis
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (middle_point[1] > middle_point[2])
|
||||||
|
return 3; // max y axis
|
||||||
|
else
|
||||||
|
return 5; // max z axis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bvh_div_nodes(BVHTree *tree, BVHNode *node, int start, int end, char lastaxis)
|
||||||
|
{
|
||||||
|
char laxis;
|
||||||
|
int i, tend;
|
||||||
|
BVHNode *tnode;
|
||||||
|
int slice = (end-start+tree->tree_type-1)/tree->tree_type; //division rounded up
|
||||||
|
|
||||||
|
// Determine which axis to split along
|
||||||
|
laxis = get_largest_axis(node->bv);
|
||||||
|
|
||||||
|
// split nodes along longest axis
|
||||||
|
for (i=0; start < end; start += slice, i++) //i counts the current child
|
||||||
|
{
|
||||||
|
tend = start + slice;
|
||||||
|
|
||||||
|
if(tend > end) tend = end;
|
||||||
|
|
||||||
|
if(tend-start == 1) // ok, we have 1 left for this node
|
||||||
|
{
|
||||||
|
node->children[i] = tree->nodes[start];
|
||||||
|
node->children[i]->parent = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tnode = node->children[i] = tree->nodes[tree->totleaf + tree->totbranch] = &(tree->nodearray[tree->totbranch + tree->totleaf]);
|
||||||
|
tree->totbranch++;
|
||||||
|
tnode->parent = node;
|
||||||
|
|
||||||
|
if(tend != end)
|
||||||
|
partition_nth_element(tree->nodes, start, end, tend, laxis);
|
||||||
|
refit_kdop_hull(tree, tnode, start, tend);
|
||||||
|
bvh_div_nodes(tree, tnode, start, tend, laxis);
|
||||||
|
}
|
||||||
|
node->totnode++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void verify_tree(BVHTree *tree)
|
||||||
|
{
|
||||||
|
int i, j, check = 0;
|
||||||
|
|
||||||
|
// check the pointer list
|
||||||
|
for(i = 0; i < tree->totleaf; i++)
|
||||||
|
{
|
||||||
|
if(tree->nodes[i]->parent == NULL)
|
||||||
|
printf("Leaf has no parent: %d\n", i);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(j = 0; j < tree->tree_type; j++)
|
||||||
|
{
|
||||||
|
if(tree->nodes[i]->parent->children[j] == tree->nodes[i])
|
||||||
|
check = 1;
|
||||||
|
}
|
||||||
|
if(!check)
|
||||||
|
{
|
||||||
|
printf("Parent child relationship doesn't match: %d\n", i);
|
||||||
|
}
|
||||||
|
check = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the leaf list
|
||||||
|
for(i = 0; i < tree->totleaf; i++)
|
||||||
|
{
|
||||||
|
if(tree->nodearray[i].parent == NULL)
|
||||||
|
printf("Leaf has no parent: %d\n", i);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(j = 0; j < tree->tree_type; j++)
|
||||||
|
{
|
||||||
|
if(tree->nodearray[i].parent->children[j] == &tree->nodearray[i])
|
||||||
|
check = 1;
|
||||||
|
}
|
||||||
|
if(!check)
|
||||||
|
{
|
||||||
|
printf("Parent child relationship doesn't match: %d\n", i);
|
||||||
|
}
|
||||||
|
check = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLI_bvhtree_balance(BVHTree *tree)
|
||||||
|
{
|
||||||
|
BVHNode *node;
|
||||||
|
|
||||||
|
if(tree->totleaf == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create root node
|
||||||
|
node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||||
|
tree->totbranch++;
|
||||||
|
|
||||||
|
// refit root bvh node
|
||||||
|
refit_kdop_hull(tree, tree->nodes[tree->totleaf], 0, tree->totleaf);
|
||||||
|
// create + balance tree
|
||||||
|
bvh_div_nodes(tree, tree->nodes[tree->totleaf], 0, tree->totleaf, 0);
|
||||||
|
|
||||||
|
// verify_tree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
// overlap - is it possbile for 2 bv's to collide ?
|
||||||
|
static int tree_overlap(float *bv1, float *bv2, int start_axis, int stop_axis)
|
||||||
|
{
|
||||||
|
float *bv1_end = bv1 + (stop_axis<<1);
|
||||||
|
|
||||||
|
bv1 += start_axis<<1;
|
||||||
|
bv2 += start_axis<<1;
|
||||||
|
|
||||||
|
// test all axis if min + max overlap
|
||||||
|
for (; bv1 != bv1_end; bv1+=2, bv2+=2)
|
||||||
|
{
|
||||||
|
if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1)))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if(tree_overlap(node1->bv, node2->bv, MIN2(data->tree1->start_axis, data->tree2->start_axis), MIN2(data->tree1->stop_axis, data->tree2->stop_axis)))
|
||||||
|
{
|
||||||
|
// check if node1 is a leaf
|
||||||
|
if(!node1->totnode)
|
||||||
|
{
|
||||||
|
// check if node2 is a leaf
|
||||||
|
if(!node2->totnode)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(node1 == node2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data->i >= data->max_overlap)
|
||||||
|
{
|
||||||
|
// try to make alloc'ed memory bigger
|
||||||
|
data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap)*data->max_overlap*2);
|
||||||
|
|
||||||
|
if(!data->overlap)
|
||||||
|
{
|
||||||
|
printf("Out of Memory in traverse\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->max_overlap *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// both leafs, insert overlap!
|
||||||
|
data->overlap[data->i].indexA = node1->index;
|
||||||
|
data->overlap[data->i].indexB = node2->index;
|
||||||
|
|
||||||
|
data->i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(j = 0; j < data->tree2->tree_type; j++)
|
||||||
|
{
|
||||||
|
if(node2->children[j])
|
||||||
|
traverse(data, node1, node2->children[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
for(j = 0; j < data->tree2->tree_type; j++)
|
||||||
|
{
|
||||||
|
if(node1->children[j])
|
||||||
|
traverse(data, node1->children[j], node2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result)
|
||||||
|
{
|
||||||
|
int j, total = 0;
|
||||||
|
BVHTreeOverlap *overlap = NULL, *to = NULL;
|
||||||
|
BVHOverlapData **data;
|
||||||
|
|
||||||
|
// check for compatibility of both trees (can't compare 14-DOP with 18-DOP)
|
||||||
|
if((tree1->axis != tree2->axis) && ((tree1->axis == 14) || tree2->axis == 14))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// fast check root nodes for collision before doing big splitting + traversal
|
||||||
|
if(!tree_overlap(tree1->nodes[tree1->totleaf]->bv, tree2->nodes[tree2->totleaf]->bv, MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
data = MEM_callocN(sizeof(BVHOverlapData *)* tree1->tree_type, "BVHOverlapData_star");
|
||||||
|
|
||||||
|
for(j = 0; j < tree1->tree_type; j++)
|
||||||
|
{
|
||||||
|
data[j] = (BVHOverlapData *)MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData");
|
||||||
|
|
||||||
|
// init BVHOverlapData
|
||||||
|
data[j]->overlap = (BVHTreeOverlap *)malloc(sizeof(BVHTreeOverlap)*MAX2(tree1->totleaf, tree2->totleaf));
|
||||||
|
data[j]->tree1 = tree1;
|
||||||
|
data[j]->tree2 = tree2;
|
||||||
|
data[j]->max_overlap = MAX2(tree1->totleaf, tree2->totleaf);
|
||||||
|
data[j]->i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma omp parallel for private(j) schedule(static)
|
||||||
|
for(j = 0; j < tree1->tree_type; j++)
|
||||||
|
{
|
||||||
|
traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j = 0; j < tree1->tree_type; j++)
|
||||||
|
total += data[j]->i;
|
||||||
|
|
||||||
|
to = overlap = (BVHTreeOverlap *)MEM_callocN(sizeof(BVHTreeOverlap)*total, "BVHTreeOverlap");
|
||||||
|
|
||||||
|
for(j = 0; j < tree1->tree_type; j++)
|
||||||
|
{
|
||||||
|
memcpy(to, data[j]->overlap, data[j]->i*sizeof(BVHTreeOverlap));
|
||||||
|
to+=data[j]->i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j = 0; j < tree1->tree_type; j++)
|
||||||
|
{
|
||||||
|
free(data[j]->overlap);
|
||||||
|
MEM_freeN(data[j]);
|
||||||
|
}
|
||||||
|
MEM_freeN(data);
|
||||||
|
|
||||||
|
(*result) = total;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// bottom up update of bvh tree:
|
||||||
|
// join the 4 children here
|
||||||
|
static void node_join(BVHTree *tree, BVHNode *node)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||||
|
{
|
||||||
|
node->bv[2*i] = FLT_MAX;
|
||||||
|
node->bv[2*i + 1] = -FLT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < tree->tree_type; i++)
|
||||||
|
{
|
||||||
|
if (node->children[i])
|
||||||
|
{
|
||||||
|
for (j = tree->start_axis; j < tree->stop_axis; j++)
|
||||||
|
{
|
||||||
|
// update minimum
|
||||||
|
if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)])
|
||||||
|
node->bv[(2 * j)] = node->children[i]->bv[(2 * j)];
|
||||||
|
|
||||||
|
// update maximum
|
||||||
|
if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1])
|
||||||
|
node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// call before BLI_bvhtree_update_tree()
|
||||||
|
int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints)
|
||||||
|
{
|
||||||
|
BVHNode *node= NULL;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// check if index exists
|
||||||
|
if(index > tree->totleaf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
node = tree->nodearray + index;
|
||||||
|
|
||||||
|
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||||
|
|
||||||
|
if(co_moving)
|
||||||
|
create_kdop_hull(tree, node, co_moving, numpoints, 1);
|
||||||
|
|
||||||
|
// inflate the bv with some epsilon
|
||||||
|
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||||
|
{
|
||||||
|
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||||
|
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call BLI_bvhtree_update_node() first for every node/point/triangle
|
||||||
|
void BLI_bvhtree_update_tree(BVHTree *tree)
|
||||||
|
{
|
||||||
|
BVHNode *leaf, *parent;
|
||||||
|
|
||||||
|
// reset tree traversing flag
|
||||||
|
for (leaf = tree->nodearray + tree->totleaf; leaf != tree->nodearray + tree->totleaf + tree->totbranch; leaf++)
|
||||||
|
leaf->traversed = 0;
|
||||||
|
|
||||||
|
for (leaf = tree->nodearray; leaf != tree->nodearray + tree->totleaf; leaf++)
|
||||||
|
{
|
||||||
|
for (parent = leaf->parent; parent; parent = parent->parent)
|
||||||
|
{
|
||||||
|
parent->traversed++; // we tried to go up in hierarchy
|
||||||
|
if (parent->traversed < parent->totnode)
|
||||||
|
break; // we do not need to check further
|
||||||
|
else
|
||||||
|
node_join(tree, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float BLI_bvhtree_getepsilon(BVHTree *tree)
|
||||||
|
{
|
||||||
|
return tree->epsilon;
|
||||||
|
}
|
||||||
@@ -3108,7 +3108,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
|
|||||||
collmd->current_v = NULL;
|
collmd->current_v = NULL;
|
||||||
collmd->time = -1;
|
collmd->time = -1;
|
||||||
collmd->numverts = 0;
|
collmd->numverts = 0;
|
||||||
collmd->bvh = NULL;
|
collmd->bvhtree = NULL;
|
||||||
collmd->mfaces = NULL;
|
collmd->mfaces = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ typedef struct CollisionModifierData {
|
|||||||
unsigned int numfaces;
|
unsigned int numfaces;
|
||||||
int pad;
|
int pad;
|
||||||
float time; /* cfra time of modifier */
|
float time; /* cfra time of modifier */
|
||||||
struct BVH *bvh; /* bounding volume hierarchy for this cloth object */
|
struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */
|
||||||
} CollisionModifierData;
|
} CollisionModifierData;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
Reference in New Issue
Block a user