void ClothDemo::InitializeDebugGui() { stiffness = 1; restlength = 3; tearlength = 10; frameSolvesPerFrame = 1; this->gridDisplay->ClickAndDrag = true; VerticalDebugMenu::WatchFloatSlider("Rest Length", &restlength, 0.5f, 10.0f); VerticalDebugMenu::WatchFloatSlider("Stiffness", &stiffness, 0.0f, 1.25f); VerticalDebugMenu::WatchFloatSlider("Solves/Frame", &frameSolvesPerFrame, 1, 4); Delegate f = Delegate(); f.bind(this, &ClothDemo::ResetParticles); VerticalDebugMenu::WatchButton("Reset", f); for(uint r = 0; r < DIMENSION; r++) { for(uint c = 0; c < DIMENSION; c++) { points[r][c] = ClothP(); if(r > 0) links_up[r][c] = ClothLink(&points[r - 1][c], &points[r][c], &restlength, &tearlength, &stiffness); if(c > 0) links_left[r][c] = ClothLink(&points[r][c - 1], &points[r][c], &restlength, &tearlength, &stiffness); DemoWindow::WatchPoint(&points[r][c].position, &points[r][c].imass, Qt::red); } } ResetParticles(); }
void Buttons( int id ) { cl_int status; switch( id ) { case GO: GLUI_Master.set_glutIdleFunc( Animate ); break; case RESET: Reset( ); ResetParticles( ); status = clEnqueueWriteBuffer( CmdQueue, dVel, CL_FALSE, 0, 4*sizeof(float)*NUM_PARTICLES, hVel, 0, NULL, NULL ); PrintCLError( status, "clEneueueWriteBuffer: " ); GLUI_Master.set_glutIdleFunc( NULL ); Glui->sync_live( ); glutSetWindow( MainWindow ); glutPostRedisplay( ); break; case QUIT: Quit( ); break; default: fprintf( stderr, "Don't know what to do with Button ID %d\n", id ); } }
void InitCL( ) { // see if we can even open the opencl Kernel Program // (no point going on if we can't): FILE *fp = fopen( CL_FILE_NAME, "r" ); if( fp == NULL ) { fprintf( stderr, "Cannot open OpenCL source file '%s'\n", CL_FILE_NAME ); return; } // 2. allocate the host memory buffers: cl_int status; // returned status from opencl calls // test against CL_SUCCESS // get the platform id: status = clGetPlatformIDs( 1, &Platform, NULL ); PrintCLError( status, "clGetPlatformIDs: " ); // get the device id: status = clGetDeviceIDs( Platform, CL_DEVICE_TYPE_GPU, 1, &Device, NULL ); PrintCLError( status, "clGetDeviceIDs: " ); // since this is an opengl interoperability program, // check if the opengl sharing extension is supported, // (no point going on if it isn't): // (we need the Device in order to ask, so can't do it any sooner than here) if( IsCLExtensionSupported( "cl_khr_gl_sharing" ) ) { fprintf( stderr, "cl_khr_gl_sharing is supported.\n" ); } else { fprintf( stderr, "cl_khr_gl_sharing is not supported -- sorry.\n" ); return; } // 3. create an opencl context based on the opengl context: cl_context_properties props[ ] = { CL_GL_CONTEXT_KHR, (cl_context_properties) wglGetCurrentContext( ), CL_WGL_HDC_KHR, (cl_context_properties) wglGetCurrentDC( ), CL_CONTEXT_PLATFORM, (cl_context_properties) Platform, 0 }; cl_context Context = clCreateContext( props, 1, &Device, NULL, NULL, &status ); PrintCLError( status, "clCreateContext: " ); // 4. create an opencl command queue: CmdQueue = clCreateCommandQueue( Context, Device, 0, &status ); if( status != CL_SUCCESS ) fprintf( stderr, "clCreateCommandQueue failed\n" ); // create the velocity array and the opengl vertex array buffer and color array buffer: delete [ ] hVel; hVel = new struct xyzw [ NUM_PARTICLES ]; glGenBuffers( 1, &hPobj ); glBindBuffer( GL_ARRAY_BUFFER, hPobj ); glBufferData( GL_ARRAY_BUFFER, 4 * NUM_PARTICLES * sizeof(float), NULL, GL_STATIC_DRAW ); glGenBuffers( 1, &hCobj ); glBindBuffer( GL_ARRAY_BUFFER, hCobj ); glBufferData( GL_ARRAY_BUFFER, 4 * NUM_PARTICLES * sizeof(float), NULL, GL_STATIC_DRAW ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); // unbind the buffer // fill those arrays and buffers: ResetParticles( ); // 5. create the opencl version of the opengl buffers: dPobj = clCreateFromGLBuffer( Context, 0, hPobj, &status ); PrintCLError( status, "clCreateFromGLBuffer (1)" ); dCobj = clCreateFromGLBuffer( Context, 0, hCobj, &status ); PrintCLError( status, "clCreateFromGLBuffer (2)" ); // 5. create the opencl version of the velocity array: dVel = clCreateBuffer( Context, CL_MEM_READ_WRITE, 4*sizeof(float)*NUM_PARTICLES, NULL, &status ); PrintCLError( status, "clCreateBuffer: " ); // 6. enqueue the command to write the data from the host buffers to the Device buffers: status = clEnqueueWriteBuffer( CmdQueue, dVel, CL_FALSE, 0, 4*sizeof(float)*NUM_PARTICLES, hVel, 0, NULL, NULL ); PrintCLError( status, "clEneueueWriteBuffer: " ); // 7. read the Kernel code from a file: fseek( fp, 0, SEEK_END ); size_t fileSize = ftell( fp ); fseek( fp, 0, SEEK_SET ); char *clProgramText = new char[ fileSize+1 ]; // leave room for '\0' for(int k = 0; k < fileSize; ++k) clProgramText[k] = ' '; // ugly hack to fix random charactor insertion problem size_t n = fread( clProgramText, 1, fileSize, fp ); clProgramText[fileSize] = '\0'; fclose( fp ); // create the text for the Kernel Program: char *strings[1]; strings[0] = clProgramText; Program = clCreateProgramWithSource( Context, 1, (const char **)strings, NULL, &status ); if( status != CL_SUCCESS ) fprintf( stderr, "clCreateProgramWithSource failed\n" ); delete [ ] clProgramText; // 8. compile and link the Kernel code: char *options = { "" }; status = clBuildProgram( Program, 1, &Device, options, NULL, NULL ); if( status != CL_SUCCESS ) { size_t size; clGetProgramBuildInfo( Program, Device, CL_PROGRAM_BUILD_LOG, 0, NULL, &size ); cl_char *log = new cl_char[ size ]; clGetProgramBuildInfo( Program, Device, CL_PROGRAM_BUILD_LOG, size, log, NULL ); fprintf( stderr, "clBuildProgram failed:\n%s\n", log ); delete [ ] log; } // 9. create the Kernel object: Kernel = clCreateKernel( Program, "Particle", &status ); PrintCLError( status, "clCreateKernel failed: " ); // 10. setup the arguments to the Kernel object: status = clSetKernelArg( Kernel, 0, sizeof(cl_mem), &dPobj ); PrintCLError( status, "clSetKernelArg (1): " ); status = clSetKernelArg( Kernel, 1, sizeof(cl_mem), &dVel ); PrintCLError( status, "clSetKernelArg (2): " ); status = clSetKernelArg( Kernel, 2, sizeof(cl_mem), &dCobj ); PrintCLError( status, "clSetKernelArg (3): " ); }
//------------------------------------------------------------------------ void CVehicleMovementStdBoat::UpdateSurfaceEffects(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); if (0 == g_pGameCVars->v_pa_surface) { ResetParticles(); return; } IEntity* pEntity = m_pVehicle->GetEntity(); const Matrix34& worldTM = pEntity->GetWorldTM(); float distSq = worldTM.GetTranslation().GetSquaredDistance(gEnv->pRenderer->GetCamera().GetPosition()); if (distSq > sqr(300.f) || (distSq > sqr(50.f) && !m_pVehicle->GetGameObject()->IsProbablyVisible())) return; Matrix34 worldTMInv = worldTM.GetInverted(); const SVehicleStatus& status = m_pVehicle->GetStatus(); float velDot = status.vel * worldTM.GetColumn1(); float powerNorm = min(abs(m_movementAction.power), 1.f); SEnvironmentParticles* envParams = m_pPaParams->GetEnvironmentParticles(); SEnvParticleStatus::TEnvEmitters::iterator end = m_paStats.envStats.emitters.end(); for (SEnvParticleStatus::TEnvEmitters::iterator emitterIt = m_paStats.envStats.emitters.begin(); emitterIt!=end; ++emitterIt) { if (emitterIt->layer < 0) { assert(0); continue; } const SEnvironmentLayer& layer = envParams->GetLayer(emitterIt->layer); SEntitySlotInfo info; info.pParticleEmitter = 0; pEntity->GetSlotInfo(emitterIt->slot, info); float countScale = 1.f; float sizeScale = 1.f; float speedScale = 1.f; float speed = 0.f; // check if helper position is beneath water level Vec3 emitterWorldPos = worldTM * emitterIt->quatT.t; float waterLevel = gEnv->p3DEngine->GetWaterLevel(&emitterWorldPos); int matId = 0; if (emitterWorldPos.z <= waterLevel+0.1f && m_physStatus[k_mainThread].submergedFraction<0.999f) { matId = gEnv->pPhysicalWorld->GetWaterMat(); speed = status.speed; bool spray = !strcmp(layer.GetName(), "spray"); if (spray) { // slip based speed -= abs(velDot); } GetParticleScale(layer, speed, powerNorm, countScale, sizeScale, speedScale); } else { countScale = 0.f; } if (matId && matId != emitterIt->matId) { // change effect IParticleEffect* pEff = 0; const char* effect = GetEffectByIndex( matId, layer.GetName() ); if (effect && (pEff = gEnv->pParticleManager->FindEffect(effect))) { #if ENABLE_VEHICLE_DEBUG if (DebugParticles()) CryLog("%s changes water sfx to %s (slot %i)", pEntity->GetName(), effect, emitterIt->slot); #endif if (info.pParticleEmitter) { info.pParticleEmitter->Activate(false); pEntity->FreeSlot(emitterIt->slot); } emitterIt->slot = pEntity->LoadParticleEmitter(emitterIt->slot, pEff); if (emitterIt->slot != -1) pEntity->SetSlotLocalTM(emitterIt->slot, Matrix34(emitterIt->quatT)); info.pParticleEmitter = 0; pEntity->GetSlotInfo(emitterIt->slot, info); } else countScale = 0.f; } if (matId) emitterIt->matId = matId; if (info.pParticleEmitter) { SpawnParams sp; sp.fSizeScale = sizeScale; sp.fCountScale = countScale; sp.fSpeedScale = speedScale; info.pParticleEmitter->SetSpawnParams(sp); if (layer.alignToWater && countScale > 0.f) { Vec3 worldPos(emitterWorldPos.x, emitterWorldPos.y, waterLevel+0.05f); Matrix34 localTM(emitterIt->quatT); localTM.SetTranslation(worldTMInv * worldPos); pEntity->SetSlotLocalTM(emitterIt->slot, localTM); } } #if ENABLE_VEHICLE_DEBUG if (DebugParticles() && m_pVehicle->IsPlayerDriving()) { float color[] = {1,1,1,1}; ColorB red(255,0,0,255); IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom(); const char* effect = info.pParticleEmitter ? info.pParticleEmitter->GetName() : ""; const Matrix34& slotTM = m_pEntity->GetSlotWorldTM(emitterIt->slot); Vec3 ppos = slotTM.GetTranslation(); pAuxGeom->DrawSphere(ppos, 0.2f, red); pAuxGeom->DrawCone(ppos, slotTM.GetColumn1(), 0.1f, 0.5f, red); gEnv->pRenderer->Draw2dLabel(50.f, (float)(400+10*emitterIt->slot), 1.2f, color, false, "<%s> water fx: slot %i [%s], speed %.1f, sizeScale %.2f, countScale %.2f (pos %.0f,%0.f,%0.f)", pEntity->GetName(), emitterIt->slot, effect, speed, sizeScale, countScale, ppos.x, ppos.y, ppos.z); } #endif } // generate water splashes Vec3 wakePos; if(m_pSplashPos) { wakePos = m_pSplashPos->GetWorldSpaceTranslation(); } else { wakePos = worldTM.GetTranslation(); } float wakeWaterLevel = gEnv->p3DEngine->GetWaterLevel(&wakePos); const Vec3& localW = m_localSpeed; if (localW.x >= 0.f) m_diving = false; if (!m_diving && localW.x < -0.03f && status.speed > 10.f && wakePos.z < m_lastWakePos.z && wakeWaterLevel+0.1f >= wakePos.z) { float speedRatio = min(1.f, status.speed/(m_maxSpeed*m_factorMaxSpeed)); m_diving = true; if (m_pWaveEffect) { if (IParticleEmitter* pEmitter = pEntity->GetParticleEmitter(m_wakeSlot)) { pEmitter->Activate(false); pEntity->FreeSlot(m_wakeSlot); m_wakeSlot = -1; } SpawnParams spawnParams; spawnParams.fSizeScale = spawnParams.fCountScale = 0.5f + 0.25f*speedRatio; spawnParams.fSizeScale += 0.4f*m_waveRandomMult; spawnParams.fCountScale += cry_random(0.0f, 0.4f); m_wakeSlot = pEntity->LoadParticleEmitter(m_wakeSlot, m_pWaveEffect, &spawnParams); } // handle splash sound ExecuteTrigger(eSID_Splash); SetSoundParam(eSID_Splash, "intensity", 0.2f*speedRatio + 0.5f*m_waveRandomMult); if (m_rpmPitchDir == 0) { m_rpmPitchDir = -1; m_waveSoundPitch = 0.f; m_waveSoundAmount = 0.02f + m_waveRandomMult*0.08f; } } if (m_wakeSlot != -1) { // update emitter local pos to short above waterlevel Matrix34 tm; if(m_pSplashPos) m_pSplashPos->GetVehicleTM(tm); else tm.SetIdentity(); Vec3 pos = tm.GetTranslation(); pos.z = worldTMInv.TransformPoint(Vec3(wakePos.x,wakePos.y,wakeWaterLevel)).z + 0.2f; tm.SetTranslation(pos); pEntity->SetSlotLocalTM(m_wakeSlot, tm); #if ENABLE_VEHICLE_DEBUG if (IsProfilingMovement()) { Vec3 wPos = worldTM * tm.GetTranslation(); ColorB col(128, 128, 0, 200); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(wPos, 0.4f, col); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(wPos, col, wPos+Vec3(0,0,1.5f), col); } #endif } m_lastWakePos = wakePos; }
bool FireBallParticles::Update(FXMVECTOR newPos, float fireballRadius, float dt, ID3D11DeviceContext* context) { if (!mProperties.isFire || mIsAllParticlesDead) { return true; } XMVECTOR nPos = newPos; if (mTweenPoints.size() > 0) { nPos = XMLoadFloat3(&mCurrTweenPoint); UpdateCurrentTweenPoint(dt); } XMFLOAT3 fVel3; float pSize; bool isParticleStillAlive = false; for (int i = 0; i < mFireBallParticles.size(); ++i) { XMVECTOR pos = XMLoadFloat3(&mFireBallParticles[i].pos); XMVECTOR vel = XMLoadFloat3(&mFireBallParticles[i].vel); mFireBallParticles[i].age += dt; if (mProperties.isOneShot && (mFireBallParticles[i].age >= mFireBallParticles[i].lifetime)) { continue; } else if (mFireBallParticles[i].age <= mFireBallParticles[i].lifetime) { isParticleStillAlive = true; } else if (!mProperties.isOneShot && (mFireBallParticles[i].age >= mFireBallParticles[i].lifetime)) { isParticleStillAlive = true; vel = XMVector3Normalize(XMVectorSet(MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), 0.0f)) * fireballRadius; XMStoreFloat3(&mFireBallParticles[i].pos, nPos + vel); fVel3 = GetVelocity(); vel = XMVector3Normalize(XMVectorSet(fVel3.x, fVel3.y, fVel3.z, 0.0f)); float speedMult = GetSpeedMultiplier(); if (MathHelper::RandF() > 0.50f) { if (MathHelper::RandF() > 0.50f) { vel.m128_f32[0] += MathHelper::RandF(-0.4f, 0.4f); //vel.m128_f32[0] *= MathHelper::RandF(-0.06f, 0.06f); //vel.m128_f32[2] *= MathHelper::RandF(-0.06f, 0.06f); } else { vel.m128_f32[2] += MathHelper::RandF(-0.4f, 0.4f); //vel.m128_f32[0] *= MathHelper::RandF(-0.06f, 0.06f); //vel.m128_f32[2] *= MathHelper::RandF(-0.06f, 0.06f); } } XMStoreFloat3(&mFireBallParticles[i].vel, vel * speedMult); pSize = GetSize(); mFireBallParticles[i].size.x = pSize; mFireBallParticles[i].size.y = pSize; mFireBallParticles[i].age = 0.0f; mFireBallParticles[i].lifetime = GetLifetime(); pos = XMLoadFloat3(&mFireBallParticles[i].pos); vel = XMLoadFloat3(&mFireBallParticles[i].vel); } if (pos.m128_f32[1] < (nPos.m128_f32[1] + (fireballRadius * 0.60f))) { XMVECTOR s1Center = nPos; float s1Radius = fireballRadius; float currOverLap = 0.0f; XMVECTOR correction = XMVectorZero(); XMVECTOR d = s1Center - pos; float distance = sqrt((d.m128_f32[0] * d.m128_f32[0]) /*+ (d.m128_f32[1] * d.m128_f32[1])*/ + (d.m128_f32[2] * d.m128_f32[2])); //Magnitude of the difference float overLap = s1Radius - distance; if (overLap > currOverLap) // Have Collision { currOverLap = overLap; correction = XMVector3Normalize(d) * currOverLap; //correct collision by moving sphere out of box } pos += correction; } pos = pos + vel; XMStoreFloat3(&mFireBallParticles[i].pos, pos); } if (isParticleStillAlive) { UpdateFireBallParticleVB(context); } else { mIsAllParticlesDead = true; if (mProperties.isOneShot) { ResetParticles(); } } return false; }