Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
When building Ogre applications that simulate an outdoor environment, we often need to control weather conditions. In this recipe, we'll build an application with controls that change the parameters of a particle system to simulate different rain-like conditions. We'll also use sound in our application to enhance the rain effect.
Add the sounds folder, which contains nature sounds, such as rain and thunder, in your media folder.
To follow along with this recipe, open the solution located in the Recipes/Chapter04 folder in the code bundle available on the Packt website.
WeatherConditions, by following the Creating an MFC Ogre application recipe, in Chapter 1,m_cpVoice.CoCreateInstance(CLSID_SpVoice);
void CWeatherControlView::OnWeatherControlRain() {
Ogre::SceneNode *RainNode = NULL;
if (!m_SceneManager->hasParticleSystem("Rain")) {
m_Rain = m_SceneManager->createParticleSystem("Rain",
"Examples/Rain");
if (m_Rain != NULL) {
RainNode = m_SceneManager->
getRootSceneNode()->createChildSceneNode("RainNode");
RainNode->attachObject(m_Rain);
m_Rain->setVisible(false);
}
}
if (m_RainControlDlg == NULL) {
m_RainControlDlg = new CRainControlDlg();
m_RainControlDlg->Create(IDD_RAIN_CONTROL);
}
m_RainControlDlg->ShowWindow(SW_SHOW);
}
Using this dialog-box, we can start and stop the rain, control particle dimensions, and enable or disable rain sounds.
OnHScroll that handles the WM_HSCROLL message. The WM_HSCROLL message is sent when a click is detected in a horizontal scroll bar. Inside the OnHScroll, we simply check the position of the particle width and height controls, and modify the particle system with the updated values.void CRainControlDlg::OnHScroll(UINT nSBCode, UINT nPos,
CScrollBar* pScrollBar) {
CMainFrame *MainFrame = (CMainFrame *)((
CWeatherControlApp*)AfxGetApp())->GetMainWnd();
CWeatherControlView *View =
(CWeatherControlView *)MainFrame->GetActiveView();
int ParticleWidth = m_ParticleWidth.GetPos();
int ParticleHeight = m_ParticleHeight.GetPos();
View->m_Rain->setDefaultDimensions(ParticleWidth,
ParticleHeight);
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}
OnClickAction to the Start/Stop button to handle the click event. Inside OnClickAction, we toggle the rain visibility and rain sounds.View->m_Rain->setVisible(!View->m_Rain->getVisible());
if (View->m_Rain->getVisible()) {
m_Action.SetWindowTextA("Stop");
View->SetTimer(ID_RAIN_TIMER, 1, 0);
}
else {
m_Action.SetWindowTextA("Start");
View->KillTimer(ID_RAIN_TIMER);
WeatherControlApp->m_cpVoice->Pause();
}
We also start or stop the ID_RAIN_TIMER to toggle rain sounds in our OnTimer() function that gets called every time we receive a timer message.
ON_WM_TIMER message handler to CWeatherControlView, and name it OnTimer. In the OnTimer member function, we will play rain sounds and render the scene when we receive the ID_RAIN_TIMER timer event.SoundPath += L"\\..\\..\\media\\sounds\\rain\\rain storm.wav";
CWeatherControlApp* WeatherControlApp = (CWeatherControlApp*)AfxGetApp();
CComPtr<ISpVoice> Voice = WeatherControlApp->m_cpVoice;
CComPtr<ISpStream> cpWavStream;
switch (nIDEvent) {
case ID_RAIN_TIMER:
if (m_RainControlDlg != NULL){
if (m_RainControlDlg->m_PlaySound && m_Rain->getVisible()) {
SPBindToFile(SoundPath, SPFM_OPEN_READONLY, &cpWavStream);
Voice->Resume();
Voice->SpeakStream(cpWavStream, SPF_ASYNC, NULL);
}
else {
Voice->Pause();
}
}
Root->renderOneFrame();
The SPBindToFile function binds the audio stream to the specified file, and SpeakStream plays the contents of the stream. In our case, when we receive an ID_RAIN_TIMER event, we play the rain sound.
The settings for our Examples/Rain particle system reside in the media/particle/Examples.particle file. The .particle file is just a text file and the settings are detailed in the Ogre online manual:
particle_system Examples/Rain
{
material Examples/Droplet
particle_width 20
particle_height 100
cull_each true
quota 10000
// Make common direction straight down (faster than self oriented)
billboard_type oriented_common
common_direction 0 -1 0
// Area emitter
emitter Box
{
angle 0
emission_rate 100
time_to_live 5
direction 0 -1 0
velocity 50
width 1000
height 1000
depth 0
}
// Gravity
affector LinearForce
{
force_vector 0 -200 0
force_application add
}
}
The rain particle effect uses a box emitter, so all the particles originate from a flat 1000x1000 box. Note that we use the Y-axis as the up and down axis in our example, and our material is the Examples/Droplet material found in the media/materials/scripts/Examples.material file.
material Examples/Droplet{
technique {
pass {
emissive 0.3 0.3 0.3
scene_blend colour_blend
depth_write off
diffuse vertexcolour
texture_unit {
texture basic_droplet.png
}
}
}
}
When you run the program and turn on the rain effect, you can see the rain particles falling on our robot overlord.