Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
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.
To follow along with this recipe, open the solution located in the Recipes/Chapter04 folder in the code bundle available on the Packt website.
DynamicEffects. 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); 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);
Ogre::Light::LT_SPOTLIGHT, and attach it to the scene graph. Cone.cpp and the Cone.h files 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.
m_WorkingTimer to CDynamicEffectsView. ON_WM_KEYDOWN message named CDynamicEffectsView::OnKeyDown().m_WorkingTimer = 0;
switch (nChar) {
case VK_LEFT: //left
case 65: //A
case 97: //a
m_WorkingTimer = 1;
break;
case VK_UP: //up
case 87: //W
case 119: //w
m_WorkingTimer = 2;
break;
case VK_RIGHT: //right
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.
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.
ON_WM_TIMER message named CDynamicEffectsView::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) {
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;
}
CameraMove variable appropriately, to move the camera in the right direction.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);
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 ++;
}
}
/**/
//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();
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 magnified, 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.
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.
Finally, when the camera view vector and the spotlight direction vector are parallel, the intensity is at its maximum value.