/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "particles_kernel.cuh" #include "particleSystem.cuh" #include "radixsort.cuh" #include "vector_functions.h" #include #ifdef WIN32//for glut.h #include #endif #include //think different #if defined(__APPLE__) && !defined (VMDMESA) #include #include #include #else #include #endif #define USE_SORT 1 #include "btCudaBroadphase.h" #include "LinearMath/btAlignedAllocator.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" btCudaBroadphase::btCudaBroadphase(SimParams& simParams,int maxProxies) : btSimpleBroadphase(maxProxies, new (btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16)) btSortedOverlappingPairCache), m_bInitialized(false), m_numParticles(simParams.numBodies), m_hPos(0), m_hVel(0), m_currentPosRead(0), m_currentVelRead(0), m_currentPosWrite(1), m_currentVelWrite(1), m_maxParticlesPerCell(4), m_simParams(simParams) { m_ownsPairCache = true; m_dPos[0] = m_dPos[1] = 0; m_dVel[0] = m_dVel[1] = 0; m_simParams.gridSize.x = 64; m_simParams.gridSize.y = 64; m_simParams.gridSize.z = 64; m_simParams.numCells = m_simParams.gridSize.x*m_simParams.gridSize.y*m_simParams.gridSize.z; m_simParams.worldSize = make_float3(2.0f, 2.0f, 2.0f); // set simulation parameters m_simParams.numBodies = m_numParticles; m_simParams.maxParticlesPerCell = m_maxParticlesPerCell; m_simParams.worldOrigin = make_float3(-1.0f, -1.0f, -1.0f); m_simParams.cellSize = make_float3(m_simParams.worldSize.x / m_simParams.gridSize.x, m_simParams.worldSize.y / m_simParams.gridSize.y, m_simParams.worldSize.z / m_simParams.gridSize.z); m_simParams.particleRadius = m_simParams.cellSize.x * 0.5f; m_simParams.colliderPos = make_float4(-1.2f, -0.8f, 0.8f, 1.0f); m_simParams.colliderRadius = 0.2f; m_simParams.spring = 0.5f; m_simParams.damping = 0.02f; m_simParams.shear = 0.1f; m_simParams.attraction = 0.0f; m_simParams.boundaryDamping = -0.5f; m_simParams.gravity = make_float3(0.0f, -0.0003f, 0.0f); m_simParams.globalDamping = 1.0f; _initialize(m_numParticles); } static inline float lerp(float a, float b, float t) { return a + t*(b-a); } static 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); } unsigned int btCudaBroadphase::createVBO(unsigned int 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; } void btCudaBroadphase::_initialize(int numParticles) { assert(!m_bInitialized); // allocate host storage m_hPos = new float[numParticles*4]; m_hVel = new float[numParticles*4]; m_hSortedPos = new float[numParticles*4]; memset(m_hPos, 0, numParticles*4*sizeof(float)); memset(m_hVel, 0, numParticles*4*sizeof(float)); memset(m_hSortedPos, 0, numParticles*4*sizeof(float)); m_hGridCounters = new uint[m_simParams.numCells]; m_hGridCells = new uint[m_simParams.numCells*m_maxParticlesPerCell]; memset(m_hGridCounters, 0, m_simParams.numCells*sizeof(uint)); memset(m_hGridCells, 0, m_simParams.numCells*m_maxParticlesPerCell*sizeof(uint)); m_hParticleHash = new uint[numParticles*2]; memset(m_hParticleHash, 0, numParticles*2*sizeof(uint)); m_hCellStart = new uint[m_simParams.numCells]; memset(m_hCellStart, 0, m_simParams.numCells*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_simParams.numCells*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 params.gridSize.x-1) || (gridPos.y < 0) || (gridPos.y > params.gridSize.y-1) || (gridPos.z < 0) || (gridPos.z > params.gridSize.z-1)) { return force; } uint gridHash = calcGridHash(gridPos); // get start of bucket for this cell uint bucketStart = FETCH(cellStart, gridHash); if (bucketStart == 0xffffffff) return force; // cell empty // iterate over particles in this cell for(uint i=0; i= 0) { //#define _USE_BRUTEFORCE_N 1 #ifdef _USE_BRUTEFORCE_N int i; for (i=0;ifindPair(proxy0,proxy1)) { m_pairCache->addOverlappingPair(proxy0,proxy1); } } else { if (!m_pairCache->hasDeferredRemoval()) { if ( m_pairCache->findPair(proxy0,proxy1)) { m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); } } } } proxy1 = &m_pHandles[proxy1->GetNextAllocated()]; } proxy0 = &m_pHandles[proxy0->GetNextAllocated()]; } #else //_USE_BRUTEFORCE_N // update constants setParameters(&m_simParams); float deltaTime = 1./60.f; /* // integrate integrateSystem(m_posVbo[m_currentPosRead], m_posVbo[m_currentPosWrite], m_dVel[m_currentVelRead], m_dVel[m_currentVelWrite], deltaTime, m_numParticles); btSwap(m_currentPosRead, m_currentPosWrite); btSwap(m_currentVelRead, m_currentVelWrite); */ #if USE_SORT // sort and search method // calculate hash 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; im_min+proxy0->m_max)*0.5f; // float4* p = (float4*)&m_hSortedPos[index*4]; int3 particleGridPos; particleGridPos.x = floor((mypos.x() - m_simParams.worldOrigin.x) / m_simParams.cellSize.x); particleGridPos.y = floor((mypos.y() - m_simParams.worldOrigin.y) / m_simParams.cellSize.y); particleGridPos.z = floor((mypos.z() - m_simParams.worldOrigin.z) / m_simParams.cellSize.z); //for(int z=0; z<1; z++) for(int z=-1; z<=1; z++) { // for(int y=0; y<1; y++) for(int y=-1; y<=1; y++) { // for(int x=0; x<1; x++) for(int x=-1; x<=1; x++) { int3 gridPos; gridPos.x = particleGridPos.x + x; gridPos.y = particleGridPos.y + y; gridPos.z = particleGridPos.z + z; if ((gridPos.x < 0) || (gridPos.x > m_simParams.gridSize.x-1) || (gridPos.y < 0) || (gridPos.y > m_simParams.gridSize.y-1) || (gridPos.z < 0) || (gridPos.z > m_simParams.gridSize.z-1)) { continue; } gridPos.x = max(0, min(gridPos.x, m_simParams.gridSize.x-1)); gridPos.y = max(0, min(gridPos.y, m_simParams.gridSize.y-1)); gridPos.z = max(0, min(gridPos.z, m_simParams.gridSize.z-1)); uint gridHash = ((gridPos.z*m_simParams.gridSize.y)* m_simParams.gridSize.x) + (gridPos.y* m_simParams.gridSize.x) + gridPos.x; // get start of bucket for this cell unsigned int bucketStart = m_hCellStart[gridHash]; if (bucketStart == 0xffffffff) continue; // iterate over particles in this cell for(uint q=0; qaddOverlappingPair(proxy0,proxy1); else { numRejected++; } } } //int numOverlap += myCollideCell2(gridPos + make_int3(x, y, z), index, pos, vel, oldPos, oldVel, particleHash, cellStart); } } } } #endif //_USE_BRUTEFORCE_N ///if this broadphase is used in a btMultiSapBroadphase, we shouldn't sort the overlapping paircache if (m_ownsPairCache && m_pairCache->hasDeferredRemoval()) { btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray(); //perform a sort, to find duplicates and to sort 'invalid' pairs to the end //overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); overlappingPairArray.heapSort(btBroadphasePairSortPredicate()); //printf("A) overlappingPairArray.size()=%d\n",overlappingPairArray.size()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; btBroadphasePair previousPair; previousPair.m_pProxy0 = 0; previousPair.m_pProxy1 = 0; previousPair.m_algorithm = 0; int i; for (i=0;iprocessOverlap(pair); } else { needsRemoval = true; } } else { //remove duplicate needsRemoval = true; //should have no algorithm btAssert(!pair.m_algorithm); } if (needsRemoval) { m_pairCache->cleanOverlappingPair(pair,dispatcher); // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); // m_overlappingPairArray.pop_back(); pair.m_pProxy0 = 0; pair.m_pProxy1 = 0; m_invalidPair++; } } ///if you don't like to skip the invalid pairs in the array, execute following code: #define CLEAN_INVALID_PAIRS 1 #ifdef CLEAN_INVALID_PAIRS //perform a sort, to sort 'invalid' pairs to the end //overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); overlappingPairArray.heapSort(btBroadphasePairSortPredicate()); //printf("B) overlappingPairArray.size()=%d\n",overlappingPairArray.size()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); // printf("C) overlappingPairArray.size()=%d\n",overlappingPairArray.size()); m_invalidPair = 0; #endif//CLEAN_INVALID_PAIRS } } //printf("numRejected=%d\n",numRejected); } static inline float frand() { return rand() / (float) RAND_MAX; } void btCudaBroadphase::initGrid(unsigned int* size, float spacing, float jitter, unsigned int numParticles) { srand(1973); #ifdef CONTROLLED_START float extra=0.01f; for(uint z=0; z maxPerCell) maxPerCell = m_hGridCounters[i]; if (m_hGridCounters[i] > 0) { printf("%d (%d): ", i, m_hGridCounters[i]); for(uint j=0; j