0% found this document useful (0 votes)
277 views31 pages

Chapter 4 Let There Be Light Sample Chapter

Chapter No. 4 - Let There Be Light Over 50 recipes to provide world-class 3D graphics solutions with OGRE 3D

Uploaded by

jagdevs7234
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
277 views31 pages

Chapter 4 Let There Be Light Sample Chapter

Chapter No. 4 - Let There Be Light Over 50 recipes to provide world-class 3D graphics solutions with OGRE 3D

Uploaded by

jagdevs7234
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 31

OGRE 3D 1.

7 Application Development Cookbook

Ilya Grinblat Alex Peterson

Chapter No. 4 "Let There Be Light"

In this package, you will find:


A Biography of the author of the book A preview chapter from the book, Chapter NO.4 "Let There Be Light" A synopsis of the books content Information on where to buy this book

About the Author


Ilya Grinblat started to work 35 years ago as developer of control systems, and some years later, he moved to the development of Computer Aided Design software. He was a development manager of the architectural software ARC+, and was working in the development of the 3D city softwarea software for 3D editing and management of a 3D printer. Last year, he was working in the development of simulators and the 3D GIS software. He was using Ogre to develop Civil Simulatea software for 3D modeling of roads and driving simulation. I would like to thank many people from Packt publishing. I would also like to thank my wife Irena for giving me the time and support to write this book.

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Alex Peterson is a graphics enthusiast with a background in game programming. His work with the Ogre engine is primarily due to programming a universe size game engine, a space skybox creator called Spacescape, and most recently, mobile games. Though his current life is filled with his family and running a business, he makes it a point be active musically and spiritually. He aims to promote his faith in God through his work to serve others, whether it is by fueling their creativity, entertaining them, or educating them. You . can find Alex online at I would like to thank my Father, my family, my wife Lydia, the Ogre development team, Steve Streeting, the Ogre forum moderators, Sean O'Neil, Chris, Ava Barneys, and all the kind people who have helped me be a part of this work. Thank you.

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

OGRE 3D 1.7 Application Development Cookbook


Harnessing the power of an elaborate graphics engine, such as Ogre 3D is timeconsuming, but a highly rewarding pursuit. Developers, over the world, attest to Ogre's elegance, versatility, and efficiency, not to mention that its code is open source and supported by a thriving online community. This book explores many useful and fun ways to leverage Ogre 3D, to make your graphics application fully-featured and entertaining.

What This Book Covers


Chapter 1, Delving Deep into Application Design, covers how to create various types of basic Ogre 3D Windows applications and plugins. Chapter 2, Let us be Multimodal, shows how to use the keyboard, the mouse, and the voice input to control a 3D application. Chapter 3, Managing Objects and Scenes, contains recipes to build a rudimentary Ogre 3D scene editor in which you can create various types of meshes, terrain, and save the scene information to an XML file. Chapter 4, Let There Be Light, explores lighting, shadows, and particle effects. Chapter 5, Playing with Materials, covers advanced techniques to manipulate materials and textures, using Ogre 3D. Chapter 6, Learning to Move, provides methods for moving meshes in a scene and basic collision detection. Chapter 7, Implementing Animations, covers skeletal, morph, and pose animations. It also covers various methods of animating programmatically, using controllers. Chapter 8, Flashy Multimedia, shows how to render to texture, and use audio and video in Ogre 3D. Chapter 9, Queries and Views, covers selecting objects in a scene with the mouse and zooming with the camera.

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light


In this chapter, we will cover the following recipes:

Creating weather controls Creating lights Creating dynamic effects Managing particle systems Managing shadows

Introduction
In this chapter, we'll explore some of the dynamic features of Ogre, such as particle systems, lights, and shadows. All of the dynamic features that we show you in this chapter can be manipulated with code to increase the realism of the effects or the artistic quality. Particle systems, in particular, are designed to change dynamically over time to achieve effects, such as sparks, explosions, or even a waterfall. Similarly, we can manipulate a light dynamically if we want to simulate the ickering of a re.

Creating weather controls


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.

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light

Getting ready
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.

How to do it...
1. First, create a new Ogre MFC application named WeatherConditions, by following the Creating an MFC Ogre application recipe, in Chapter 1, Delving Deep into Application Design. 2. Next, create a SAPI voice.
m_cpVoice.CoCreateInstance(CLSID_SpVoice);

3. Create a submenu named Weather Control in the main menu. Then, add commands: Rain, Snow, Fog, Sky, and Sun to the submenu. For this recipe, we will only be implementing the rain functionality, but it will be easy to complete the other controls, once you see how the rain is implemented.

4. Next, add an event handler to the Rain submenu item using the Event Handler Wizard.
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->

108

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4 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); }

5. In the Rain submenu event handler, we create the rain particle system and the Rain Control dialog-box, and then show it. 6. Create the Rain Control dialog-box using the Dialog Editor.

Using this dialog-box, we can start and stop the rain, control particle dimensions, and enable or disable rain sounds. 6. Now that we've created the dialog-box, we need to add the event handler code for the dialog-box controls. Add a message handler to the Rain Control dialog-box called 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();

109

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light


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); }

7.

Next, add an event handler named 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. 8. To handle the timer messages, add an 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()) {
110

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4 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 specied le, and SpeakStream plays the contents of the stream. In our case, when we receive an ID_RAIN_TIMER event, we play the rain sound.

How it works...
The settings for our Examples/Rain particle system reside in the media/particle/ Examples.particle le. The .particle le is just a text le 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 emission_rate time_to_live direction velocity width height depth } // Gravity
111

0 100 5 0 -1 0 50 1000 1000 0

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light


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 at 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 le.
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.

112

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4

There's more...
You can add additional elements to the Rain Control dialog-box to control other parameters of the rain particle system, such as the speed or the color. By adding dialog-boxes for each weather control, we can create a full-scale weather editor.

Creating lights
In Ogre, when you create a light, you are dening the origin and color for a light, but there is no visible representation of an object casting light in the scene, such as a light bulb, or a window, or TV screen. In this recipe, we'll show you how to create those illuminated objects that represent the light source object in a 3D scene.

Getting ready
First, add Wall.material to media\materials\scripts, and then add the White.jpg, Grey.jpg, Yellow.jpg, and Black.jpg textures to the media\materials\textures 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.

How to do it...
1. First, create an MFC Ogre application named Lights. 2. Next, in LightsView::EngineSetup(), add a spotlight can and a light beam, to represent the light from the spotlight, hitting particles in the air.
// spotlight can CCone ConeObject; ConeObject.m_Height = 20.0; ConeObject.m_Radius = 10.0; Ogre::ManualObject *Can = ConeObject.CreateCone(0,"SpotLightLight","Wall/Black"); Ogre::SceneNode *CanNode = SceneManager->getRootSceneNode()-> createChildSceneNode(Ogre::Vector3(100.0, 181.0, 0.0)); //Can->setCastShadows(true); CanNode->attachObject(Can); // spotlight beam ConeObject.m_Height = 200.0; ConeObject.m_Radius = 80.0; Ogre::ManualObject *Beam = ConeObject.CreateCone(0.99,"SpotLightBeam","LightBeam",0.5);
113

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light


Ogre::SceneNode *BeamNode = SceneManager->getRootSceneNode()-> createChildSceneNode(Ogre::Vector3(100.0, 0.0, 0.0)); Beam->setCastShadows(false); BeamNode->attachObject(Beam); // spotlight light Ogre::Light* SpotLight = SceneManager->createLight("SpotLight"); SpotLight->setDirection((Ogre::Vector3(0.0, 0.0, 0.0) Ogre::Vector3(0.0, 100.0, 0.0)).normalisedCopy()); SpotLight->setType(Ogre::Light::LT_SPOTLIGHT); SpotLight->setDiffuseColour(1.0, 1.0, 0.0); SpotLight->setSpecularColour(1.0, 1.0, 0.0); //SpotLight->setAttenuation(150, 1.0, 0.005, 0.0); SpotLight->setSpotlightRange( Ogre::Radian(0.5),Ogre::Radian(0.9),2.0f); SpotLight->setVisible(true); Ogre::SceneNode *LightNode = SceneManager->getRootSceneNode()-> createChildSceneNode("SpotLight"); LightNode->attachObject(SpotLight); LightNode->setPosition(Ogre::Vector3(100.0,199,0.0));

We position the light beam cone and the spotlight, just under the can. 3. Next, create a point light and a are billboard sprite as its visual representation.
// point light Ogre::Light* PointLight = SceneManager->createLight("PointLight"); PointLight->setType(Ogre::Light::LT_POINT); PointLight->setDiffuseColour(1.0, 0.0, 0.0); PointLight->setSpecularColour(1.0, 0.0, 0.0); PointLight->setVisible(true); PointLight->setAttenuation(3250.0,1.0,0.0014,0.000007); Ogre::SceneNode *PointLightNode = SceneManager-> getRootSceneNode()->createChildSceneNode("PointLight"); PointLightNode->attachObject(PointLight); PointLightNode->setPosition(Ogre::Vector3(-100.0,150,30.0)); // attach a flare to the point light node Ogre::BillboardSet* FlareSet = SceneManager-> createBillboardSet("FlareSet"); FlareSet->setMaterialName("Examples/FlarePointSprite"); FlareSet->setDefaultDimensions(50.0,50.0); Ogre::Billboard* Flare = FlareSet->createBillboard( Ogre::Vector3(0,0,0),Ogre::ColourValue(1.0,0.0,0.0,0.5)); PointLightNode->attachObject(FlareSet);
114

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4

4. Finally, add a couple dangerous robots under each light and a ground plane.
// floor mesh Ogre::Plane Floor(Ogre::Vector3::UNIT_Y, 0); Ogre::MeshPtr WallMesh = Ogre::MeshManager::getSingleton().createPlane("Floor", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Floor, 1000,1000,100,100,true,1,5,5, Ogre::Vector3::UNIT_Z); Ogre::Entity *FloorEntity = SceneManager->createEntity("Floor", "Floor"); FloorEntity->setCastShadows(false); Ogre::SceneNode *FloorNode = SceneManager->getRootSceneNode()-> createChildSceneNode("Floor"); FloorNode->attachObject(FloorEntity); Ogre::Entity *RobotEntity = SceneManager->createEntity("Robot", "robot.mesh"); Ogre::SceneNode *RobotNode = SceneManager->getRootSceneNode()-> createChildSceneNode(Ogre::Vector3(100.0,00.0,0.0)); RobotNode->yaw(-Ogre::Radian(Ogre::Math::HALF_PI)); RobotEntity->setCastShadows(true); RobotNode->attachObject(RobotEntity); Ogre::Entity *RobotEntity2 = SceneManager->createEntity("Robot2", "robot.mesh"); Ogre::SceneNode *RobotNode2 = SceneManager->getRootSceneNode()-> createChildSceneNode(Ogre::Vector3(-100.0,00.0,0.0)); RobotNode2->yaw(-Ogre::Radian(Ogre::Math::HALF_PI)); RobotEntity2->setCastShadows(true); RobotNode2->attachObject(RobotEntity2);

How it works...
In Ogre 3D, there are three types of lights: point lights, spot lights, and directional lights. In this recipe, we use a transparent cone to represent the light from the spot light, hitting air particles. To accomplish this, we create a cone mesh using an Ogre::ManualObject with each vertex having an alpha value based on the height of the vertex. This way, the vertices at the bottom of the spot light cone are fully transparent, and vertices at the top of the cone are less transparent.
Cone->colour(Intensity, Intensity, 0.0, ((Ogre::Real) HeightSegmentIndex / (Ogre::Real)m_HeightSegments) * fadeAmount);

115

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light The alpha value for each vertex in the cone is also multiplied by some variable fadeAmount. For this recipe, we set the fadeAmount to 0.5, so that the top of the cone is not opaque. For the point light, we use a are sprite tinted red that always faces the camera. This is the most common approach for making light sources visible. We make use of the Ogre::BillboardSet and the Ogre::Billboard classes to create ares that will always face the camera, because Ogre will adjust the billboard positions for every frame for us. The Ogre::BillboardSet class is also very efcient at managing and rendering many billboards at once.

Our robot overlords sure know how to get their mood on!

There's more...
Our recipe does not have a are for the spotlight. Create another are for the spotlight, then make the transparency of each are dependent on the view angle from the camera to the are, so that, when looking directly at the are, it is most visible, but as the camera looks away from the are, it becomes less visible. Ideally, the are for the spotlight should only be visible from under the spotlight. The directional light, not shown in this recipe, is a good choice for representing the sun or moon, which also can be represented with a billboard sprite that always faces the camera.
116

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4

See also
In this chapter:

Creating dynamic effects

Creating dynamic effects


In this recipe, we'll show you how to dynamically adjust the intensity of a spotlight beam, based on the camera's view angle. Our goal is to render a spotlight beam that is barely visible when the camera angle is perpendicular to the angle of the spotlight beam, and we want the spotlight beam to be most visible when the camera is directly in the spotlight beam, looking at it.

Getting ready
To follow along with this recipe, open the solution located in the Recipes/Chapter04 folder in the code bundle available on the Packt website.

How to do it...
1. First, create an MFC Ogre application named DynamicEffects. 2. Next, add an Ogre::Light member variable to the CDynamicEffectsView class, and then initialize it in CDynamicEffectsView::EngineSetup().
Ogre::AxisAlignedBox Box(-1000, -1000, -1000, 1000, 1000, 1000); Ogre::Vector3 Center = Box.getCenter(); Light = SceneManager->createLight(); m_Camera->setPosition(Ogre::Vector3(25.0, 25.0, 25.0)); m_Camera->setDirection((Ogre::Vector3(0.0, 100.0, 0.0) m_Camera->getPosition()).normalisedCopy()); Light->setDirection((Ogre::Vector3(0.0, 100.0, 0.0) Ogre::Vector3(0.0, 0.0, 0.0)).normalisedCopy()); Ogre::Real Intensity = m_Camera->getDirection().dotProduct( Light->getDirection()); Ogre::SceneNode* lightNode = SceneManager->getRootSceneNode()-> createChildSceneNode(Center); Light->setType(Ogre::Light::LT_SPOTLIGHT); Light->setVisible(true);
117

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light


Light->setPosition(Ogre::Vector3(0.0, 100.0, 0.0)); Light->setSpotlightOuterAngle(Ogre::Radian(0.4)); Light->setDiffuseColour(Intensity, Intensity, 0.0); Light->setSpecularColour(Intensity, Intensity, 0.0); lightNode->attachObject(Light);

3. After creating the light, we set its type to Ogre::Light::LT_SPOTLIGHT, and attach it to the scene graph. 4. Next, add the Cone.cpp and the Cone.h les from the example project, and then create a new CCone object in CDynamicEffectsView::EngineSetup().
CCone ConeObject; Cone = ConeObject.CreateCone(Intensity); Ogre::SceneNode *ConeNode = SceneManager->getRootSceneNode()-> createChildSceneNode(Ogre::Vector3(0.0, 100.0, 0.0)); ConeNode->attachObject(Cone);

The cone mesh object will represent our spotlight beam in the scene. 5. Now that we have all the graphical elements we need in the scene, it's time to add controls, so that we can move the camera. Add an integer member variable named m_WorkingTimer to CDynamicEffectsView. 6. Next, add a handler for the ON_WM_KEYDOWN message named CDynamicEffectsV iew::OnKeyDown().
m_WorkingTimer = 0; switch case case case (nChar) { VK_LEFT: //left 65: //A 97: //a

m_WorkingTimer = 1; break; case VK_UP: //up case 87: //W case 119: //w m_WorkingTimer = 2; break; case VK_RIGHT: //right
118

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4 case 68: //D case 100: //d m_WorkingTimer = 3; break; case VK_DOWN: //down case 83: //S case 115://s m_WorkingTimer = 4; break; } if (m_WorkingTimer != 0) SetTimer(m_WorkingTimer, 10, NULL);

In OnKeyDown, we set a different working timer value, depending on which key is down. 7. Next, add a handler for the ON_WM_KEYUP message named CDynamicEffectsView::OnKeyUP().
KillTimer(m_WorkingTimer); CView::OnKeyUp(nChar, nRepCnt, nFlags);

Here' we kill the m_WorkingTimer, so we stop generating WM_TIMER messages. 8. Next, add a handler for the ON_WM_TIMER message named CDynamicEffectsVie w::OnTimer().
CEngine *Engine = ((CDynamicEffectsApp*)AfxGetApp())->m_Engine; if (Engine == NULL) return; Ogre::Root *Root = Engine->GetRoot(); if (Root == NULL) { return; } Ogre::Vector3 CameraMove; switch (nIDEvent) {
119

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light


case 1: CameraMove[0] = -1; CameraMove[1] = 0; CameraMove[2] = 0; break; case 2: CameraMove[0] = 0; CameraMove[1] = 1; CameraMove[2] = 0; break; case 3: CameraMove[0] = 1; CameraMove[1] = 0; CameraMove[2] = 0; break; case 4: CameraMove[0] = 0; CameraMove[1] = -1; CameraMove[2] = 0; break; }

9. First, we check the timer event ID, and set the CameraMove variable appropriately, to move the camera in the right direction. 10. Next, we calculate the dot product between camera direction and the spotlight direction. The spotlight intensity is proportional to this dot product.
m_Camera->moveRelative(CameraMove); m_Camera->setDirection((Light->getPosition() - m_Camera-> getPosition()).normalisedCopy()); Ogre::Real Intensity = m_Camera->getDirection().dotProduct(Light-> getDirection()); Light->setDiffuseColour(Intensity, Intensity, 0.0); Light->setSpecularColour(Intensity, Intensity, 0.0);
120

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4

11. Next, we update the vertex colors for the spotlight beam, so that their intensity matches the spotlight intensity.
int numSegBase = 24; int numSegHeight = 24; Ogre::Real radius = 10.0; Ogre::Real height = 20.0; Cone->beginUpdate(0); Ogre::Real deltaAngle = (Ogre::Math::TWO_PI / numSegBase); Ogre::Real deltaHeight = height/(Ogre::Real)numSegHeight; Ogre::Real uTile = 1.0; Ogre::Real vTile = 1.0; Ogre::Vector3 refNormal = Ogre::Vector3(radius, height, 0.f).normalisedCopy(); Ogre::Quaternion q; int offset = 0; for (int i = 0; i <=numSegHeight; i++) { Ogre::Real r0 = radius * (1 - i / (Ogre::Real)numSegHeight); for (int j = 0; j<=numSegBase; j++) { Ogre::Real x0 = r0* cosf(j * deltaAngle); Ogre::Real z0 = r0 * sinf(j * deltaAngle); Cone->position(x0, i * deltaHeight, z0); Cone->colour(Intensity, Intensity, 0.0, 0.0); q.FromAngleAxis(Ogre::Radian(-j*deltaAngle), Ogre::Vector3::NEGATIVE_UNIT_Y); Cone->normal(q*refNormal); Cone->textureCoord(j / (Ogre::Real)numSegBase * uTile, i / (Ogre::Real)numSegHeight * vTile); if (i != numSegHeight&& j != numSegBase) { Cone->index(offset + numSegBase + 2); Cone->index(offset); Cone->index(offset + numSegBase + 1); Cone->index(offset + numSegBase + 2); Cone->index(offset + 1); Cone->index(offset); } offset ++; }
121

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light


} /**/ //low cap int centerIndex = offset; Cone->position(0,0,0); Cone->normal(Ogre::Vector3::NEGATIVE_UNIT_Y); Cone->textureCoord(0.0,vTile); offset++; for (int j=0; j<=numSegBase; j++) { Ogre::Real x0 = radius * cosf(j*deltaAngle); Ogre::Real z0 = radius * sinf(j*deltaAngle); Cone->position(x0, 0.0f, z0); Cone->colour(Intensity, Intensity, 0.0, 0.0); Cone->normal(Ogre::Vector3::NEGATIVE_UNIT_Y); Cone->textureCoord(j/(Ogre::Real)numSegBase*uTile,0.0); if (j!=numSegBase) { Cone->index(centerIndex); Cone->index(offset); Cone->index(offset+1); } offset++; } /**/ Cone->end();

How it works...
Each time we render a frame, we calculate the dot product of the spotlight direction vector and the camera view vector, and use that value to set the intensity for the spotlight beam. The dot product value is the cosine of the angle between the two vectors. So, when the vectors are parallel, this value will be 1 or -1, and when the vectors are perpendicular, the dot product will be 0. In this recipe, we set the Intensity variable value based on the dot product, so that if the camera is looking directly at the spotlight beam, the intensity will be magnied, but if the camera is looking away, the intensity will be less. The effect of changing the intensity of the light is meant to be similar to the way our eyes adjust to lights when we look directly at them or an angle. If we were using a point light, which has no direction, we would take the dot product of a camera view vector, and a normalized vector from the light's origin to the camera's origin.

122

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4

The intensity of the spotlight beam cone is very low when the camera direction vector is perpendicular to the spotlight direction vector.

As the camera has moved, and the angle between the camera view vector and the spotlight direction vector is smaller, the intensity has increased.

123

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light Finally, when the camera view vector and the spotlight direction vector are parallel, the intensity is at its maximum value.

There's more...
In this recipe, we used a solid color for our spotlight beam. A better looking spotlight beam should use a gradient texture; one that is bright and opaque at the spotlight source, then progressively fades out, relative to the distance to the source.

Managing particle system


In this recipe, we'll create a basic particle system editor. Using this editor, we will be able to try out various particle effects that we can then use in our 3D application.

Getting ready
To follow along with this recipe, open the solution located in the Recipes/Chapter04 folder in the code bundle available on the Packt website.

How to do it...
1. First, create an MFC Ogre application named ParticleSystem. 2. Next, create a dialog-box named Particle System Editor using the Visual Studio Dialog Editor. Add two menus to the dialog-boxa menu to add various types of emitters and a menu to add affecters. Add event handles to each menu item. Next, add a tree control to manage the structure of the particle system, and controls for creating particle systems.

124

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4

3. Add a click handler for the Create button named OnBnClickCreateParticleSystem().


void CParticleSystemControlDlg::OnBnClickedCreateParticleSystem() { CMainFrame *MainFrame = (CMainFrame *)(( CParticleSystemApp*)AfxGetApp())->GetMainWnd(); CEngine *Engine = ((CParticleSystemApp*)AfxGetApp())->m_Engine; Ogre::Root *Root = Engine->GetRoot(); Ogre::SceneManager *SceneManager = Root-> getSceneManager("ParticleSystem"); m_ParticleSystem = SceneManager->createParticleSystem("Sun"); m_ParticleSystem->setDefaultDimensions(12, 24); m_ParticleSystem->setSortingEnabled(true); m_ParticleSystem->setMaterialName("Examples/Flare2"); m_ParticleSystem->setCullIndividually(true); m_ParticleSystem->setParticleQuota(3000); m_ParticleSystem->setRenderer("billboard"); m_ParticleSystem->setKeepParticlesInLocalSpace(false); }

When the Create button is pressed, we add a new particle system called sun, and set default dimensions, a material name, the particle type, and the maximum number of particles. 4. Next, create a handler for the Try button named OnBnClickedTryParticleSystem().
void CParticleSystemControlDlg::OnBnClickedTryParticleSystem() { CMainFrame *MainFrame = (CMainFrame *)(( CParticleSystemApp*)AfxGetApp())->GetMainWnd(); CEngine *Engine = ((CParticleSystemApp*)AfxGetApp())->m_Engine; Ogre::Root *Root = Engine->GetRoot(); Ogre::SceneManager *SceneManager = Root-> getSceneManager("ParticleSystem"); Ogre::SceneNode *SceneNode = SceneManager->getRootSceneNode()-> createChildSceneNode(); SceneNode->attachObject(m_ParticleSystem); SceneNode->setPosition(0, 10, 0); m_ParticleSystem->setVisible(true); Root->renderOneFrame(); MainFrame->GetActiveView()->SetTimer(1,1,0); }
125

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light In OnBnClickedTryParticleSystem(), we attach the particle system to a scene node, and render the scene. We also activate a timer to render the scene and update the particle system at regular intervals. 5. Next, we need to implement the handlers for creating the emitters and affecters. In this recipe, we will show you how to implement the Box Emitter and the Deector plane affecter. The implementation for the remaining emitters and affecters should be very similar. The message handler for Add Box Emitter should look like this:
void CParticleSystemControlDlg::OnEmittersAddBoxEmitter() { CBoxEmitterDlg BoxEmitterDlg; if (IDOK == BoxEmitterDlg.DoModal()) { HTREEITEM EmitterItem = m_ParticleSystemTree.InsertItem(BoxEmitterDlg.m_EmitterName, m_EmittersItem); m_ParticleSystemTree.EnsureVisible(EmitterItem); Ogre::ParticleEmitter *BoxEmitter = m_ParticleSystem-> addEmitter("Box");

When the Add Box Emitter menu item is selected, the BoxEmitterDlg dialog-box is displayed, and a box emitter is added to the particle system. 6. Create a dialog-box named CBoxEmitterDlg with a single text eld for the emitter name. 7. Now, let's implement the Add Deector Plane menu item handler. Create a dialogbox named CDeflectorPlaneAffectorDlg, and add controls for naming the affecter, setting the plane origin, normal, and bounce value.

126

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4

8. Next, we add code to the Add Deector Plane Affector menu item that opens the CDeectorPlaneAffectorDlg, then uses the dialog-box settings to create the affecter, and add it to the scene.
void CParticleSystemControlDlg:: OnAffectorsAdddeflectorplaneaffector() { CDeflectorPlaneAffectorDlg DeflectorPlaneAffectorDlg; if (IDOK == DeflectorPlaneAffectorDlg.DoModal()) { m_ParticleSystemTree.InsertItem( DeflectorPlaneAffectorDlg.m_AffectorName, m_AffectorsItem); Ogre::ParticleAffector *Plane = m_ParticleSystem-> addAffector("DeflectorPlane"); Plane->setParameter("plane_point", "0 -50 0"); Plane->setParameter("plane_normal", "0 1 0"); Plane->setParameter("bounce", "1"); } }

How it works...
When you create the particle system, and add emitters and affecters, they are added to the tree control. When the Try button is pressed, the particle system activates and a timer is enabled that renders the scene at regular intervals.
void CParticleSystemView::OnTimer(UINT_PTR nIDEvent) { CEngine * Engine = ((CParticleSystemApp*)AfxGetApp())->m_Engine; Ogre::Root *Root = Engine->GetRoot(); Root->renderOneFrame(); CView::OnTimer(nIDEvent); }

127

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light We also add a robot mesh to the scene to give a sense of scale, though you may wish to remove it, if the particle system you are testing is obscured by it.

There's more...
In this recipe, we only implemented one emitter and one affecter. You can implement the handlers and dialog-boxes for the remaining emitters and affecters. You can also add functionality to the tree, to enable and disable emitters and affecters by adding and removing them from the particle system, when the check-box next to each tree item is checked.

Managing shadows
When architects design buildings, they must adhere to city building codes and be aware of the impact on the environment caused by the structures they design. A tall building erected near others might cast a shadow over them, thus decreasing the warming rays of the sun, and increasing the cost of heating them. In this recipe, we will assume the role of the architect, and our job is to determine if the building that we want to erect will cast a shadow on an existing, nearby building. To simulate shadows cast on buildings, we will create a scene with a house to represent the affected building, and then use a 3D box model to represent the building we want to construct. We will also move a point light representing the sun, to simulate shadows at different times of day.

Getting ready
To follow along with this recipe, open the solution located in the Recipes/Chapter04 folder in the code bundle available on the Packt website.

How to do it...
1. First, create an MFC Ogre application with a ribbon named Shadows. 2. Next, create the simple scene with a ground plane, a house model, and a box model to represent the new building.
Ogre::Plane Ground(Ogre::Vector3::UNIT_Y, 0); Ogre::MeshPtr GroundMesh = Ogre::MeshManager::getSingleton().createPlane("Ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ground, 10000, 10000,20,20,true,1,5,5, Ogre::Vector3::UNIT_Z); Ogre::Entity *GroundEntity = SceneManager->createEntity("Ground", "Ground");
128

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4 Ogre::SceneNode *GroundNode = SceneManager->getRootSceneNode()-> createChildSceneNode("Ground"); GroundNode->attachObject(GroundEntity); GroundEntity->setCastShadows(false); Ogre::Vector3 InsertionPoint; Ogre::Entity *HouseEntity = SceneManager->createEntity("House", "tudorhouse.mesh"); Ogre::AxisAlignedBox HouseBox = HouseEntity->getBoundingBox(); InsertionPoint = - HouseBox.getCorner( Ogre::AxisAlignedBox::NEAR_LEFT_BOTTOM); Ogre::SceneNode *HouseNode = SceneManager->getRootSceneNode()-> createChildSceneNode(InsertionPoint); HouseNode->attachObject(HouseEntity); HouseEntity->setCastShadows(false); Ogre::Entity *BoxEntity = SceneManager->createEntity("Box", Ogre::SceneManager::PrefabType::PT_CUBE); BoxEntity->setMaterialName("Examples/BeachStones"); Ogre::AxisAlignedBox Box = BoxEntity->getBoundingBox(); Ogre::SceneNode *BoxNode = SceneManager->getRootSceneNode()-> createChildSceneNode("Box"); BoxNode->attachObject(BoxEntity); BoxNode->setScale(Ogre::Vector3(5, 20, 5)); BoxNode->setPosition(Ogre::Vector3(-1000, 0, 1000)); BoxEntity->setCastShadows(true);

3. Next, add a point light to represent the sun in our simulation.


SceneManager-> setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE); Sun = SceneManager->createLight("Sun"); Sun->setType(Ogre::Light::LT_POINT); Sun->setPosition(2500 * Ogre::Math::Cos(0), 1000, 2500 * Ogre::Math::Sin(0)); Sun->setDiffuseColour(0.35, 0.35, 0); Sun->setSpecularColour(0.9, 0.9, 0); Sun->setVisible(true);

129

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light 4. Next, add panels and sliders to the ribbon for controlling the height of the building and the time of day.

5. Now, it's time to create the event handlers for ribbon sliders.
void CShadowsView::OnTime() { CMainFrame *MainFrame = (CMainFrame *)(( CShadowsApp*)AfxGetApp())->GetMainWnd(); CMFCRibbonBar* RibbonBar = MainFrame->GetRibbonBar(); CMFCRibbonSlider* Slider = DYNAMIC_DOWNCAST(CMFCRibbonSlider, RibbonBar->FindByID(ID_TIME)); Ogre::Radian Angle = Ogre::Radian(Ogre::Math::TWO_PI * ( double)Slider->GetPos() / 24); CEngine *Engine = ((CShadowsApp*)AfxGetApp())->m_Engine; Ogre::Root *Root = Engine->GetRoot(); Ogre::SceneManager *SceneManager = Root-> getSceneManager("Shadows"); Ogre::Light *Sun = SceneManager->getLight("Sun"); Sun->setPosition(2500 * Ogre::Math::Cos(Angle), 1000, 2500 * Ogre::Math::Sin(Angle)); if (Root != NULL) { Root->renderOneFrame(); } }

6. For the Time slider, we convert the slider position to an angle, and use that value to set the sun position.
void CShadowsView::OnHeight() { CMainFrame *MainFrame = (CMainFrame *)(( CShadowsApp*)AfxGetApp())->GetMainWnd(); CMFCRibbonBar* RibbonBar = MainFrame->GetRibbonBar();

130

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Chapter 4 CMFCRibbonSlider* Slider = DYNAMIC_DOWNCAST(CMFCRibbonSlider, RibbonBar->FindByID(ID_HEIGHT)); CEngine *Engine = ((CShadowsApp*)AfxGetApp())->m_Engine; Ogre::Root *Root = Engine->GetRoot(); Ogre::SceneManager *SceneManager = Root-> getSceneManager("Shadows"); Ogre::SceneNode *BoxNode = SceneManager->getSceneNode("Box"); BoxNode->setScale(5, Slider->GetPos(), 5); if (Root != NULL) { Root->renderOneFrame(); } }

The Height slider simply scales the 3D box that represents the new building.

How it works...
When the Time slider is moved, we change the position of the sun point light, and render the scene again. Each time the scene is rendered, Ogre automatically updates the shadows in the scene, based on the light position, the shadow casters, and receivers in the scene. In this recipe, we specically instructed Ogre to only cast shadows for the 3D box that represents our new building, so the shadow is clearly visible. We also set the shadow type to SHADOWTYPE_ STENCIL_ADDITIVE, so the shadows are very crisp and dened.

131

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Let There Be Light

There's more...
To make a complete shadows analyzer, you should add a sun position calculator based on real locations in the world at various times of year. You can also add terrain to the scene, to more accurately represent the building location. Finally, using the Creating and Editing a Scene recipe, from the previous chapter, you can add functionality to add and remove objects in the scene.

See also
Chapter 3, Managing Objects and Scenes:

Creating a terrain from a LandXML le Creating Delaunay triangulation Creating and editing a scene

132

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

Where to buy this book


You can buy OGRE 3D 1.7 Application Development Cookbook from the Packt Publishing website: http://www.packtpub.com/ogre-3d-1-7-applicationdevelopment-cookbook/book.
Free shipping to the US, UK, Europe and selected Asian countries. For more information, please read our shipping policy.

Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and most internet book retailers.

www.PacktPub.com

For More Information: www.packtpub.com/ogre-3d-1-7-application-development-cookbook/book

You might also like