Files
bullet3/examples/OpenCL/rigidbody/GpuRigidBodyDemo.cpp

524 lines
14 KiB
C++

#include "GpuRigidBodyDemo.h"
#include "../OpenGLWindow/ShapeData.h"
#include "../OpenGLWindow/GLInstancingRenderer.h"
#include "Bullet3Common/b3Quaternion.h"
#include "../CommonInterfaces/CommonWindowInterface.h"
#include "Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h"
#include "Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h"
#include "../CommonOpenCL/GpuDemoInternalData.h"
#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h"
#include "../OpenGLWindow/OpenGLInclude.h"
#include "../OpenGLWindow/GLInstanceRendererInternalData.h"
#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h"
#include "Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h"
#include "Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.h"
#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h"
#include "GpuRigidBodyDemoInternalData.h"
#include "Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h"
#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h"
#include "Bullet3OpenCL/RigidBody/b3GpuNarrowPhaseInternalData.h"
#include "stb_image/stb_image.h"
#include "../OpenGLWindow/GLPrimitiveRenderer.h"
extern int gPreferredOpenCLDeviceIndex;
extern int gPreferredOpenCLPlatformIndex;
extern int gGpuArraySizeX;
extern int gGpuArraySizeY;
extern int gGpuArraySizeZ;
static b3KeyboardCallback oldCallback = 0;
extern bool gReset;
bool useUniformGrid = false;
bool convertOnCpu = false;
#define MSTRINGIFY(A) #A
static const char* s_rigidBodyKernelString = MSTRINGIFY(
typedef struct
{
float4 m_pos;
float4 m_quat;
float4 m_linVel;
float4 m_angVel;
unsigned int m_collidableIdx;
float m_invMass;
float m_restituitionCoeff;
float m_frictionCoeff;
} Body;
__kernel void
copyTransformsToVBOKernel( __global Body* gBodies, __global float4* posOrnColor, const int numNodes)
{
int nodeID = get_global_id(0);
if( nodeID < numNodes )
{
posOrnColor[nodeID] = (float4) (gBodies[nodeID].m_pos.xyz,1.0);
posOrnColor[nodeID + numNodes] = gBodies[nodeID].m_quat;
}
}
);
GpuRigidBodyDemo::GpuRigidBodyDemo(GUIHelperInterface* helper)
:CommonOpenCLBase(helper),
m_instancingRenderer(0),
m_window(0)
{
if (helper->getRenderInterface()->getInternalData())
{
m_instancingRenderer = (GLInstancingRenderer*)helper->getRenderInterface();
} else
{
m_instancingRenderer = 0;
}
m_window = helper->getAppInterface()->m_window;
m_data = new GpuRigidBodyDemoInternalData;
m_data->m_guiHelper = helper;
}
void GpuRigidBodyDemo::resetCamera()
{
float dist = 114;
float pitch = -35;
float yaw = 52;
float targetPos[3]={0,0,0};
m_data->m_guiHelper->resetCamera(dist,yaw,pitch,targetPos[0],targetPos[1],targetPos[2]);
}
GpuRigidBodyDemo::~GpuRigidBodyDemo()
{
delete m_data;
}
static void PairKeyboardCallback(int key, int state)
{
if (key=='R' && state)
{
//gReset = true;
}
//b3DefaultKeyboardCallback(key,state);
oldCallback(key,state);
}
void GpuRigidBodyDemo::setupScene()
{
}
void GpuRigidBodyDemo::initPhysics()
{
initCL(gPreferredOpenCLDeviceIndex,gPreferredOpenCLPlatformIndex);
m_guiHelper->setUpAxis(1);
if (m_clData->m_clContext)
{
int errNum=0;
cl_program rbProg=0;
m_data->m_copyTransformsToVBOKernel = b3OpenCLUtils::compileCLKernelFromString(m_clData->m_clContext,m_clData->m_clDevice,s_rigidBodyKernelString,"copyTransformsToVBOKernel",&errNum,rbProg);
m_data->m_config.m_maxConvexBodies = b3Max(m_data->m_config.m_maxConvexBodies,gGpuArraySizeX*gGpuArraySizeY*gGpuArraySizeZ+10);
m_data->m_config.m_maxConvexShapes = m_data->m_config.m_maxConvexBodies;
int maxPairsPerBody = 16;
m_data->m_config.m_maxBroadphasePairs = maxPairsPerBody*m_data->m_config.m_maxConvexBodies;
m_data->m_config.m_maxContactCapacity = m_data->m_config.m_maxBroadphasePairs;
b3GpuNarrowPhase* np = new b3GpuNarrowPhase(m_clData->m_clContext,m_clData->m_clDevice,m_clData->m_clQueue,m_data->m_config);
b3GpuBroadphaseInterface* bp =0;
if (useUniformGrid)
{
bp = new b3GpuGridBroadphase(m_clData->m_clContext,m_clData->m_clDevice,m_clData->m_clQueue);
} else
{
bp = new b3GpuSapBroadphase(m_clData->m_clContext,m_clData->m_clDevice,m_clData->m_clQueue);
}
m_data->m_np = np;
m_data->m_bp = bp;
m_data->m_broadphaseDbvt = new b3DynamicBvhBroadphase(m_data->m_config.m_maxConvexBodies);
m_data->m_rigidBodyPipeline = new b3GpuRigidBodyPipeline(m_clData->m_clContext,m_clData->m_clDevice,m_clData->m_clQueue, np, bp,m_data->m_broadphaseDbvt,m_data->m_config);
setupScene();
m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
np->writeAllBodiesToGpu();
bp->writeAabbsToGpu();
}
m_guiHelper->getRenderInterface()->writeTransforms();
}
void GpuRigidBodyDemo::exitPhysics()
{
destroyScene();
delete m_data->m_instancePosOrnColor;
delete m_data->m_rigidBodyPipeline;
delete m_data->m_broadphaseDbvt;
delete m_data->m_np;
m_data->m_np = 0;
delete m_data->m_bp;
m_data->m_bp = 0;
exitCL();
}
void GpuRigidBodyDemo::renderScene()
{
m_guiHelper->getRenderInterface()->renderScene();
}
void GpuRigidBodyDemo::stepSimulation(float deltaTime)
{
if (!m_instancingRenderer)
return;
bool animate=true;
int numObjects= m_data->m_rigidBodyPipeline->getNumBodies();
//printf("numObjects=%d\n",numObjects);
if (numObjects > m_instancingRenderer->getInstanceCapacity())
{
static bool once = true;
if (once)
{
once=false;
b3Assert(0);
b3Error("m_instancingRenderer out-of-memory\n");
}
numObjects = m_instancingRenderer->getInstanceCapacity();
}
GLint err = glGetError();
assert(err==GL_NO_ERROR);
b3Vector4* positions = 0;
if (animate && numObjects)
{
B3_PROFILE("gl2cl");
if (!m_data->m_instancePosOrnColor)
{
GLuint vbo = m_instancingRenderer->getInternalData()->m_vbo;
int arraySizeInBytes = numObjects * (3)*sizeof(b3Vector4);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// cl_bool blocking= CL_TRUE;
positions= (b3Vector4*)glMapBufferRange( GL_ARRAY_BUFFER,m_instancingRenderer->getMaxShapeCapacity(),arraySizeInBytes, GL_MAP_READ_BIT );//GL_READ_WRITE);//GL_WRITE_ONLY
GLint err = glGetError();
assert(err==GL_NO_ERROR);
m_data->m_instancePosOrnColor = new b3OpenCLArray<b3Vector4>(m_clData->m_clContext,m_clData->m_clQueue);
m_data->m_instancePosOrnColor->resize(3*numObjects);
m_data->m_instancePosOrnColor->copyFromHostPointer(positions,3*numObjects,0);
glUnmapBuffer( GL_ARRAY_BUFFER);
err = glGetError();
assert(err==GL_NO_ERROR);
}
}
{
B3_PROFILE("stepSimulation");
m_data->m_rigidBodyPipeline->stepSimulation(1./60.f);
}
if (numObjects)
{
if (convertOnCpu)
{
b3GpuNarrowPhaseInternalData* npData = m_data->m_np->getInternalData();
npData->m_bodyBufferGPU->copyToHost(*npData->m_bodyBufferCPU);
b3AlignedObjectArray<b3Vector4> vboCPU;
m_data->m_instancePosOrnColor->copyToHost(vboCPU);
for (int i=0;i<numObjects;i++)
{
b3Vector4 pos = (const b3Vector4&)npData->m_bodyBufferCPU->at(i).m_pos;
b3Quat orn = npData->m_bodyBufferCPU->at(i).m_quat;
pos.w = 1.f;
vboCPU[i] = pos;
vboCPU[i + numObjects] = (b3Vector4&)orn;
}
m_data->m_instancePosOrnColor->copyFromHost(vboCPU);
} else
{
B3_PROFILE("cl2gl_convert");
int ciErrNum = 0;
cl_mem bodies = m_data->m_rigidBodyPipeline->getBodyBuffer();
b3LauncherCL launch(m_clData->m_clQueue,m_data->m_copyTransformsToVBOKernel,"m_copyTransformsToVBOKernel");
launch.setBuffer(bodies);
launch.setBuffer(m_data->m_instancePosOrnColor->getBufferCL());
launch.setConst(numObjects);
launch.launch1D(numObjects);
oclCHECKERROR(ciErrNum, CL_SUCCESS);
}
}
if (animate && numObjects)
{
B3_PROFILE("cl2gl_upload");
GLint err = glGetError();
assert(err==GL_NO_ERROR);
GLuint vbo = m_instancingRenderer->getInternalData()->m_vbo;
int arraySizeInBytes = numObjects * (3)*sizeof(b3Vector4);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// cl_bool blocking= CL_TRUE;
positions= (b3Vector4*)glMapBufferRange( GL_ARRAY_BUFFER,m_instancingRenderer->getMaxShapeCapacity(),arraySizeInBytes, GL_MAP_WRITE_BIT );//GL_READ_WRITE);//GL_WRITE_ONLY
err = glGetError();
assert(err==GL_NO_ERROR);
m_data->m_instancePosOrnColor->copyToHostPointer(positions,3*numObjects,0);
glUnmapBuffer( GL_ARRAY_BUFFER);
err = glGetError();
assert(err==GL_NO_ERROR);
}
}
b3Vector3 GpuRigidBodyDemo::getRayTo(int x,int y)
{
if (!m_instancingRenderer)
return b3MakeVector3(0,0,0);
float top = 1.f;
float bottom = -1.f;
float nearPlane = 1.f;
float tanFov = (top-bottom)*0.5f / nearPlane;
float fov = b3Scalar(2.0) * b3Atan(tanFov);
b3Vector3 camPos,camTarget;
m_instancingRenderer->getActiveCamera()->getCameraPosition(camPos);
m_instancingRenderer->getActiveCamera()->getCameraTargetPosition(camTarget);
b3Vector3 rayFrom = camPos;
b3Vector3 rayForward = (camTarget-camPos);
rayForward.normalize();
float farPlane = 10000.f;
rayForward*= farPlane;
// b3Vector3 rightOffset;
b3Vector3 m_cameraUp=b3MakeVector3(0,1,0);
b3Vector3 vertical = m_cameraUp;
b3Vector3 hor;
hor = rayForward.cross(vertical);
hor.normalize();
vertical = hor.cross(rayForward);
vertical.normalize();
float tanfov = tanf(0.5f*fov);
hor *= 2.f * farPlane * tanfov;
vertical *= 2.f * farPlane * tanfov;
b3Scalar aspect;
float width = m_instancingRenderer->getScreenWidth();
float height = m_instancingRenderer->getScreenHeight();
aspect = width / height;
hor*=aspect;
b3Vector3 rayToCenter = rayFrom + rayForward;
b3Vector3 dHor = hor * 1.f/width;
b3Vector3 dVert = vertical * 1.f/height;
b3Vector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
rayTo += b3Scalar(x) * dHor;
rayTo -= b3Scalar(y) * dVert;
return rayTo;
}
unsigned char* GpuRigidBodyDemo::loadImage(const char* fileName, int& width, int& height, int& n)
{
unsigned char *data = stbi_load(fileName, &width, &height, &n, 3);
return data;
}
bool GpuRigidBodyDemo::keyboardCallback(int key, int state)
{
if (m_data)
{
if (key==B3G_ALT )
{
m_data->m_altPressed = state;
}
if (key==B3G_CONTROL )
{
m_data->m_controlPressed = state;
}
}
return false;
}
bool GpuRigidBodyDemo::mouseMoveCallback(float x,float y)
{
if (!m_instancingRenderer)
return false;
if (m_data->m_altPressed!=0 || m_data->m_controlPressed!=0)
return false;
if (m_data->m_pickBody>=0 && m_data->m_pickConstraint>=0)
{
m_data->m_rigidBodyPipeline->removeConstraintByUid(m_data->m_pickConstraint);
b3Vector3 newRayTo = getRayTo(x,y);
b3Vector3 rayFrom;
// b3Vector3 oldPivotInB = m_data->m_pickPivotInB;
b3Vector3 newPivotB;
m_guiHelper->getRenderInterface()->getActiveCamera()->getCameraPosition(rayFrom);
b3Vector3 dir = newRayTo-rayFrom;
dir.normalize();
dir *= m_data->m_pickDistance;
newPivotB = rayFrom + dir;
m_data->m_pickPivotInB = newPivotB;
m_data->m_rigidBodyPipeline->copyConstraintsToHost();
m_data->m_pickConstraint = m_data->m_rigidBodyPipeline->createPoint2PointConstraint(m_data->m_pickBody,m_data->m_pickFixedBody,m_data->m_pickPivotInA,m_data->m_pickPivotInB,1e30);
m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
return true;
}
return false;
}
bool GpuRigidBodyDemo::mouseButtonCallback(int button, int state, float x, float y)
{
if (!m_instancingRenderer)
return false;
if (state==1)
{
if(button==0 && (m_data->m_altPressed==0 && m_data->m_controlPressed==0))
{
b3AlignedObjectArray<b3RayInfo> rays;
b3AlignedObjectArray<b3RayHit> hitResults;
b3Vector3 camPos;
m_guiHelper->getRenderInterface()->getActiveCamera()->getCameraPosition(camPos);
b3RayInfo ray;
ray.m_from = camPos;
ray.m_to = getRayTo(x,y);
rays.push_back(ray);
b3RayHit hit;
hit.m_hitFraction = 1.f;
hitResults.push_back(hit);
m_data->m_rigidBodyPipeline->castRays(rays,hitResults);
if (hitResults[0].m_hitFraction<1.f)
{
int hitBodyA = hitResults[0].m_hitBody;
if (m_data->m_np->getBodiesCpu()[hitBodyA].m_invMass)
{
//printf("hit!\n");
m_data->m_np->readbackAllBodiesToCpu();
m_data->m_pickBody = hitBodyA;
//pivotInA
b3Vector3 pivotInB;
pivotInB.setInterpolate3(ray.m_from,ray.m_to,hitResults[0].m_hitFraction);
b3Vector3 posA;
b3Quaternion ornA;
m_data->m_np->getObjectTransformFromCpu(posA,ornA,hitBodyA);
b3Transform tr;
tr.setOrigin(posA);
tr.setRotation(ornA);
b3Vector3 pivotInA = tr.inverse()*pivotInB;
if (m_data->m_pickFixedBody<0)
{
b3Vector3 pos=b3MakeVector3(0,0,0);
b3Quaternion orn(0,0,0,1);
int fixedSphere = m_data->m_np->registerConvexHullShape(0,0,0,0);//>registerSphereShape(0.1);
m_data->m_pickFixedBody = m_data->m_rigidBodyPipeline->registerPhysicsInstance(0,pos,orn,fixedSphere,0,false);
m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
m_data->m_bp->writeAabbsToGpu();
if (m_data->m_pickGraphicsShapeIndex<0)
{
int strideInBytes = 9*sizeof(float);
int numVertices = sizeof(point_sphere_vertices)/strideInBytes;
int numIndices = sizeof(point_sphere_indices)/sizeof(int);
m_data->m_pickGraphicsShapeIndex = m_guiHelper->getRenderInterface()->registerShape(&point_sphere_vertices[0],numVertices,point_sphere_indices,numIndices,B3_GL_POINTS);
float color[4] ={1,0,0,1};
float scaling[4]={1,1,1,1};
m_data->m_pickGraphicsShapeInstance = m_guiHelper->getRenderInterface()->registerGraphicsInstance(m_data->m_pickGraphicsShapeIndex,pivotInB,orn,color,scaling);
m_guiHelper->getRenderInterface()->writeTransforms();
delete m_data->m_instancePosOrnColor;
m_data->m_instancePosOrnColor=0;
} else
{
m_guiHelper->getRenderInterface()->writeSingleInstanceTransformToCPU(pivotInB,orn,m_data->m_pickGraphicsShapeInstance);
if (this->m_instancingRenderer)
m_instancingRenderer->writeSingleInstanceTransformToGPU(pivotInB,orn,m_data->m_pickGraphicsShapeInstance);
m_data->m_np->setObjectTransformCpu(pos,orn,m_data->m_pickFixedBody);
}
}
pivotInB.w = 0.f;
m_data->m_pickPivotInA = pivotInA;
m_data->m_pickPivotInB = pivotInB;
m_data->m_rigidBodyPipeline->copyConstraintsToHost();
m_data->m_pickConstraint = m_data->m_rigidBodyPipeline->createPoint2PointConstraint(hitBodyA,m_data->m_pickFixedBody,pivotInA,pivotInB,1e30);//hitResults[0].m_hitResult0
m_data->m_rigidBodyPipeline->writeAllInstancesToGpu();
m_data->m_np->writeAllBodiesToGpu();
m_data->m_pickDistance = (pivotInB-camPos).length();
return true;
}
}
}
} else
{
if (button==0)
{
if (m_data->m_pickConstraint>=0)
{
m_data->m_rigidBodyPipeline->removeConstraintByUid(m_data->m_pickConstraint);
m_data->m_pickConstraint=-1;
}
}
}
//printf("button=%d, state=%d\n",button,state);
return false;
}