/* * Copyright 1993-2006 NVIDIA Corporation. All rights reserved. * * NOTICE TO USER: * * This source code is subject to NVIDIA ownership rights under U.S. and * international Copyright laws. * * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE * OR PERFORMANCE OF THIS SOURCE CODE. * * U.S. Government End Users. This source code is a "commercial item" as * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of * "commercial computer software" and "commercial computer software * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) * and is provided to the U.S. Government only as a commercial end item. * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the * source code with only those rights set forth herein. */ #include "particleSystem.h" #include "particleSystem.cuh" #include "radixsort.cuh" #include "particles_kernel.cuh" //#include #include #include #include #include #include #include #include #include #include "../../Demos/OpenGL/GLDebugDrawer.h" #include "btCudaBroadphase.h" #ifndef CUDART_PI_F #define CUDART_PI_F 3.141592654f #endif #define USE_BULLET 1 #define VEL_DIR_FACT (30.0F) #define ACC_DIR_FACT (VEL_DIR_FACT*VEL_DIR_FACT) #define VEL_INV_FACT (1.0F/VEL_DIR_FACT) #define ACC_INV_FACT (1.0F/ACC_DIR_FACT) GLDebugDrawer debugDrawer; ParticleSystem::ParticleSystem(uint numParticles, uint3 gridSize) : m_bInitialized(false), m_numParticles(numParticles), m_hPos(0), m_hVel(0), m_currentPosRead(0), m_currentVelRead(0), m_currentPosWrite(1), m_currentVelWrite(1), m_gridSize(gridSize), m_maxParticlesPerCell(4), m_timer(0), m_solverIterations(1), // m_simulationMode(SIMULATION_CUDA) m_simulationMode(SIMULATION_BULLET_CPU) { m_dPos[0] = m_dPos[1] = 0; m_dVel[0] = m_dVel[1] = 0; m_numGridCells = m_gridSize.x*m_gridSize.y*m_gridSize.z; float3 worldSize = make_float3(2.0f, 2.0f, 2.0f); // set simulation parameters m_params.gridSize = m_gridSize; m_params.numCells = m_numGridCells; m_params.numBodies = m_numParticles; m_params.maxParticlesPerCell = m_maxParticlesPerCell; m_params.worldOrigin = make_float3(-1.0f, -1.0f, -1.0f); m_params.cellSize = make_float3(worldSize.x / m_gridSize.x, worldSize.y / m_gridSize.y, worldSize.z / m_gridSize.z); m_params.particleRadius = m_params.cellSize.x * 0.5f; m_params.colliderPos = make_float4(0.0f, -0.7f, 0.0f, 1.0f); m_params.colliderRadius = 0.2f; m_params.spring = 0.5f; m_params.damping = 0.02f; m_params.shear = 0.1f; m_params.attraction = 0.0f; m_params.boundaryDamping = -0.5f; m_params.gravity = make_float3(0.0f, -0.0003f, 0.0f); m_params.globalDamping = 1.0f; _initialize(numParticles); #if USE_BULLET initializeBullet(); #endif } ParticleSystem::~ParticleSystem() { #if USE_BULLET finalizeBullet(); #endif _finalize(); m_numParticles = 0; } uint ParticleSystem::createVBO(uint size) { GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); registerGLBufferObject(vbo); return vbo; } inline float lerp(float a, float b, float t) { return a + t*(b-a); } void colorRamp(float t, float *r) { const int ncolors = 7; float c[ncolors][3] = { { 1.0, 0.0, 0.0, }, { 1.0, 0.5, 0.0, }, { 1.0, 1.0, 0.0, }, { 0.0, 1.0, 0.0, }, { 0.0, 1.0, 1.0, }, { 0.0, 0.0, 1.0, }, { 1.0, 0.0, 1.0, }, }; t = t * (ncolors-1); int i = (int) t; float u = t - floor(t); r[0] = lerp(c[i][0], c[i+1][0], u); r[1] = lerp(c[i][1], c[i+1][1], u); r[2] = lerp(c[i][2], c[i+1][2], u); } void ParticleSystem::_initialize(int numParticles) { assert(!m_bInitialized); m_numParticles = numParticles; // allocate host storage m_hPos = new float[m_numParticles*4]; m_hVel = new float[m_numParticles*4]; memset(m_hPos, 0, m_numParticles*4*sizeof(float)); memset(m_hVel, 0, m_numParticles*4*sizeof(float)); m_hGridCounters = new uint[m_numGridCells]; m_hGridCells = new uint[m_numGridCells*m_maxParticlesPerCell]; memset(m_hGridCounters, 0, m_numGridCells*sizeof(uint)); memset(m_hGridCells, 0, m_numGridCells*m_maxParticlesPerCell*sizeof(uint)); m_hParticleHash = new uint[m_numParticles*2]; memset(m_hParticleHash, 0, m_numParticles*2*sizeof(uint)); m_hCellStart = new uint[m_numGridCells]; memset(m_hCellStart, 0, m_numGridCells*sizeof(uint)); // allocate GPU data unsigned int memSize = sizeof(float) * 4 * m_numParticles; m_posVbo[0] = createVBO(memSize); m_posVbo[1] = createVBO(memSize); allocateArray((void**)&m_dVel[0], memSize); allocateArray((void**)&m_dVel[1], memSize); allocateArray((void**)&m_dSortedPos, memSize); allocateArray((void**)&m_dSortedVel, memSize); #if USE_SORT allocateArray((void**)&m_dParticleHash[0], m_numParticles*2*sizeof(uint)); allocateArray((void**)&m_dParticleHash[1], m_numParticles*2*sizeof(uint)); allocateArray((void**)&m_dCellStart, m_numGridCells*sizeof(uint)); #else allocateArray((void**)&m_dGridCounters, m_numGridCells*sizeof(uint)); allocateArray((void**)&m_dGridCells, m_numGridCells*m_maxParticlesPerCell*sizeof(uint)); #endif m_colorVBO = createVBO(m_numParticles*4*sizeof(float)); #if 1 // fill color buffer glBindBufferARB(GL_ARRAY_BUFFER, m_colorVBO); float *data = (float *) glMapBufferARB(GL_ARRAY_BUFFER, GL_WRITE_ONLY); float *ptr = data; for(uint i=0; i 1.0f - m_params.particleRadius) { pos.x = 1.0f - m_params.particleRadius; vel.x *= m_params.boundaryDamping; } // if (pos.x < -1.0f + m_params.particleRadius) { pos.x = -1.0f + m_params.particleRadius; vel.x *= m_params.boundaryDamping;} // if (pos.y > 1.0f - m_params.particleRadius) { pos.y = 1.0f - m_params.particleRadius; vel.y *= m_params.boundaryDamping; } // if (pos.y < -1.0f + m_params.particleRadius) { pos.y = -1.0f + m_params.particleRadius; vel.y *= m_params.boundaryDamping;} // if (pos.z > 1.0f - m_params.particleRadius) { pos.z = 1.0f - m_params.particleRadius; vel.z *= m_params.boundaryDamping; } // if (pos.z < -1.0f + m_params.particleRadius) { pos.z = -1.0f + m_params.particleRadius; vel.z *= m_params.boundaryDamping;} btTransform& trans = m_bulletParticles[i]->getWorldTransform(); trans.setOrigin(btVector3(pos.x, pos.y, pos.z)); m_bulletParticles[i]->setLinearVelocity(btVector3(vel.x, vel.y, vel.z)*btScalar(VEL_DIR_FACT)); m_bulletParticles[i]->setAngularVelocity(btVector3(0,0,0)); } glUnmapBufferARB(GL_ARRAY_BUFFER); std::swap(m_currentPosRead, m_currentPosWrite); std::swap(m_currentVelRead, m_currentVelWrite); btTransform& collTrans = m_bulletCollider->getWorldTransform(); collTrans.setOrigin(btVector3(m_params.colliderPos.x, m_params.colliderPos.y, m_params.colliderPos.z)); m_dynamicsWorld->stepSimulation(deltaTime); glBindBufferARB(GL_ARRAY_BUFFER, m_posVbo[m_currentPosRead]); hPos = (float *) glMapBufferARB(GL_ARRAY_BUFFER, GL_READ_WRITE);//GL_WRITE_ONLY); //sync transform and velocity from Bullet to particle system for (uint i=0;igetWorldTransform(); hPos[i*4] = trans.getOrigin().getX(); hPos[i*4+1] = trans.getOrigin().getY(); hPos[i*4+2] = trans.getOrigin().getZ(); hVel[i*4] = m_bulletParticles[i]->getLinearVelocity().getX() * VEL_INV_FACT; hVel[i*4+1] = m_bulletParticles[i]->getLinearVelocity().getY() * VEL_INV_FACT; hVel[i*4+2] = m_bulletParticles[i]->getLinearVelocity().getZ() * VEL_INV_FACT; } copyBuffersFromHostToDevice(); collTrans = m_bulletCollider->getWorldTransform(); m_params.colliderPos.x = collTrans.getOrigin().getX(); m_params.colliderPos.y = collTrans.getOrigin().getY(); m_params.colliderPos.z = collTrans.getOrigin().getZ(); } void ParticleSystem::updateCuda(float deltaTime) { #ifndef BT_NO_PROFILE CProfileManager::Reset(); #endif //BT_NO_PROFILE BT_PROFILE("update CUDA"); // update constants setParameters(&m_params); // integrate { BT_PROFILE("integrate"); integrateSystem(m_posVbo[m_currentPosRead], m_posVbo[m_currentPosWrite], m_dVel[m_currentVelRead], m_dVel[m_currentVelWrite], deltaTime, m_numParticles); } std::swap(m_currentPosRead, m_currentPosWrite); std::swap(m_currentVelRead, m_currentVelWrite); #if USE_SORT // sort and search method // calculate hash { BT_PROFILE("calcHash"); calcHash(m_posVbo[m_currentPosRead], m_dParticleHash[0], m_numParticles); } #if DEBUG_GRID copyArrayFromDevice((void *) m_hParticleHash, (void *) m_dParticleHash[0], 0, sizeof(uint)*2*m_numParticles); printf("particle hash:\n"); for(uint i=0; i maxPerCell) maxPerCell = m_hGridCounters[i]; if (m_hGridCounters[i] > 0) { printf("%d (%d): ", i, m_hGridCounters[i]); for(uint j=0; jsetDebugDrawer(&debugDrawer); //debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawPairs); // m_dynamicsWorld->setGravity(100*btVector3(m_params.gravity.x,m_params.gravity.y,m_params.gravity.z)); m_dynamicsWorld->setGravity(btScalar(ACC_DIR_FACT) * btVector3(m_params.gravity.x,m_params.gravity.y,m_params.gravity.z)); m_dynamicsWorld->getSolverInfo().m_numIterations=1; btRigidBody* body; btCollisionShape* boxShape = new btBoxShape(btVector3(btScalar(1.2),btScalar(0.05),btScalar(1.2))); // boxShape->setMargin(0.03f); btScalar mass(0.); btVector3 localInertia(0,0,0); btRigidBody::btRigidBodyConstructionInfo boxRbcInfo(mass, 0, boxShape, localInertia); boxRbcInfo.m_startWorldTransform.setIdentity(); boxRbcInfo.m_startWorldTransform.setOrigin(btVector3(0, -1.05f,0)); boxRbcInfo.m_friction = 0.0f; body = new btRigidBody(boxRbcInfo); m_dynamicsWorld->addRigidBody(body); boxRbcInfo.m_startWorldTransform.setIdentity(); boxRbcInfo.m_startWorldTransform.setOrigin(btVector3(0, 1.05f,0)); boxRbcInfo.m_friction = 0.0f; body = new btRigidBody(boxRbcInfo); m_dynamicsWorld->addRigidBody(body); boxRbcInfo.m_startWorldTransform.setIdentity(); boxRbcInfo.m_startWorldTransform.getBasis().setEulerZYX(0, 0, SIMD_HALF_PI); boxRbcInfo.m_startWorldTransform.setOrigin(btVector3(-1.05f, 0, 0)); boxRbcInfo.m_friction = 0.0f; body = new btRigidBody(boxRbcInfo); m_dynamicsWorld->addRigidBody(body); boxRbcInfo.m_startWorldTransform.setIdentity(); boxRbcInfo.m_startWorldTransform.getBasis().setEulerZYX(0, 0, SIMD_HALF_PI); boxRbcInfo.m_startWorldTransform.setOrigin(btVector3(1.05f, 0, 0)); boxRbcInfo.m_friction = 0.0f; body = new btRigidBody(boxRbcInfo); m_dynamicsWorld->addRigidBody(body); boxRbcInfo.m_startWorldTransform.setIdentity(); boxRbcInfo.m_startWorldTransform.getBasis().setEulerZYX(SIMD_HALF_PI, 0, 0); boxRbcInfo.m_startWorldTransform.setOrigin(btVector3(0, 0, -1.05f)); boxRbcInfo.m_friction = 0.0f; body = new btRigidBody(boxRbcInfo); m_dynamicsWorld->addRigidBody(body); boxRbcInfo.m_startWorldTransform.setIdentity(); boxRbcInfo.m_startWorldTransform.getBasis().setEulerZYX(SIMD_HALF_PI, 0, 0); boxRbcInfo.m_startWorldTransform.setOrigin(btVector3(0, 0, 1.05f)); boxRbcInfo.m_friction = 0.0f; body = new btRigidBody(boxRbcInfo); m_dynamicsWorld->addRigidBody(body); unsigned int i; btSphereShape* particleSphere = new btSphereShape(m_params.particleRadius); particleSphere->setMargin(0.0); particleSphere->calculateLocalInertia(1,localInertia); reset(CONFIG_GRID); for (i=0;isetActivationState(DISABLE_DEACTIVATION); m_bulletParticles.push_back(body); m_dynamicsWorld->addRigidBody(body); } btSphereShape* colliderSphere = new btSphereShape(m_params.colliderRadius); colliderSphere->setMargin(0.0); colliderSphere->calculateLocalInertia(10., localInertia); btRigidBody::btRigidBodyConstructionInfo rbci(5., 0, colliderSphere,localInertia); rbci.m_startWorldTransform.setOrigin(btVector3(m_params.colliderPos.x, m_params.colliderPos.y, m_params.colliderPos.z)); body = new btRigidBody(rbci); body->setActivationState(DISABLE_DEACTIVATION); m_bulletCollider = body; m_dynamicsWorld->addRigidBody(body); /* for (i=0;i<6;i++) { btVector4 planeEq; worldBox->getPlaneEquation(planeEq,i); planeShape = new btStaticPlaneShape(-planeEq,planeEq.getW()); planeShape->setMargin(0.f); btRigidBody::btRigidBodyConstructionInfo rbci(0.f,0,planeShape); body = new btRigidBody(rbci); m_dynamicsWorld->addRigidBody(body); } */ } void ParticleSystem::finalizeBullet() { delete m_dynamicsWorld; delete m_constraintSolver; delete m_broadphase; delete m_dispatcher ; delete m_collisionConfiguration; } float* ParticleSystem::copyBuffersFromDeviceToHost() { copyArrayFromDevice(m_hVel, m_dVel[m_currentVelRead], 0, sizeof(float)*4*m_numParticles); // fill color buffer glBindBufferARB(GL_ARRAY_BUFFER, m_posVbo[m_currentPosRead]); float* hPosData = (float *) glMapBufferARB(GL_ARRAY_BUFFER, GL_READ_WRITE);//GL_WRITE_ONLY); return hPosData; } void ParticleSystem::copyBuffersFromHostToDevice() { glUnmapBufferARB(GL_ARRAY_BUFFER); copyArrayToDevice(m_dVel[m_currentVelRead],m_hVel, 0, sizeof(float)*4*m_numParticles); } void ParticleSystem::debugDraw() { #if USE_BULLET glDisable(GL_DEPTH_TEST); m_dynamicsWorld->debugDrawWorld(); glEnable(GL_DEPTH_TEST); #endif }