Home | History | Annotate | Download | only in BulletSoftBody
      1 /*
      2 Bullet Continuous Collision Detection and Physics Library
      3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
      4 
      5 This software is provided 'as-is', without any express or implied warranty.
      6 In no event will the authors be held liable for any damages arising from the use of this software.
      7 Permission is granted to anyone to use this software for any purpose,
      8 including commercial applications, and to alter it and redistribute it freely,
      9 subject to the following restrictions:
     10 
     11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
     12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
     13 3. This notice may not be removed or altered from any source distribution.
     14 */
     15 ///btSparseSdf implementation by Nathanael Presson
     16 
     17 #ifndef BT_SPARSE_SDF_H
     18 #define BT_SPARSE_SDF_H
     19 
     20 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
     21 #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
     22 
     23 // Modified Paul Hsieh hash
     24 template <const int DWORDLEN>
     25 unsigned int HsiehHash(const void* pdata)
     26 {
     27 	const unsigned short*	data=(const unsigned short*)pdata;
     28 	unsigned				hash=DWORDLEN<<2,tmp;
     29 	for(int i=0;i<DWORDLEN;++i)
     30 	{
     31 		hash	+=	data[0];
     32 		tmp		=	(data[1]<<11)^hash;
     33 		hash	=	(hash<<16)^tmp;
     34 		data	+=	2;
     35 		hash	+=	hash>>11;
     36 	}
     37 	hash^=hash<<3;hash+=hash>>5;
     38 	hash^=hash<<4;hash+=hash>>17;
     39 	hash^=hash<<25;hash+=hash>>6;
     40 	return(hash);
     41 }
     42 
     43 template <const int CELLSIZE>
     44 struct	btSparseSdf
     45 {
     46 	//
     47 	// Inner types
     48 	//
     49 	struct IntFrac
     50 	{
     51 		int					b;
     52 		int					i;
     53 		btScalar			f;
     54 	};
     55 	struct	Cell
     56 	{
     57 		btScalar			d[CELLSIZE+1][CELLSIZE+1][CELLSIZE+1];
     58 		int					c[3];
     59 		int					puid;
     60 		unsigned			hash;
     61 		const btCollisionShape*	pclient;
     62 		Cell*				next;
     63 	};
     64 	//
     65 	// Fields
     66 	//
     67 
     68 	btAlignedObjectArray<Cell*>		cells;
     69 	btScalar						voxelsz;
     70 	int								puid;
     71 	int								ncells;
     72 	int								m_clampCells;
     73 	int								nprobes;
     74 	int								nqueries;
     75 
     76 	//
     77 	// Methods
     78 	//
     79 
     80 	//
     81 	void					Initialize(int hashsize=2383, int clampCells = 256*1024)
     82 	{
     83 		//avoid a crash due to running out of memory, so clamp the maximum number of cells allocated
     84 		//if this limit is reached, the SDF is reset (at the cost of some performance during the reset)
     85 		m_clampCells = clampCells;
     86 		cells.resize(hashsize,0);
     87 		Reset();
     88 	}
     89 	//
     90 	void					Reset()
     91 	{
     92 		for(int i=0,ni=cells.size();i<ni;++i)
     93 		{
     94 			Cell*	pc=cells[i];
     95 			cells[i]=0;
     96 			while(pc)
     97 			{
     98 				Cell*	pn=pc->next;
     99 				delete pc;
    100 				pc=pn;
    101 			}
    102 		}
    103 		voxelsz		=0.25;
    104 		puid		=0;
    105 		ncells		=0;
    106 		nprobes		=1;
    107 		nqueries	=1;
    108 	}
    109 	//
    110 	void					GarbageCollect(int lifetime=256)
    111 	{
    112 		const int life=puid-lifetime;
    113 		for(int i=0;i<cells.size();++i)
    114 		{
    115 			Cell*&	root=cells[i];
    116 			Cell*	pp=0;
    117 			Cell*	pc=root;
    118 			while(pc)
    119 			{
    120 				Cell*	pn=pc->next;
    121 				if(pc->puid<life)
    122 				{
    123 					if(pp) pp->next=pn; else root=pn;
    124 					delete pc;pc=pp;--ncells;
    125 				}
    126 				pp=pc;pc=pn;
    127 			}
    128 		}
    129 		//printf("GC[%d]: %d cells, PpQ: %f\r\n",puid,ncells,nprobes/(btScalar)nqueries);
    130 		nqueries=1;
    131 		nprobes=1;
    132 		++puid;	///@todo: Reset puid's when int range limit is reached	*/
    133 		/* else setup a priority list...						*/
    134 	}
    135 	//
    136 	int						RemoveReferences(btCollisionShape* pcs)
    137 	{
    138 		int	refcount=0;
    139 		for(int i=0;i<cells.size();++i)
    140 		{
    141 			Cell*&	root=cells[i];
    142 			Cell*	pp=0;
    143 			Cell*	pc=root;
    144 			while(pc)
    145 			{
    146 				Cell*	pn=pc->next;
    147 				if(pc->pclient==pcs)
    148 				{
    149 					if(pp) pp->next=pn; else root=pn;
    150 					delete pc;pc=pp;++refcount;
    151 				}
    152 				pp=pc;pc=pn;
    153 			}
    154 		}
    155 		return(refcount);
    156 	}
    157 	//
    158 	btScalar				Evaluate(	const btVector3& x,
    159 		const btCollisionShape* shape,
    160 		btVector3& normal,
    161 		btScalar margin)
    162 	{
    163 		/* Lookup cell			*/
    164 		const btVector3	scx=x/voxelsz;
    165 		const IntFrac	ix=Decompose(scx.x());
    166 		const IntFrac	iy=Decompose(scx.y());
    167 		const IntFrac	iz=Decompose(scx.z());
    168 		const unsigned	h=Hash(ix.b,iy.b,iz.b,shape);
    169 		Cell*&			root=cells[static_cast<int>(h%cells.size())];
    170 		Cell*			c=root;
    171 		++nqueries;
    172 		while(c)
    173 		{
    174 			++nprobes;
    175 			if(	(c->hash==h)	&&
    176 				(c->c[0]==ix.b)	&&
    177 				(c->c[1]==iy.b)	&&
    178 				(c->c[2]==iz.b)	&&
    179 				(c->pclient==shape))
    180 			{ break; }
    181 			else
    182 			{ c=c->next; }
    183 		}
    184 		if(!c)
    185 		{
    186 			++nprobes;
    187 			++ncells;
    188 			int sz = sizeof(Cell);
    189 			if (ncells>m_clampCells)
    190 			{
    191 				static int numResets=0;
    192 				numResets++;
    193 //				printf("numResets=%d\n",numResets);
    194 				Reset();
    195 			}
    196 
    197 			c=new Cell();
    198 			c->next=root;root=c;
    199 			c->pclient=shape;
    200 			c->hash=h;
    201 			c->c[0]=ix.b;c->c[1]=iy.b;c->c[2]=iz.b;
    202 			BuildCell(*c);
    203 		}
    204 		c->puid=puid;
    205 		/* Extract infos		*/
    206 		const int		o[]={	ix.i,iy.i,iz.i};
    207 		const btScalar	d[]={	c->d[o[0]+0][o[1]+0][o[2]+0],
    208 			c->d[o[0]+1][o[1]+0][o[2]+0],
    209 			c->d[o[0]+1][o[1]+1][o[2]+0],
    210 			c->d[o[0]+0][o[1]+1][o[2]+0],
    211 			c->d[o[0]+0][o[1]+0][o[2]+1],
    212 			c->d[o[0]+1][o[1]+0][o[2]+1],
    213 			c->d[o[0]+1][o[1]+1][o[2]+1],
    214 			c->d[o[0]+0][o[1]+1][o[2]+1]};
    215 		/* Normal	*/
    216 #if 1
    217 		const btScalar	gx[]={	d[1]-d[0],d[2]-d[3],
    218 			d[5]-d[4],d[6]-d[7]};
    219 		const btScalar	gy[]={	d[3]-d[0],d[2]-d[1],
    220 			d[7]-d[4],d[6]-d[5]};
    221 		const btScalar	gz[]={	d[4]-d[0],d[5]-d[1],
    222 			d[7]-d[3],d[6]-d[2]};
    223 		normal.setX(Lerp(	Lerp(gx[0],gx[1],iy.f),
    224 			Lerp(gx[2],gx[3],iy.f),iz.f));
    225 		normal.setY(Lerp(	Lerp(gy[0],gy[1],ix.f),
    226 			Lerp(gy[2],gy[3],ix.f),iz.f));
    227 		normal.setZ(Lerp(	Lerp(gz[0],gz[1],ix.f),
    228 			Lerp(gz[2],gz[3],ix.f),iy.f));
    229 		normal		=	normal.normalized();
    230 #else
    231 		normal		=	btVector3(d[1]-d[0],d[3]-d[0],d[4]-d[0]).normalized();
    232 #endif
    233 		/* Distance	*/
    234 		const btScalar	d0=Lerp(Lerp(d[0],d[1],ix.f),
    235 			Lerp(d[3],d[2],ix.f),iy.f);
    236 		const btScalar	d1=Lerp(Lerp(d[4],d[5],ix.f),
    237 			Lerp(d[7],d[6],ix.f),iy.f);
    238 		return(Lerp(d0,d1,iz.f)-margin);
    239 	}
    240 	//
    241 	void					BuildCell(Cell& c)
    242 	{
    243 		const btVector3	org=btVector3(	(btScalar)c.c[0],
    244 			(btScalar)c.c[1],
    245 			(btScalar)c.c[2])	*
    246 			CELLSIZE*voxelsz;
    247 		for(int k=0;k<=CELLSIZE;++k)
    248 		{
    249 			const btScalar	z=voxelsz*k+org.z();
    250 			for(int j=0;j<=CELLSIZE;++j)
    251 			{
    252 				const btScalar	y=voxelsz*j+org.y();
    253 				for(int i=0;i<=CELLSIZE;++i)
    254 				{
    255 					const btScalar	x=voxelsz*i+org.x();
    256 					c.d[i][j][k]=DistanceToShape(	btVector3(x,y,z),
    257 						c.pclient);
    258 				}
    259 			}
    260 		}
    261 	}
    262 	//
    263 	static inline btScalar	DistanceToShape(const btVector3& x,
    264 		const btCollisionShape* shape)
    265 	{
    266 		btTransform	unit;
    267 		unit.setIdentity();
    268 		if(shape->isConvex())
    269 		{
    270 			btGjkEpaSolver2::sResults	res;
    271 			const btConvexShape*				csh=static_cast<const btConvexShape*>(shape);
    272 			return(btGjkEpaSolver2::SignedDistance(x,0,csh,unit,res));
    273 		}
    274 		return(0);
    275 	}
    276 	//
    277 	static inline IntFrac	Decompose(btScalar x)
    278 	{
    279 		/* That one need a lot of improvements...	*/
    280 		/* Remove test, faster floor...				*/
    281 		IntFrac			r;
    282 		x/=CELLSIZE;
    283 		const int		o=x<0?(int)(-x+1):0;
    284 		x+=o;r.b=(int)x;
    285 		const btScalar	k=(x-r.b)*CELLSIZE;
    286 		r.i=(int)k;r.f=k-r.i;r.b-=o;
    287 		return(r);
    288 	}
    289 	//
    290 	static inline btScalar	Lerp(btScalar a,btScalar b,btScalar t)
    291 	{
    292 		return(a+(b-a)*t);
    293 	}
    294 
    295 
    296 
    297 	//
    298 	static inline unsigned int	Hash(int x,int y,int z,const btCollisionShape* shape)
    299 	{
    300 		struct btS
    301 		{
    302 			int x,y,z;
    303 			void* p;
    304 		};
    305 
    306 		btS myset;
    307 
    308 		myset.x=x;myset.y=y;myset.z=z;myset.p=(void*)shape;
    309 		const void* ptr = &myset;
    310 
    311 		unsigned int result = HsiehHash<sizeof(btS)/4> (ptr);
    312 
    313 
    314 		return result;
    315 	}
    316 };
    317 
    318 
    319 #endif //BT_SPARSE_SDF_H
    320