bool DelayedInitializer::eventFilter( QObject *receiver, QEvent *event ) { if ( m_signalEmitted || event->type() != m_eventType ) return false; m_signalEmitted = true; receiver->removeEventFilter( this ); // Move the emitting of the event to the end of the eventQueue // so we are absolutely sure the event we get here is handled before // the initialize is fired. QTimer::singleShot( 0, this, SLOT( slotInitialize() ) ); return false; }
void ParticleSystem::slotResetParticles() { qDebug() << __PRETTY_FUNCTION__; if(!mIsInitialized) slotInitialize(); // When re-setting particles, also reset their position of last collision! cudaSafeCall(cudaMemset(mDeviceParticleCollisionPositions, 0, mParametersSimulation->particleCount * 4 * sizeof(float))); switch(mDefaultParticlePlacement) { case ParticlePlacement::PlacementRandom: { int p = 0, v = 0; qDebug() << __PRETTY_FUNCTION__ << "world min" << mParametersSimulation->gridParticleSystem.worldMin.x << mParametersSimulation->gridParticleSystem.worldMin.y << mParametersSimulation->gridParticleSystem.worldMin.z << "max" << mParametersSimulation->gridParticleSystem.worldMax.x << mParametersSimulation->gridParticleSystem.worldMax.y << mParametersSimulation->gridParticleSystem.worldMax.z; for(unsigned int i=0; i < mParametersSimulation->particleCount; i++) { mHostParticlePos[p++] = mParametersSimulation->gridParticleSystem.worldMin.x + (mParametersSimulation->gridParticleSystem.worldMax.x - mParametersSimulation->gridParticleSystem.worldMin.x) * frand(); mHostParticlePos[p++] = mParametersSimulation->gridParticleSystem.worldMin.y + (mParametersSimulation->gridParticleSystem.worldMax.y - mParametersSimulation->gridParticleSystem.worldMin.y) * frand(); mHostParticlePos[p++] = mParametersSimulation->gridParticleSystem.worldMin.z + (mParametersSimulation->gridParticleSystem.worldMax.z - mParametersSimulation->gridParticleSystem.worldMin.z) * frand(); mHostParticlePos[p++] = 1.0f; mHostParticleVel[v++] = 0.0f; mHostParticleVel[v++] = 0.0f; mHostParticleVel[v++] = 0.0f; mHostParticleVel[v++] = 0.0f; } break; } case ParticlePlacement::PlacementGrid: { const float jitter = mParametersSimulation->particleRadius * 0.01f; const float spacing = mParametersSimulation->particleRadius * 2.0f; // If we want a cube, determine the number of particles in each dimension unsigned int s = (int) ceilf(powf((float) mParametersSimulation->particleCount, 1.0f / 3.0f)); unsigned int gridSize[3]; gridSize[0] = gridSize[1] = gridSize[2] = s; srand(1973); for(unsigned int z=0; z<gridSize[2]; z++) { for(unsigned int y=0; y<gridSize[1]; y++) { for(unsigned int x=0; x<gridSize[0]; x++) { unsigned int i = (z*gridSize[1]*gridSize[0]) + (y*gridSize[0]) + x; if (i < mParametersSimulation->particleCount) { mHostParticlePos[i*4+0] = (spacing * x) + mParametersSimulation->particleRadius - 1.0f + (frand()*2.0f-1.0f)*jitter; mHostParticlePos[i*4+1] = (spacing * y) + mParametersSimulation->particleRadius - 1.0f + (frand()*2.0f-1.0f)*jitter; mHostParticlePos[i*4+2] = (spacing * z) + mParametersSimulation->particleRadius - 1.0f + (frand()*2.0f-1.0f)*jitter; mHostParticlePos[i*4+3] = 1.0f; mHostParticleVel[i*4+0] = 0.0f; mHostParticleVel[i*4+1] = 0.0f; mHostParticleVel[i*4+2] = 0.0f; mHostParticleVel[i*4+3] = 0.0f; } } } } break; } case ParticlePlacement::PlacementFillSky: { float jitter = mParametersSimulation->particleRadius * 0.1f; const float spacing = mParametersSimulation->particleRadius * 2.02f; unsigned int particleNumber = 0; for( float y = mParametersSimulation->gridParticleSystem.worldMax.y - mParametersSimulation->particleRadius; y >= mParametersSimulation->gridParticleSystem.worldMin.y + mParametersSimulation->particleRadius && particleNumber < mParametersSimulation->particleCount; y -= spacing) { for( float x = mParametersSimulation->gridParticleSystem.worldMin.x + mParametersSimulation->particleRadius; x <= mParametersSimulation->gridParticleSystem.worldMax.x - mParametersSimulation->particleRadius && particleNumber < mParametersSimulation->particleCount; x += spacing) { for( float z = mParametersSimulation->gridParticleSystem.worldMin.z + mParametersSimulation->particleRadius; z <= mParametersSimulation->gridParticleSystem.worldMax.z - mParametersSimulation->particleRadius && particleNumber < mParametersSimulation->particleCount; z += spacing) { // qDebug() << "moving particle" << particleNumber << "to" << x << y << z; mHostParticlePos[particleNumber*4+0] = x + (frand()-0.5) * jitter; mHostParticlePos[particleNumber*4+1] = y + (frand()-0.5) * jitter; mHostParticlePos[particleNumber*4+2] = z + (frand()-0.5) * jitter; mHostParticlePos[particleNumber*4+3] = 1.0f; mHostParticleVel[particleNumber*4+0] = 0.0f; mHostParticleVel[particleNumber*4+1] = 0.0f; mHostParticleVel[particleNumber*4+2] = 0.0f; mHostParticleVel[particleNumber*4+3] = 0.0f; particleNumber++; } } } break; } } setArray(ArrayPositions, mHostParticlePos, 0, mParametersSimulation->particleCount); setArray(ArrayVelocities, mHostParticleVel, 0, mParametersSimulation->particleCount); }
// step the simulation void ParticleSystem::update(quint8 *deviceGridMapOfWayPointPressure) { //qDebug() << __PRETTY_FUNCTION__; //if(mParametersSimulation->gridParticleSystem.worldMax.x == 0.0f) return; // why this? if(!mIsInitialized) slotInitialize(); QTime startTime = QTime::currentTime(); startTime.start(); // Get a pointer to the particle positions in the device by mapping GPU mem into CPU mem float *deviceParticlePositions = (float*)CudaHelper::mapGLBufferObject(&mCudaVboResourceParticlePositions); //qDebug() << __PRETTY_FUNCTION__ << "0: getting pointer finished at" << startTime.elapsed(); // Update constants copyParametersToGpu(mParametersSimulation); //qDebug() << __PRETTY_FUNCTION__ << "1: setting parameters finished at" << startTime.elapsed(); // Get a pointer to the "__constant__ ParametersParticleSystem parametersParticleSystem" on the device ParametersParticleSystem* paramsParticleSystem; getDeviceAddressOfParametersParticleSystem(¶msParticleSystem); // Integrate integrateSystem( deviceParticlePositions, // in/out: The particle positions, unsorted mDeviceParticleVel, // in/out: The particle velocities, unsorted deviceGridMapOfWayPointPressure, // output: A grid mapping the 3d-space to waypoint pressure. Cells with high values (255) should be visited for information gain. mDeviceParticleCollisionPositions, // input: The particle's last collision position (or 0 if it didn't collide yet) paramsParticleSystem, // input: The particle system's parameters mParametersSimulation->particleCount); // showInformationGain(); //qDebug() << __PRETTY_FUNCTION__ << "2: integrating system finished at" << startTime.elapsed(); // Now that particles have been moved, they might be contained in different grid cells. So recompute the // mapping gridCell => particleIndex. This will allow fast neighbor searching in the grid during collision phase. computeMappingFromPointToGridCell( mDeviceParticleMapGridCell, // output: The key - part of the particle gridcell->index map, unsorted mDeviceParticleMapIndex, // output: The value-part of the particle gridcell->index map, unsorted deviceParticlePositions, // input: The particle positions after integration, unsorted and possibly colliding with other particles ¶msParticleSystem->gridParticleSystem, mParametersSimulation->particleCount); // input: The number of particles, one thread per particle //qDebug() << __PRETTY_FUNCTION__ << "3: computing particle spatial hash table finished at" << startTime.elapsed(); // Sort the mapping gridCell => particleId on gridCell sortGridOccupancyMap(mDeviceParticleMapGridCell, mDeviceParticleMapIndex, mParametersSimulation->particleCount); //qDebug() << __PRETTY_FUNCTION__ << "4: sorting particle spatial hash table finished at" << startTime.elapsed(); // Reorder particle arrays into sorted order and find start and end of each cell. The ordering of the particles is useful // only for the particle/particle-collisions. The collision code writes the post-collision velocities back into the // original, unsorted particle velocity array, where is will be used again in the next iteration's integrateSystem(). sortParticlePosAndVelAccordingToGridCellAndFillCellStartAndEndArrays( mDeviceParticleCellStart, // output: At which index in mDeviceMapParticleIndex does cell X start? mDeviceParticleCellEnd, // output: At which index in mDeviceMapParticleIndex does cell X end? mDeviceParticleSortedPos, // output: The particle positions, sorted by gridcell mDeviceParticleSortedVel, // output: The particle velocities, sorted by gridcell mDeviceParticleMapGridCell, // input: The key - part of the particle gridcell->index map, unsorted mDeviceParticleMapIndex, // input: The value-part of the particle gridcell->index map, unsorted deviceParticlePositions, // input: The particle-positions, unsorted mDeviceParticleVel, // input: The particle-velocities, unsorted mParametersSimulation->particleCount, // input: The number of particles mParametersSimulation->gridParticleSystem.getCellCount() // input: Number of grid cells ); //qDebug() << __PRETTY_FUNCTION__ << "5: computing particle navigation tables and sorting particles finished at" << startTime.elapsed(); // Same for colliders if(mUpdateMappingFromColliderToGridCell) { float *deviceColliderPositions = (float*)CudaHelper::mapGLBufferObject(&mCudaVboResourceColliderPositions); computeMappingFromPointToGridCell( mDeviceColliderMapGridCell, // output: The key - part of the collider gridcell->index map, unsorted mDeviceColliderMapIndex, // output: The value-part of the collider gridcell->index map, unsorted deviceColliderPositions, // input: The collider positions (no integration), unsorted and possibly colliding with particles ¶msParticleSystem->gridParticleSystem, mPointCloudColliders->getRenderInfo()->at(0)->size // input: The number of colliders, one thread per particle ); //qDebug() << __PRETTY_FUNCTION__ << "6: computing collider spatial hash table finished at" << startTime.elapsed(); sortGridOccupancyMap(mDeviceColliderMapGridCell, mDeviceColliderMapIndex, mPointCloudColliders->getRenderInfo()->at(0)->size); //qDebug() << __PRETTY_FUNCTION__ << "7: sorting collider spatial hash table finished at" << startTime.elapsed(); sortParticlePosAndVelAccordingToGridCellAndFillCellStartAndEndArrays( mDeviceColliderCellStart, // output: At which index in mDeviceMapColliderIndex does cell X start? mDeviceColliderCellEnd, // output: At which index in mDeviceMapColliderIndex does cell X end? mDeviceColliderSortedPos, // output: The collider positions, sorted by gridcell 0, // output: The collider velocities, sorted by gridcell / they have no vel, so pass 0 mDeviceColliderMapGridCell, // input: The key - part of the collider gridcell->index map, unsorted mDeviceColliderMapIndex, // input: The value-part of the collider gridcell->index map, unsorted deviceColliderPositions, // input: The particle-positions, unsorted 0, // input: The particle-velocities, unsorted / they have no vel, so pass 0 mPointCloudColliders->getRenderInfo()->at(0)->size, // input: The number of colliders mParametersSimulation->gridParticleSystem.cells.x * mParametersSimulation->gridParticleSystem.cells.y * mParametersSimulation->gridParticleSystem.cells.z // input: Number of grid cells ); cudaGraphicsUnmapResources(1, &mCudaVboResourceColliderPositions, 0); mUpdateMappingFromColliderToGridCell = false; } //qDebug() << __PRETTY_FUNCTION__ << "8: computing collider navigation tables and sorting particles finished at" << startTime.elapsed(); // process collisions between particles collideParticlesWithParticlesAndColliders( mDeviceParticleVel, // output: The particle velocities deviceParticlePositions, // output: The w-component is changed whenever a particle has hit a collider. Used just for visualization. mDeviceParticleCollisionPositions, // output: Every particle's position of last collision, or 0.0/0.0/0.0 if none occurred. mDeviceParticleSortedPos, // input: The particle positions, sorted by gridcell mDeviceParticleSortedVel, // input: The particle velocities, sorted by gridcell mDeviceParticleMapIndex, // input: The value-part of the particle gridcell->index map, sorted by gridcell mDeviceParticleCellStart, // input: At which index in mDeviceMapParticleIndex does cell X start? mDeviceParticleCellEnd, // input: At which index in mDeviceMapParticleIndex does cell X end? mDeviceColliderSortedPos, // input: The collider positions, sorted by gridcell mDeviceColliderMapIndex, // input: The value-part of the collider gridcell->index map, sorted by gridcell mDeviceColliderCellStart, // input: At which index in mDeviceMapColliderIndex does cell X start? mDeviceColliderCellEnd, // input: At which index in mDeviceMapColliderIndex does cell X end? mParametersSimulation->particleCount, // input: How many particles to collide against other particles (one thread per particle) mParametersSimulation->gridParticleSystem.cells.x * mParametersSimulation->gridParticleSystem.cells.y * mParametersSimulation->gridParticleSystem.cells.z // input: Number of grid cells ); //showCollisionPositions(); //qDebug() << __PRETTY_FUNCTION__ << "9: colliding particles finished at" << startTime.elapsed(); // Unmap at end here to avoid unnecessary graphics/CUDA context switch. // Once unmapped, the resource may not be accessed by CUDA until they // are mapped again. This function provides the synchronization guarantee // that any CUDA work issued before ::cudaGraphicsUnmapResources() // will complete before any subsequently issued graphics work begins. cudaGraphicsUnmapResources(1, &mCudaVboResourceParticlePositions, 0); size_t memTotal, memFree; cudaMemGetInfo(&memFree, &memTotal); //qDebug() << __PRETTY_FUNCTION__ << "finished," << startTime.elapsed() << "ms, fps:" << 1000.0f/startTime.elapsed() << "free mem:" << memFree / 1048576; }