1 #include "GpuConvexScene.h"
2 
3 #include "GpuRigidBodyDemo.h"
4 #include "../OpenGLWindow/ShapeData.h"
5 
6 #include "../OpenGLWindow/GLInstancingRenderer.h"
7 #include "Bullet3Common/b3Quaternion.h"
8 #include "../CommonInterfaces/CommonWindowInterface.h"
9 #include "Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h"
10 #include "../CommonOpenCL/GpuDemoInternalData.h"
11 #include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h"
12 #include "../OpenGLWindow/OpenGLInclude.h"
13 #include "../OpenGLWindow/GLInstanceRendererInternalData.h"
14 #include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h"
15 #include "Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h"
16 #include "Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.h"
17 #include "Bullet3Collision/NarrowPhaseCollision/b3Config.h"
18 #include "GpuRigidBodyDemoInternalData.h"
19 
20 #include "Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h"
21 #include "../OpenGLWindow/GLPrimitiveRenderer.h"
22 #include "Bullet3OpenCL/Raycast/b3GpuRaycast.h"
23 #include "Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.h"
24 #include "Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.h"
25 
26 #include "../OpenGLWindow/GLRenderToTexture.h"
27 
28 static bool gUseInstancedCollisionShapes = true;
29 extern int gGpuArraySizeX;
30 extern int gGpuArraySizeY;
31 extern int gGpuArraySizeZ;
32 
33 #include "GpuRigidBodyDemo.h"
34 #include "Bullet3Common/b3AlignedObjectArray.h"
35 #include "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h"
36 
37 class GpuConvexScene : public GpuRigidBodyDemo
38 {
39 protected:
40 	class b3GpuRaycast* m_raycaster;
41 
42 public:
GpuConvexScene(GUIHelperInterface * helper)43 	GpuConvexScene(GUIHelperInterface* helper)
44 		: GpuRigidBodyDemo(helper), m_raycaster(0)
45 	{
46 	}
~GpuConvexScene()47 	virtual ~GpuConvexScene() {}
getName()48 	virtual const char* getName()
49 	{
50 		return "Tetrahedra";
51 	}
52 
53 	virtual void setupScene();
54 
55 	virtual void destroyScene();
56 
57 	virtual int createDynamicsObjects();
58 
59 	virtual int createDynamicsObjects2(const float* vertices, int numVertices, const int* indices, int numIndices);
60 
61 	virtual void createStaticEnvironment();
62 };
63 
64 class GpuConvexPlaneScene : public GpuConvexScene
65 {
66 public:
GpuConvexPlaneScene(GUIHelperInterface * helper)67 	GpuConvexPlaneScene(GUIHelperInterface* helper)
68 		: GpuConvexScene(helper) {}
~GpuConvexPlaneScene()69 	virtual ~GpuConvexPlaneScene() {}
getName()70 	virtual const char* getName()
71 	{
72 		return "ConvexOnPlane";
73 	}
74 
75 	virtual void createStaticEnvironment();
76 };
77 
78 class GpuBoxPlaneScene : public GpuConvexPlaneScene
79 {
80 public:
GpuBoxPlaneScene(GUIHelperInterface * helper)81 	GpuBoxPlaneScene(GUIHelperInterface* helper) : GpuConvexPlaneScene(helper) {}
~GpuBoxPlaneScene()82 	virtual ~GpuBoxPlaneScene() {}
getName()83 	virtual const char* getName()
84 	{
85 		return "BoxBox";
86 	}
87 
88 	virtual int createDynamicsObjects();
89 };
90 
91 class GpuTetraScene : public GpuConvexScene
92 {
93 protected:
94 	void createFromTetGenData(const char* ele, const char* node);
95 
96 public:
getName()97 	virtual const char* getName()
98 	{
99 		return "TetraBreakable";
100 	}
101 
102 	virtual int createDynamicsObjects();
103 };
104 
105 b3Vector4 colors[4] =
106 	{
107 		b3MakeVector4(1, 0, 0, 1),
108 		b3MakeVector4(0, 1, 0, 1),
109 		b3MakeVector4(0, 1, 1, 1),
110 		b3MakeVector4(1, 1, 0, 1),
111 };
112 
setupScene()113 void GpuConvexScene::setupScene()
114 {
115 	m_raycaster = new b3GpuRaycast(m_clData->m_clContext, m_clData->m_clDevice, m_clData->m_clQueue);
116 
117 	int index = 0;
118 	createStaticEnvironment();
119 
120 	index += createDynamicsObjects();
121 
122 	m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
123 
124 	float camPos[4] = {0, 0, 0, 0};  //ci.arraySizeX,ci.arraySizeY/2,ci.arraySizeZ,0};
125 	//float camPos[4]={1,12.5,1.5,0};
126 
127 	m_guiHelper->getRenderInterface()->getActiveCamera()->setCameraTargetPosition(camPos[0], camPos[1], camPos[2]);
128 	m_guiHelper->getRenderInterface()->getActiveCamera()->setCameraDistance(150);
129 	//m_instancingRenderer->setCameraYaw(85);
130 	m_guiHelper->getRenderInterface()->getActiveCamera()->setCameraYaw(225);
131 	m_guiHelper->getRenderInterface()->getActiveCamera()->setCameraPitch(-30);
132 
133 	m_guiHelper->getRenderInterface()->updateCamera(1);  //>updateCamera();
134 
135 	char msg[1024];
136 	int numInstances = index;
137 	sprintf(msg, "Num objects = %d", numInstances);
138 	b3Printf(msg);
139 
140 	//if (ci.m_gui)
141 	//	ci.m_gui->setStatusBarMessage(msg,true);
142 }
143 
destroyScene()144 void GpuConvexScene::destroyScene()
145 {
146 	delete m_raycaster;
147 	m_raycaster = 0;
148 }
149 
createDynamicsObjects()150 int GpuConvexScene::createDynamicsObjects()
151 {
152 	int strideInBytes = 9 * sizeof(float);
153 	/*int numVertices = sizeof(barrel_vertices)/strideInBytes;
154 	int numIndices = sizeof(barrel_indices)/sizeof(int);
155 	return createDynamicsObjects2(ci,barrel_vertices,numVertices,barrel_indices,numIndices);
156 	*/
157 
158 	int numVertices = sizeof(tetra_vertices) / strideInBytes;
159 	int numIndices = sizeof(tetra_indices) / sizeof(int);
160 	return createDynamicsObjects2(tetra_vertices, numVertices, tetra_indices, numIndices);
161 }
162 
createDynamicsObjects()163 int GpuBoxPlaneScene::createDynamicsObjects()
164 {
165 	int strideInBytes = 9 * sizeof(float);
166 	int numVertices = sizeof(cube_vertices) / strideInBytes;
167 	int numIndices = sizeof(cube_indices) / sizeof(int);
168 	return createDynamicsObjects2(cube_vertices_textured, numVertices, cube_indices, numIndices);
169 }
170 
createDynamicsObjects2(const float * vertices,int numVertices,const int * indices,int numIndices)171 int GpuConvexScene::createDynamicsObjects2(const float* vertices, int numVertices, const int* indices, int numIndices)
172 {
173 	int strideInBytes = 9 * sizeof(float);
174 	int textureIndex = -1;
175 	if (0)
176 	{
177 		int width, height, n;
178 
179 		const char* filename = "data/cube.png";
180 		const unsigned char* image = 0;
181 
182 		const char* prefix[] = {"./", "../", "../../", "../../../", "../../../../"};
183 		int numprefix = sizeof(prefix) / sizeof(const char*);
184 
185 		for (int i = 0; !image && i < numprefix; i++)
186 		{
187 			char relativeFileName[1024];
188 			sprintf(relativeFileName, "%s%s", prefix[i], filename);
189 			image = loadImage(relativeFileName, width, height, n);
190 		}
191 
192 		b3Assert(image);
193 		if (image)
194 		{
195 			textureIndex = m_instancingRenderer->registerTexture(image, width, height);
196 		}
197 	}
198 
199 	int shapeId = m_guiHelper->getRenderInterface()->registerShape(&vertices[0], numVertices, indices, numIndices, B3_GL_TRIANGLES, textureIndex);
200 	//int group=1;
201 	//int mask=1;
202 	int index = 0;
203 
204 	{
205 		int curColor = 0;
206 		float scaling[4] = {1, 1, 1, 1};
207 		int prevBody = -1;
208 		//int insta = 0;
209 
210 		b3ConvexUtility* utilPtr = new b3ConvexUtility();
211 
212 		{
213 			b3AlignedObjectArray<b3Vector3> verts;
214 
215 			unsigned char* vts = (unsigned char*)vertices;
216 			for (int i = 0; i < numVertices; i++)
217 			{
218 				float* vertex = (float*)&vts[i * strideInBytes];
219 				verts.push_back(b3MakeVector3(vertex[0] * scaling[0], vertex[1] * scaling[1], vertex[2] * scaling[2]));
220 			}
221 
222 			bool merge = true;
223 			if (numVertices)
224 			{
225 				utilPtr->initializePolyhedralFeatures(&verts[0], verts.size(), merge);
226 			}
227 		}
228 
229 		int colIndex = -1;
230 		if (gUseInstancedCollisionShapes)
231 			colIndex = m_data->m_np->registerConvexHullShape(utilPtr);
232 
233 		//int colIndex = m_data->m_np->registerSphereShape(1);
234 		for (int i = 0; i < gGpuArraySizeX; i++)
235 		{
236 			//printf("%d of %d\n", i, ci.arraySizeX);
237 			for (int j = 0; j < gGpuArraySizeY; j++)
238 			{
239 				for (int k = 0; k < gGpuArraySizeZ; k++)
240 				{
241 					//int colIndex = m_data->m_np->registerConvexHullShape(&vertices[0],strideInBytes,numVertices, scaling);
242 					if (!gUseInstancedCollisionShapes)
243 						colIndex = m_data->m_np->registerConvexHullShape(utilPtr);
244 
245 					float mass = 1.f;
246 					if (j == 0)  //ci.arraySizeY-1)
247 					{
248 						//mass=0.f;
249 					}
250 					b3Vector3 position = b3MakeVector3(((j + 1) & 1) + i * 2.2, 1 + j * 2., ((j + 1) & 1) + k * 2.2);
251 					//b3Vector3 position = b3MakeVector3(i*2,1+j*2,k*2);
252 					//b3Vector3 position=b3MakeVector3(1,0.9,1);
253 					b3Quaternion orn(0, 0, 0, 1);
254 
255 					b3Vector4 color = colors[curColor];
256 					curColor++;
257 					curColor &= 3;
258 					//					b3Vector4 scaling=b3MakeVector4(1,1,1,1);
259 					int id;
260 					id = m_guiHelper->getRenderInterface()->registerGraphicsInstance(shapeId, position, orn, color, scaling);
261 					int pid;
262 					pid = m_data->m_rigidBodyPipeline->registerPhysicsInstance(mass, position, orn, colIndex, index, false);
263 
264 					if (prevBody >= 0)
265 					{
266 						//b3Point2PointConstraint* p2p = new b3Point2PointConstraint(pid,prevBody,b3Vector3(0,-1.1,0),b3Vector3(0,1.1,0));
267 						//						 m_data->m_rigidBodyPipeline->addConstraint(p2p);//,false);
268 					}
269 					prevBody = pid;
270 
271 					index++;
272 				}
273 			}
274 		}
275 		delete utilPtr;
276 	}
277 	return index;
278 }
279 
createStaticEnvironment()280 void GpuConvexScene::createStaticEnvironment()
281 {
282 	int strideInBytes = 9 * sizeof(float);
283 	int numVertices = sizeof(cube_vertices) / strideInBytes;
284 	int numIndices = sizeof(cube_indices) / sizeof(int);
285 	//int shapeId = ci.m_instancingRenderer->registerShape(&cube_vertices[0],numVertices,cube_indices,numIndices);
286 	int shapeId = m_instancingRenderer->registerShape(&cube_vertices[0], numVertices, cube_indices, numIndices);
287 	//int group=1;
288 	//int mask=1;
289 	int index = 0;
290 
291 	{
292 		b3Vector4 scaling = b3MakeVector4(400, 400, 400, 1);
293 		int colIndex = m_data->m_np->registerConvexHullShape(&cube_vertices[0], strideInBytes, numVertices, scaling);
294 		b3Vector3 position = b3MakeVector3(0, -400, 0);
295 		b3Quaternion orn(0, 0, 0, 1);
296 
297 		b3Vector4 color = b3MakeVector4(0, 0, 1, 1);
298 
299 		int id;
300 		id = m_instancingRenderer->registerGraphicsInstance(shapeId, position, orn, color, scaling);
301 		int pid;
302 		pid = m_data->m_rigidBodyPipeline->registerPhysicsInstance(0.f, position, orn, colIndex, index, false);
303 	}
304 }
305 
createStaticEnvironment()306 void GpuConvexPlaneScene::createStaticEnvironment()
307 {
308 	int strideInBytes = 9 * sizeof(float);
309 	int numVertices = sizeof(cube_vertices) / strideInBytes;
310 	int numIndices = sizeof(cube_indices) / sizeof(int);
311 	//int shapeId = ci.m_instancingRenderer->registerShape(&cube_vertices[0],numVertices,cube_indices,numIndices);
312 	int shapeId = m_guiHelper->getRenderInterface()->registerShape(&cube_vertices[0], numVertices, cube_indices, numIndices);
313 	//	int group=1;
314 	//	int mask=1;
315 	int index = 0;
316 
317 	{
318 		b3Vector4 scaling = b3MakeVector4(400, 400, 400, 1);
319 		int colIndex = m_data->m_np->registerConvexHullShape(&cube_vertices[0], strideInBytes, numVertices, scaling);
320 		b3Vector3 position = b3MakeVector3(0, -400, 0);
321 		b3Quaternion orn(0, 0, 0, 1);
322 
323 		b3Vector4 color = b3MakeVector4(0, 0, 1, 1);
324 
325 		int id;
326 		id = m_guiHelper->getRenderInterface()->registerGraphicsInstance(shapeId, position, orn, color, scaling);
327 		int pid;
328 		pid = m_data->m_rigidBodyPipeline->registerPhysicsInstance(0.f, position, orn, colIndex, index, false);
329 	}
330 }
331 
332 /*
333 void GpuConvexPlaneScene::createStaticEnvironment(const ConstructionInfo& ci)
334 {
335 	int strideInBytes = 9*sizeof(float);
336 	int numVertices = sizeof(cube_vertices)/strideInBytes;
337 	int numIndices = sizeof(cube_indices)/sizeof(int);
338 	//int shapeId = ci.m_instancingRenderer->registerShape(&cube_vertices[0],numVertices,cube_indices,numIndices);
339 	int shapeId = ci.m_instancingRenderer->registerShape(&cube_vertices[0],numVertices,cube_indices,numIndices);
340 	int group=1;
341 	int mask=1;
342 	int index=0;
343 
344 
345 	{
346 		b3Vector4 scaling=b3MakeVector4(100,0.001,100,1);
347 
348 
349 		//int colIndex = m_data->m_np->registerConvexHullShape(&cube_vertices[0],strideInBytes,numVertices, scaling);
350 		b3Vector3 normal=b3MakeVector3(0,1,0);
351 		float constant=0.f;
352 		int colIndex = m_data->m_np->registerPlaneShape(normal,constant);//>registerConvexHullShape(&cube_vertices[0],strideInBytes,numVertices, scaling);
353 		b3Vector3 position=b3MakeVector3(0,0,0);
354 
355 
356 
357 		b3Quaternion orn(0,0,0,1);
358 
359 		b3Vector4 color=b3MakeVector4(0,0,1,1);
360 
361 		int id = ci.m_instancingRenderer->registerGraphicsInstance(shapeId,position,orn,color,scaling);
362 		int pid = m_data->m_rigidBodyPipeline->registerPhysicsInstance(0.f,position,orn,colIndex,index,false);
363 
364 	}
365 
366 }
367 */
368 
369 struct TetraBunny
370 {
371 #include "bunny.inl"
372 };
373 
374 struct TetraCube
375 {
376 #include "cube.inl"
377 };
378 
nextLine(const char * buffer)379 static int nextLine(const char* buffer)
380 {
381 	int numBytesRead = 0;
382 
383 	while (*buffer != '\n')
384 	{
385 		buffer++;
386 		numBytesRead++;
387 	}
388 
389 	if (buffer[0] == 0x0a)
390 	{
391 		buffer++;
392 		numBytesRead++;
393 	}
394 	return numBytesRead;
395 }
396 
397 static float mytetra_vertices[] =
398 	{
399 		-1.f, 0, -1.f, 0.5f, 0, 1, 0, 0, 0,
400 		-1.f, 0, 1.f, 0.5f, 0, 1, 0, 1, 0,
401 		1.f, 0, 1.f, 0.5f, 0, 1, 0, 1, 1,
402 		1.f, 0, -1.f, 0.5f, 0, 1, 0, 0, 1};
403 
404 static int mytetra_indices[] =
405 	{
406 		0, 1, 2,
407 		3, 1, 2, 3, 2, 0,
408 		3, 0, 1};
409 
410 /* Create from TetGen .ele, .face, .node data */
createFromTetGenData(const char * ele,const char * node)411 void GpuTetraScene::createFromTetGenData(const char* ele,
412 										 const char* node)
413 {
414 	b3Scalar scaling(10);
415 
416 	b3AlignedObjectArray<b3Vector3> pos;
417 	int nnode = 0;
418 	int ndims = 0;
419 	int nattrb = 0;
420 	int hasbounds = 0;
421 	int result = sscanf(node, "%d %d %d %d", &nnode, &ndims, &nattrb, &hasbounds);
422 	result = sscanf(node, "%d %d %d %d", &nnode, &ndims, &nattrb, &hasbounds);
423 	node += nextLine(node);
424 
425 	//b3AlignedObjectArray<b3Vector3> rigidBodyPositions;
426 	//b3AlignedObjectArray<int> rigidBodyIds;
427 
428 	pos.resize(nnode);
429 	for (int i = 0; i < pos.size(); ++i)
430 	{
431 		int index = 0;
432 		//int			bound=0;
433 		float x, y, z;
434 		sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
435 
436 		//	sn>>index;
437 		//	sn>>x;sn>>y;sn>>z;
438 		node += nextLine(node);
439 
440 		//for(int j=0;j<nattrb;++j)
441 		//	sn>>a;
442 
443 		//if(hasbounds)
444 		//	sn>>bound;
445 
446 		pos[index].setX(b3Scalar(x) * scaling);
447 		pos[index].setY(b3Scalar(y) * scaling);
448 		pos[index].setZ(b3Scalar(z) * scaling);
449 	}
450 
451 	if (ele && ele[0])
452 	{
453 		int ntetra = 0;
454 		int ncorner = 0;
455 		int neattrb = 0;
456 		sscanf(ele, "%d %d %d", &ntetra, &ncorner, &neattrb);
457 		ele += nextLine(ele);
458 
459 		//se>>ntetra;se>>ncorner;se>>neattrb;
460 		for (int i = 0; i < ntetra; ++i)
461 		{
462 			int index = 0;
463 			int ni[4];
464 
465 			//se>>index;
466 			//se>>ni[0];se>>ni[1];se>>ni[2];se>>ni[3];
467 			sscanf(ele, "%d %d %d %d %d", &index, &ni[0], &ni[1], &ni[2], &ni[3]);
468 			ele += nextLine(ele);
469 
470 			b3Vector3 average = b3MakeVector3(0, 0, 0);
471 
472 			for (int v = 0; v < 4; v++)
473 			{
474 				average += pos[ni[v]];
475 			}
476 			average /= 4;
477 
478 			for (int v = 0; v < 4; v++)
479 			{
480 				b3Vector3 shiftedPos = pos[ni[v]] - average;
481 				mytetra_vertices[0 + v * 9] = shiftedPos.getX();
482 				mytetra_vertices[1 + v * 9] = shiftedPos.getY();
483 				mytetra_vertices[2 + v * 9] = shiftedPos.getZ();
484 			}
485 			//todo: subtract average
486 
487 			int strideInBytes = 9 * sizeof(float);
488 			int numVertices = sizeof(mytetra_vertices) / strideInBytes;
489 			int numIndices = sizeof(mytetra_indices) / sizeof(int);
490 			int shapeId = m_instancingRenderer->registerShape(&mytetra_vertices[0], numVertices, mytetra_indices, numIndices);
491 			//	int group=1;
492 			//	int mask=1;
493 
494 			{
495 				b3Vector4 scaling = b3MakeVector4(1, 1, 1, 1);
496 				int colIndex = m_data->m_np->registerConvexHullShape(&mytetra_vertices[0], strideInBytes, numVertices, scaling);
497 				b3Vector3 position = b3MakeVector3(0, 150, 0);
498 				//				position+=average;//*1.2;//*2;
499 				position += average * 1.2;  //*2;
500 				//rigidBodyPositions.push_back(position);
501 				b3Quaternion orn(0, 0, 0, 1);
502 
503 				static int curColor = 0;
504 				b3Vector4 color = colors[curColor++];
505 				curColor &= 3;
506 
507 				int id;
508 				id = m_instancingRenderer->registerGraphicsInstance(shapeId, position, orn, color, scaling);
509 				int pid;
510 				pid = m_data->m_rigidBodyPipeline->registerPhysicsInstance(1.f, position, orn, colIndex, 0, false);
511 				//rigidBodyIds.push_back(pid);
512 			}
513 
514 			//for(int j=0;j<neattrb;++j)
515 			//	se>>a;
516 			//psb->appendTetra(ni[0],ni[1],ni[2],ni[3]);
517 		}
518 		//	printf("Nodes:  %u\r\n",psb->m_nodes.size());
519 		//	printf("Links:  %u\r\n",psb->m_links.size());
520 		//	printf("Faces:  %u\r\n",psb->m_faces.size());
521 		//	printf("Tetras: %u\r\n",psb->m_tetras.size());
522 	}
523 
524 	m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
525 	m_data->m_np->writeAllBodiesToGpu();
526 	m_data->m_bp->writeAabbsToGpu();
527 	m_data->m_rigidBodyPipeline->setupGpuAabbsFull();
528 	m_data->m_bp->calculateOverlappingPairs(m_data->m_config.m_maxBroadphasePairs);
529 
530 	int numPairs = m_data->m_bp->getNumOverlap();
531 	cl_mem pairs = m_data->m_bp->getOverlappingPairBuffer();
532 	b3OpenCLArray<b3Int2> clPairs(m_clData->m_clContext, m_clData->m_clQueue);
533 	clPairs.setFromOpenCLBuffer(pairs, numPairs);
534 	b3AlignedObjectArray<b3Int2> allPairs;
535 	clPairs.copyToHost(allPairs);
536 
537 	for (int p = 0; p < allPairs.size(); p++)
538 	{
539 		b3Vector3 posA, posB;
540 		b3Quaternion ornA, ornB;
541 		int bodyIndexA = allPairs[p].x;
542 		int bodyIndexB = allPairs[p].y;
543 
544 		m_data->m_np->getObjectTransformFromCpu(posA, ornA, bodyIndexA);
545 		m_data->m_np->getObjectTransformFromCpu(posB, ornB, bodyIndexB);
546 
547 		b3Vector3 pivotWorld = (posA + posB) * 0.5f;
548 		b3Transform transA, transB;
549 		transA.setIdentity();
550 		transA.setOrigin(posA);
551 		transA.setRotation(ornA);
552 		transB.setIdentity();
553 		transB.setOrigin(posB);
554 		transB.setRotation(ornB);
555 		b3Vector3 pivotInA = transA.inverse() * pivotWorld;
556 		b3Vector3 pivotInB = transB.inverse() * pivotWorld;
557 
558 		b3Transform frameInA, frameInB;
559 		frameInA.setIdentity();
560 		frameInB.setIdentity();
561 		frameInA.setOrigin(pivotInA);
562 		frameInB.setOrigin(pivotInB);
563 		b3Quaternion relTargetAB = frameInA.getRotation() * frameInB.getRotation().inverse();
564 
565 		//c = new b3FixedConstraint(pid,prevBody,frameInA,frameInB);
566 		float breakingThreshold = 45;  //37.f;
567 		//c->setBreakingImpulseThreshold(37.1);
568 		bool useGPU = true;
569 		if (useGPU)
570 		{
571 			int cid;
572 			cid = m_data->m_rigidBodyPipeline->createFixedConstraint(bodyIndexA, bodyIndexB, pivotInA, pivotInB, relTargetAB, breakingThreshold);
573 		}
574 		else
575 		{
576 			b3FixedConstraint* c = new b3FixedConstraint(bodyIndexA, bodyIndexB, frameInA, frameInB);
577 			c->setBreakingImpulseThreshold(breakingThreshold);
578 			m_data->m_rigidBodyPipeline->addConstraint(c);
579 		}
580 	}
581 
582 	printf("numPairs = %d\n", numPairs);
583 }
584 
createDynamicsObjects()585 int GpuTetraScene::createDynamicsObjects()
586 {
587 	//createFromTetGenData(TetraCube::getElements(),TetraCube::getNodes());
588 	createFromTetGenData(TetraBunny::getElements(), TetraBunny::getNodes());
589 
590 	return 0;
591 }
592 
OpenCLBoxBoxCreateFunc(struct CommonExampleOptions & options)593 class CommonExampleInterface* OpenCLBoxBoxCreateFunc(struct CommonExampleOptions& options)
594 {
595 	return new GpuBoxPlaneScene(options.m_guiHelper);
596 }
597