#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(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 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 rays; b3AlignedObjectArray 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; }