New version of btCudaBroadphase compatible with Bullet and better performance
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
#include "radixsort.cuh"
|
||||
#include "particles_kernel.cuh"
|
||||
|
||||
//#include <cutil.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
@@ -42,6 +43,7 @@
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include "../../Demos/OpenGL/GLDebugDrawer.h"
|
||||
|
||||
#include "btCudaBroadphase.h"
|
||||
|
||||
@@ -50,22 +52,609 @@
|
||||
#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_simulationMode(SIMULATION_BULLET_CPU)//SIMULATION_CUDA)
|
||||
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)
|
||||
{
|
||||
this->m_params.numBodies = numParticles;
|
||||
this->m_params.m_gridSize = gridSize;
|
||||
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<m_numParticles; i++) {
|
||||
float t = i / (float) m_numParticles;
|
||||
#if 0
|
||||
*ptr++ = rand() / (float) RAND_MAX;
|
||||
*ptr++ = rand() / (float) RAND_MAX;
|
||||
*ptr++ = rand() / (float) RAND_MAX;
|
||||
#else
|
||||
colorRamp(t, ptr);
|
||||
ptr+=3;
|
||||
#endif
|
||||
*ptr++ = 1.0f;
|
||||
}
|
||||
glUnmapBufferARB(GL_ARRAY_BUFFER);
|
||||
#endif
|
||||
|
||||
// CUT_SAFE_CALL(cutCreateTimer(&m_timer));
|
||||
|
||||
setParameters(&m_params);
|
||||
|
||||
m_bInitialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::_finalize()
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
delete [] m_hPos;
|
||||
delete [] m_hVel;
|
||||
|
||||
delete [] m_hGridCounters;
|
||||
delete [] m_hGridCells;
|
||||
|
||||
freeArray(m_dVel[0]);
|
||||
freeArray(m_dVel[1]);
|
||||
|
||||
freeArray(m_dSortedPos);
|
||||
freeArray(m_dSortedVel);
|
||||
|
||||
#if USE_SORT
|
||||
freeArray(m_dParticleHash[0]);
|
||||
freeArray(m_dParticleHash[1]);
|
||||
freeArray(m_dCellStart);
|
||||
#else
|
||||
freeArray(m_dGridCounters);
|
||||
freeArray(m_dGridCells);
|
||||
#endif
|
||||
|
||||
unregisterGLBufferObject(m_posVbo[0]);
|
||||
unregisterGLBufferObject(m_posVbo[1]);
|
||||
glDeleteBuffers(2, (const GLuint*)m_posVbo);
|
||||
|
||||
glDeleteBuffers(1, (const GLuint*)&m_colorVBO);
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::update(float deltaTime)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
#if USE_BULLET
|
||||
switch (m_simulationMode)
|
||||
{
|
||||
case SIMULATION_CUDA:
|
||||
{
|
||||
updateCuda(deltaTime);
|
||||
break;
|
||||
}
|
||||
case SIMULATION_BULLET_CPU:
|
||||
{
|
||||
updateBullet(deltaTime);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printf("unknown simulation method\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
updateCuda(deltaTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::updateBullet(float deltaTime)
|
||||
{
|
||||
float* hPos = copyBuffersFromDeviceToHost();
|
||||
float* hVel = m_hVel;
|
||||
|
||||
for (uint i=0;i<m_params.numBodies;i++)
|
||||
{
|
||||
float3 pos;
|
||||
pos.x = hPos[i*4];
|
||||
pos.y = hPos[i*4+1];
|
||||
pos.z = hPos[i*4+2];
|
||||
float3 vel;
|
||||
vel.x = hVel[i*4];
|
||||
vel.y = hVel[i*4+1];
|
||||
vel.z = hVel[i*4+2];
|
||||
// if (pos.x > 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;i<m_params.numBodies;i++)
|
||||
{
|
||||
btTransform& trans = m_bulletParticles[i]->getWorldTransform();
|
||||
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<m_numParticles; i++) {
|
||||
printf("%d: %d, %d\n", i, m_hParticleHash[i*2], m_hParticleHash[i*2+1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// sort particles based on hash
|
||||
{
|
||||
BT_PROFILE("RadixSort");
|
||||
RadixSort((KeyValuePair *) m_dParticleHash[0], (KeyValuePair *) m_dParticleHash[1], m_numParticles, 32);
|
||||
}
|
||||
|
||||
#if DEBUG_GRID
|
||||
copyArrayFromDevice((void *) m_hParticleHash, (void *) m_dParticleHash[0], 0, sizeof(uint)*2*m_numParticles);
|
||||
printf("particle hash sorted:\n");
|
||||
for(uint i=0; i<m_numParticles; i++) {
|
||||
printf("%d: %d, %d\n", i, m_hParticleHash[i*2], m_hParticleHash[i*2+1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// reorder particle arrays into sorted order and
|
||||
// find start of each cell
|
||||
{
|
||||
BT_PROFILE("reorder");
|
||||
reorderDataAndFindCellStart(m_dParticleHash[0],
|
||||
m_posVbo[m_currentPosRead],
|
||||
m_dVel[m_currentVelRead],
|
||||
m_dSortedPos,
|
||||
m_dSortedVel,
|
||||
m_dCellStart,
|
||||
m_numParticles,
|
||||
m_numGridCells);
|
||||
}
|
||||
#if DEBUG_GRID
|
||||
copyArrayFromDevice((void *) m_hCellStart, (void *) m_dCellStart, 0, sizeof(uint)*m_numGridCells);
|
||||
printf("cell start:\n");
|
||||
for(uint i=0; i<m_numGridCells; i++) {
|
||||
printf("%d: %d\n", i, m_hCellStart[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
// update grid using atomics
|
||||
updateGrid(m_posVbo[m_currentPosRead],
|
||||
m_dGridCounters,
|
||||
m_dGridCells,
|
||||
m_numParticles,
|
||||
m_numGridCells);
|
||||
#endif
|
||||
|
||||
// process collisions
|
||||
{
|
||||
BT_PROFILE("collide");
|
||||
for(uint i=0; i<m_solverIterations; i++) {
|
||||
collide(m_posVbo[m_currentPosRead], m_posVbo[m_currentPosWrite],
|
||||
m_dSortedPos, m_dSortedVel,
|
||||
m_dVel[m_currentVelRead], m_dVel[m_currentVelWrite],
|
||||
m_dGridCounters,
|
||||
m_dGridCells,
|
||||
m_dParticleHash[0],
|
||||
m_dCellStart,
|
||||
m_numParticles,
|
||||
m_numGridCells,
|
||||
m_maxParticlesPerCell
|
||||
);
|
||||
std::swap(m_currentVelRead, m_currentVelWrite);
|
||||
}
|
||||
}
|
||||
#ifndef BT_NO_PROFILE
|
||||
CProfileManager::Increment_Frame_Counter();
|
||||
#endif //BT_NO_PROFILE
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::dumpGrid()
|
||||
{
|
||||
// debug
|
||||
copyArrayFromDevice(m_hGridCounters, m_dGridCounters, 0, sizeof(uint)*m_numGridCells);
|
||||
copyArrayFromDevice(m_hGridCells, m_dGridCells, 0, sizeof(uint)*m_numGridCells*m_maxParticlesPerCell);
|
||||
uint total = 0;
|
||||
uint maxPerCell = 0;
|
||||
for(uint i=0; i<m_numGridCells; i++) {
|
||||
if (m_hGridCounters[i] > maxPerCell)
|
||||
maxPerCell = m_hGridCounters[i];
|
||||
if (m_hGridCounters[i] > 0) {
|
||||
printf("%d (%d): ", i, m_hGridCounters[i]);
|
||||
for(uint j=0; j<m_hGridCounters[i]; j++) {
|
||||
printf("%d ", m_hGridCells[i*m_maxParticlesPerCell + j]);
|
||||
}
|
||||
total += m_hGridCounters[i];
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("max per cell = %d\n", maxPerCell);
|
||||
printf("total = %d\n", total);
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::dumpParticles(uint start, uint count)
|
||||
{
|
||||
// debug
|
||||
copyArrayFromDevice(m_hPos, 0, m_posVbo[m_currentPosRead], sizeof(float)*4*count);
|
||||
copyArrayFromDevice(m_hVel, m_dVel[m_currentVelRead], 0, sizeof(float)*4*count);
|
||||
|
||||
for(uint i=start; i<start+count; i++) {
|
||||
// printf("%d: ", i);
|
||||
printf("pos: (%.4f, %.4f, %.4f, %.4f)\n", m_hPos[i*4+0], m_hPos[i*4+1], m_hPos[i*4+2], m_hPos[i*4+3]);
|
||||
printf("vel: (%.4f, %.4f, %.4f, %.4f)\n", m_hVel[i*4+0], m_hVel[i*4+1], m_hVel[i*4+2], m_hVel[i*4+3]);
|
||||
}
|
||||
}
|
||||
|
||||
float*
|
||||
ParticleSystem::getArray(ParticleArray array)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
float* hdata = 0;
|
||||
float* ddata = 0;
|
||||
|
||||
unsigned int vbo = 0;
|
||||
|
||||
switch (array)
|
||||
{
|
||||
default:
|
||||
case POSITION:
|
||||
hdata = m_hPos;
|
||||
ddata = m_dPos[m_currentPosRead];
|
||||
vbo = m_posVbo[m_currentPosRead];
|
||||
break;
|
||||
case VELOCITY:
|
||||
hdata = m_hVel;
|
||||
ddata = m_dVel[m_currentVelRead];
|
||||
break;
|
||||
}
|
||||
|
||||
copyArrayFromDevice(hdata, ddata, vbo, m_numParticles*4*sizeof(float));
|
||||
return hdata;
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::setArray(ParticleArray array, const float* data, int start, int count)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
switch (array)
|
||||
{
|
||||
default:
|
||||
case POSITION:
|
||||
{
|
||||
unregisterGLBufferObject(m_posVbo[m_currentPosRead]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_posVbo[m_currentPosRead]);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, start*4*sizeof(float), count*4*sizeof(float), data);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
registerGLBufferObject(m_posVbo[m_currentPosRead]);
|
||||
}
|
||||
break;
|
||||
case VELOCITY:
|
||||
copyArrayToDevice(m_dVel[m_currentVelRead], data, start*4*sizeof(float), count*4*sizeof(float));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline float frand()
|
||||
{
|
||||
return rand() / (float) RAND_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::initGrid(uint *size, float spacing, float jitter, uint numParticles)
|
||||
{
|
||||
srand(1973);
|
||||
for(uint z=0; z<size[2]; z++) {
|
||||
for(uint y=0; y<size[1]; y++) {
|
||||
for(uint x=0; x<size[0]; x++) {
|
||||
uint i = (z*size[1]*size[0]) + (y*size[0]) + x;
|
||||
if (i < numParticles) {
|
||||
m_hPos[i*4] = (spacing * x) + m_params.particleRadius - 1.0f + (frand()*2.0f-1.0f)*jitter;
|
||||
m_hPos[i*4+1] = (spacing * y) + m_params.particleRadius - 1.0f + (frand()*2.0f-1.0f)*jitter;
|
||||
m_hPos[i*4+2] = (spacing * z) + m_params.particleRadius - 1.0f + (frand()*2.0f-1.0f)*jitter;
|
||||
m_hPos[i*4+3] = 1.0f;
|
||||
|
||||
m_hVel[i*4] = 0.0f;
|
||||
m_hVel[i*4+1] = 0.0f;
|
||||
m_hVel[i*4+2] = 0.0f;
|
||||
m_hVel[i*4+3] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::reset(ParticleConfig config)
|
||||
{
|
||||
switch(config)
|
||||
{
|
||||
default:
|
||||
case CONFIG_RANDOM:
|
||||
{
|
||||
int p = 0, v = 0;
|
||||
for(uint i=0; i < m_numParticles; i++)
|
||||
{
|
||||
float point[3];
|
||||
point[0] = frand();
|
||||
point[1] = frand();
|
||||
point[2] = frand();
|
||||
m_hPos[p++] = 2 * (point[0] - 0.5f);
|
||||
m_hPos[p++] = 2 * (point[1] - 0.5f);
|
||||
m_hPos[p++] = 2 * (point[2] - 0.5f);
|
||||
m_hPos[p++] = 1.0f; // radius
|
||||
m_hVel[v++] = 0.0f;
|
||||
m_hVel[v++] = 0.0f;
|
||||
m_hVel[v++] = 0.0f;
|
||||
m_hVel[v++] = 0.0f;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CONFIG_GRID:
|
||||
{
|
||||
float jitter = m_params.particleRadius*0.01f;
|
||||
uint s = (int) ceilf(powf((float) m_numParticles, 1.0f / 3.0f));
|
||||
uint gridSize[3];
|
||||
gridSize[0] = gridSize[1] = gridSize[2] = s;
|
||||
initGrid(gridSize, m_params.particleRadius*2.0f, jitter, m_numParticles);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
setArray(POSITION, m_hPos, 0, m_numParticles);
|
||||
setArray(VELOCITY, m_hVel, 0, m_numParticles);
|
||||
}
|
||||
|
||||
void
|
||||
ParticleSystem::addSphere(int start, float *pos, float *vel, int r, float spacing)
|
||||
{
|
||||
uint index = start;
|
||||
for(int z=-r; z<=r; z++) {
|
||||
for(int y=-r; y<=r; y++) {
|
||||
for(int x=-r; x<=r; x++) {
|
||||
float dx = x*spacing;
|
||||
float dy = y*spacing;
|
||||
float dz = z*spacing;
|
||||
float l = sqrtf(dx*dx + dy*dy + dz*dz);
|
||||
if ((l <= m_params.particleRadius*2.0f*r) && (index < m_numParticles)) {
|
||||
m_hPos[index*4] = pos[0] + dx;
|
||||
m_hPos[index*4+1] = pos[1] + dy;
|
||||
m_hPos[index*4+2] = pos[2] + dz;
|
||||
m_hPos[index*4+3] = pos[3];
|
||||
|
||||
m_hVel[index*4] = vel[0];
|
||||
m_hVel[index*4+1] = vel[1];
|
||||
m_hVel[index*4+2] = vel[2];
|
||||
m_hVel[index*4+3] = vel[3];
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setArray(POSITION, m_hPos, start, index);
|
||||
setArray(VELOCITY, m_hVel, start, index);
|
||||
|
||||
}
|
||||
#include "../../Demos/OpenGL/GLDebugDrawer.h"
|
||||
|
||||
GLDebugDrawer debugDrawer;
|
||||
|
||||
void ParticleSystem::initializeBullet()
|
||||
{
|
||||
@@ -73,9 +662,8 @@ void ParticleSystem::initializeBullet()
|
||||
m_collisionConfiguration = new btDefaultCollisionConfiguration();
|
||||
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
|
||||
// m_broadphase = new btDbvtBroadphase();
|
||||
//m_broadphase = new btAxisSweep3(btVector3(-3,-3,-3),btVector3(3,3,3));
|
||||
m_broadphase = new btCudaBroadphase(m_params,m_params.numBodies+6);
|
||||
|
||||
// m_broadphase = new btAxisSweep3(btVector3(-3,-3,-3),btVector3(3,3,3));
|
||||
m_broadphase = new btCudaBroadphase(btVector3(-1, -1, -1), btVector3(1, 1, 1), 64, 64, 64, m_params.numBodies, 16, 64, 8, btScalar(1.0f/1.733f));
|
||||
|
||||
|
||||
m_constraintSolver=new btSequentialImpulseConstraintSolver();
|
||||
@@ -84,27 +672,67 @@ void ParticleSystem::initializeBullet()
|
||||
//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(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;
|
||||
|
||||
btBoxShape* worldBox = new btBoxShape(btVector3(m_params.worldSize.x/2,m_params.worldSize.y/2,m_params.worldSize.z/2));
|
||||
worldBox->setMargin(0.f);
|
||||
|
||||
//create 6 static planes for the world cube
|
||||
btStaticPlaneShape* planeShape;
|
||||
btRigidBody* body;
|
||||
btVector3 worldSize();
|
||||
|
||||
int i;
|
||||
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);
|
||||
btVector3 localInertia;
|
||||
particleSphere->calculateLocalInertia(1,localInertia);
|
||||
|
||||
float* m_hPos = m_broadphase->getHposPtr();
|
||||
reset(CONFIG_GRID);
|
||||
|
||||
for (i=0;i<m_params.numBodies;i++)
|
||||
{
|
||||
@@ -116,7 +744,15 @@ void ParticleSystem::initializeBullet()
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
|
||||
reset(CONFIG_GRID);
|
||||
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++)
|
||||
{
|
||||
@@ -130,7 +766,6 @@ void ParticleSystem::initializeBullet()
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void ParticleSystem::finalizeBullet()
|
||||
@@ -142,139 +777,29 @@ void ParticleSystem::finalizeBullet()
|
||||
delete m_collisionConfiguration;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ParticleSystem::update(float deltaTime)
|
||||
float* ParticleSystem::copyBuffersFromDeviceToHost()
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
switch (m_simulationMode)
|
||||
{
|
||||
case SIMULATION_CUDA:
|
||||
{
|
||||
m_broadphase->quickHack(deltaTime);
|
||||
//todo
|
||||
break;
|
||||
}
|
||||
case SIMULATION_BULLET_CPU:
|
||||
{
|
||||
m_broadphase->integrate();
|
||||
|
||||
|
||||
///copy particles from device to main memory
|
||||
{
|
||||
float* hPosData = m_broadphase->copyBuffersFromDeviceToHost();
|
||||
float* m_hVel = m_broadphase->getHvelPtr();
|
||||
m_broadphase->copyBuffersFromHostToDevice();
|
||||
|
||||
|
||||
//sync transform and velocity from particle system to Bullet
|
||||
|
||||
for (int i=0;i<m_params.numBodies;i++)
|
||||
{
|
||||
btTransform& trans = m_bulletParticles[i]->getWorldTransform();
|
||||
trans.setOrigin(btVector3(hPosData[i*4],hPosData[i*4+1],hPosData[i*4+2]));
|
||||
m_bulletParticles[i]->setLinearVelocity(btVector3(m_hVel[i*4],m_hVel[i*4+1],m_hVel[i*4+2])*10.);
|
||||
}
|
||||
}
|
||||
|
||||
m_dynamicsWorld->stepSimulation(deltaTime);
|
||||
|
||||
/* for (int i=0;i<m_numParticles;i++)
|
||||
{
|
||||
data[i*4+1] -= 0.001f;
|
||||
m_hVel[i*4]=0;
|
||||
m_hVel[i*4+1]=0;
|
||||
m_hVel[i*4+2]=0;
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
float* hPosData = m_broadphase->copyBuffersFromDeviceToHost();
|
||||
float* m_hVel = m_broadphase->getHvelPtr();
|
||||
|
||||
//sync transform and velocity from Bullet to particle system
|
||||
for (int i=0;i<m_params.numBodies;i++)
|
||||
{
|
||||
btTransform& trans = m_bulletParticles[i]->getWorldTransform();
|
||||
hPosData[i*4] = trans.getOrigin().getX();
|
||||
hPosData[i*4+1] = trans.getOrigin().getY();
|
||||
hPosData[i*4+2] = trans.getOrigin().getZ();
|
||||
|
||||
m_hVel[i*4] = m_bulletParticles[i]->getLinearVelocity().getX()/10.f;
|
||||
m_hVel[i*4+1] = m_bulletParticles[i]->getLinearVelocity().getY()/10.f;
|
||||
m_hVel[i*4+2] = m_bulletParticles[i]->getLinearVelocity().getZ()/10.f;
|
||||
}
|
||||
|
||||
m_broadphase->copyBuffersFromHostToDevice();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
printf("unknown simulation method\n");
|
||||
}
|
||||
};
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
float* ParticleSystem::getArray(ParticleArray array)
|
||||
{
|
||||
return m_broadphase->getArray((btCudaBroadphase::ParticleArray)array);
|
||||
|
||||
}
|
||||
void ParticleSystem::debugDraw()
|
||||
{
|
||||
#if USE_BULLET
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
m_dynamicsWorld->debugDrawWorld();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ParticleSystem::reset(ParticleConfig config)
|
||||
{
|
||||
m_broadphase->reset((btCudaBroadphase::ParticleConfig)config);
|
||||
for (int i=0;i<m_bulletParticles.size();i++)
|
||||
{
|
||||
m_bulletParticles[i]->setAngularVelocity(btVector3(0,0,0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ParticleSystem::addSphere(int start, float *pos, float *vel, int r, float spacing)
|
||||
{
|
||||
m_broadphase->addSphere(start,pos,vel,r,spacing);
|
||||
}
|
||||
|
||||
unsigned int ParticleSystem::getCurrentReadBuffer() const
|
||||
{
|
||||
return m_broadphase->getCurrentReadBuffer();
|
||||
}
|
||||
unsigned int ParticleSystem::getColorBuffer() const
|
||||
{
|
||||
return m_broadphase->getColorBuffer();
|
||||
}
|
||||
|
||||
void ParticleSystem::dumpGrid()
|
||||
{
|
||||
return m_broadphase->dumpGrid();
|
||||
}
|
||||
|
||||
void ParticleSystem::dumpParticles(uint start, uint count)
|
||||
{
|
||||
m_broadphase->dumpParticles(start,count);
|
||||
}
|
||||
|
||||
int ParticleSystem::getNumParticles() const
|
||||
{
|
||||
return m_params.numBodies;
|
||||
}
|
||||
Reference in New Issue
Block a user