Tutorial Básico 2

Cámaras, Luces, y Sombras


Introducción del Tutorial


external image dl1773
En este tutorial se te introducirá en más construcciones de Ogre expandiendo lo que ya has aprendido.
Este tutorial tratará sobre los objetos Light y como usarlos para crear sombras en Ogre.

También se cubrirá lo básico sobre cámaras.





external image help.gifCualquier problema que encuentres mientras estes trabajando en este tutorial deberías preguntarlo en el Foro.


Prerrequisitos


  • Este tutorial asume que tienes conocimientos sobre programación en C++ y eres capaz de compilar e instalar una aplicación de Ogre.
  • Este tutorial también asume que has creado un proyecto usando el Tutorial Framework Ogre Wiki, manualmente, usando CMake o el AppWizard de Ogre - mirar Creando una aplicación para más instrucciones.
  • Este tutorial se compila sobre la versión anterior de los tutoriales básicos, así que se asume que has trabajado con ellos.

Cuando mires el tutorial deberías ir lentamente añadiendo código a tu proyecto y mirando los resultados. Puedes ver el código fuente para ver el estado final del tutorial aquí. Si tienes problemas con el código, deberías comparar tu fuente del proyecto al resultado final.

Comenzando


Como con el último tutorial, usaremos un código pre-construido de base como nuestro punto de partida. Añadiremos un punto de partida. Añadiremos dos métodos más a nuestra clase BasicTutorial2: createViewport y createCamera. Estas dos funciones fueron definidas en la base BaseApplication, pero en este tutorial las buscaremos para ver como las Cámaras y Viewports son creados y usados.

Añade las declaraciones para createCamera y createViewport a tu cabecera de clase tutorial básico 2:

cabecera BasicTutorial2
class BasicTutorial2 : public BaseApplication
{
public:
BasicTutorial2(void);
virtual ~BasicTutorial2(void);
 
protected:
virtual void createScene(void);
virtual void createCamera(void);
virtual void createViewports(void);
};
Entonces necesitas añadir las definiciones para la implementación del tutorial básico 2:

Implementación BasicTutorial2
//-------------------------------------------------------------------------------------
void BasicTutorial2::createCamera(void)
{
}
//-------------------------------------------------------------------------------------
void BasicTutorial2::createViewports(void)
{
}

Cámaras


Cámaras en Ogre


Una Cámara es lo que usamos para ver la escena que hemos creado. Una Cámara es un objeto especial que funciona como los SceneNodes. El objeto Cámara tiene setPosition, yaw, roll y pitch, y puede acoplarse a cualquier SceneNode. Como en los SceneNodes, la posición de la cámara es relativa a sus padres. Para todos los movimientos y rotaciones, puedes considerar a la Cámara un SceneNode.

Una cosa sobre las Cámaras de Ogre que es diferente de lo que se podría esperar es que sólo puede usarse una Cámara cada vez (por ahora). Esto es, no necesitamos crear una Cámara para ver una porción de la escena, una segunda cámara para ver otra porción de la escena y entonces activar o desactivar cámaras basándose en que porción de la escena queremos mostrar. En vez de esto, el modo apropiado es crear SceneNodes que actúen como "marcas de cámara". Estos SceneNodes marcan un punto en la Escena hacia el que la camara debería apuntar. Cuando es tiempo de mostrar una porción de la Escena, la Cámara simplemente se acopla al SceneNode apropiado. Volveremos a ver esta técnica en el tutorial sobre FrameListeners.

Creando una Cámara


Sobreescribiremos el método por defecto que BaseApplication usa para crear la cámara.

Encuentra el miembro de función BasicTutorial2::createCamera
La primera cosa que pienso que debemos hacer es crear la Cámara.
Ya que las Cámaras estan ligadas al SceneManager en el que residen, usamos el objeto SceneManager para crearlas. Añade esta línea de código para crear la Cámara:
void BasicTutorial2::createCamera(void)
{
// crea la camara
mCamera = mSceneMgr->createCamera("PlayerCam");
}

Esto crea una Cámara con el nombre "PlayerCam".
Nota que puedes usar la función getCamera de SceneManager para conseguir Cámaras basadas en su nombre si decides no guardar un puntero a ello.


La siguiente cosa que haremos es establecer la posición de la Cámara y el modo en el que se muestra.
Colocaremos objetos alrededor del origen, así que pondremos la Cámara a una buena distancia en la dirección +z y tendremos la cara de la cámara en el origen. Añade este código después de lo anterior:

// establece su posicion, direccion
 mCamera->setPosition(Ogre::Vector3(0,10,500));
 mCamera->lookAt(Ogre::Vector3(0,0,0));

La función lookAt es muy sencilla. Puedes tener la cara de la cámara en cualquier posición que tu quieras en vez de tener que yaw, rotate, y pitch. Los SceneNodes también tienen esta función, lo cual puede hacer que las Entidades apunten en la dirección correcta mucho más fácilmente en muchos casos.

Finalmente estableceremos una distancia de recorte cercano de 5 unidades.
Esta distancia de recorte de Cámara se especifica como cercanía o lejanía de algo que antes no podías ver. Estableciendo la cercanía de la distancia de recorte hace mas fácil mirar a través de Entidades en la pantalla cuando estás muy cerca de ellas. La alternativa es estar tan pegado a un objeto que llene la pantalla y no puedas ver nada más que una versión reducida. También puedes establecer la lejanía. Esto es usado principalmente para incrementar el número de frames si quieres renderizar grandes cantidades de cosas sobre la pantalla para distancias muy largas.

Para establecer la distancia de recorte de cercanía, añade esta línea:
// establece la distancia cercana de recorte
 mCamera->setNearClipDistance(5);
Los ajustes de lejanía deberían ser similares llamando a setFarClipDistance (pienso que no deberías usar una distancia de lejanía con Sombras Stencil, la cual usaremos en este tutorial).


Ahora, ya que hemos sobreescrito la función createCamera, necesitamos construir un OgreBites::SdkCameraMan (controlador de Cámara) usando nuestra recién construida cámara, camera:

mCameraMan = new OgreBites::SdkCameraMan(mCamera); // crea un controlador de camara por defecto
La función createCamera resulta así:
void BasicTutorial2::createCamera(void)
{
// Crea la camara
mCamera = mSceneMgr->createCamera("PlayerCam");
// Establece su posicion y direccion
mCamera->setPosition(Ogre::Vector3(0,10,500));
mCamera->lookAt(Ogre::Vector3(0,0,0));
// Establece la cercania de recorte
mCamera->setNearClipDistance(5);
 
mCameraMan = new OgreBites::SdkCameraMan(mCamera); // crea un controlador de camara por defecto
}


Viewports (Puertos de Vista)




Viewports de Ogre



Cuando comiences a tratar con múltiples cámaras, el concepto de la clase Viewport resultará muy útil. Te explicaré este tema ahora porque pienso que es importante para que comprendas como Ogre decide que Cámara usar cuando se renderiza la escena. Es posible tener en Ogre múltiples SceneManagers ejecutándose al mismo tiempo. También es posible dividir la pantalla en múltiples áreas, y tener cámaras separadas para áreas separadas sobre la pantalla (piensa en la vista dividida para 2 jugadores en una consola de juegos, por ejemplo). Sabiendo que es posibles hacer estas cosas, no las trataremos hasta los tutoriales avanzados.

Comprender como Ogre renderiza la escena, considera tres construcciones de Ogre:
la Camera, el SceneManager, y el RenderWindow. El RenderWindow no lo hemos tratado, pero es básicamente la ventana en la que todo se muestra. El objeto SceneManager crea Cámaras para ver la Escena. Debes decirle al RenderWindow que cámaras se mostrarán en pantalla, y que porción de la ventana se renderizará. El área en la cual dices al RenderWindow que muestre la Cámara es tu Viewport. Para los usos mas típicos, no necesitarás crear más que una única cámara, registra la cámara para usar el RenderWindow entero, y además sólo tendrás un objeto Viewport.

En este tutorial trataremos sobre como registrar la Cámara para crear el Viewport. Podremos entonces usar este objeto Viewport para establecer el color de fondo de la escena que estamos renderizando.


Creando el Viewport



Sobreescribiremos la creación del BaseApplication del Viewport, así que encuentra el miembro de función BasicTutorial2::createViewports. Para crear el Viewport llamaremos a la función addViewport de RenderWindow y le proporcionaremos la cámara que estamos usando. La clase BaseApplication ya tiene la clase mWindow con nuestra RenderWindow, así que añade esta línea de código:
// Crea un viewport, la ventana entera
Ogre::Viewport* vp = mWindow->addViewport(mCamera);

Ahora que tenemos nuestro Viewport, que haremos con él? La respuesta es: no mucho. La cosa más importante que podemos hacer con él es llamar a la función setBackgroundColour para establecer el fondo del color que queramos. Ya que estamos tratando con iluminación en este tutorial estableceremos el color a negro:

vp->setBackgroundColour(Ogre::ColourValue(0,0,0));

Nota que el ColourValue espera un valor de color de rojo, verde, y azul para sus parámetros entre el 0 y el 1. La última, y más importante cosa que necesitamos hacer es establecer la relación de aspecto de nuestra Camera. Si estás usando distinto al viewport estándar a pantalla completa, entonces fallará al establecer esto y puede dar como resultado unas imágenes extrañas de la escena. Lo trataremos más adelante , vamos a usar la relación de aspecto por defecto:

// Altera la relacion de aspecto para que coincida con el viewport
mCamera->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
Esto es todo lo que se tiene que hacer para un uso común de la clase Viewport.

Así es como nuestra función createViewports quedaría:
void BasicTutorial2::createViewports(void)
{
// Crea un viewport, la ventana entera
Ogre::Viewport* vp = mWindow->addViewport(mCamera);
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
// Altera la relacion de aspecto de la camara para que coindica con el viewport
mCamera->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
}
En este punto deberías ser capaz de compilar y ejecutar la aplicación, pienso que no aparecería nada más que una escena en blanco (usa la tecla Escape para salir). Asegúrate de que puedes ejecutar la aplicación sin que falle antes de continuar.

Luces y Sombras


Tipos de Sombras que Soporta Ogre


Ogre soporta tres tipos de sombras:

  1. Sombras de Textura Modulativas (Ogre::SHADOWTYPE_TEXTURE_MODULATIVE) - La más costosa computacionalmente hablando de las tres. Crea un renderizado de textura blanco y negro de los arrojadores de sombra, que es más tarde aplicado a la escena.
  2. Sombras Modulativas Stencil (Ogre::SHADOWTYPE_STENCIL_MODULATIVE) - Esta técnica renderiza todos los volumes de sombra como una modulación después de que todos los objetos no transparentes hayan sido renderizados a la escena. Esto no es tan intensivo como las Sombras Aditivas Stencil, pero también no es tan preciso.
  3. Sombras Aditivas Stencil (Ogre::SHADOWTYPE_STENCIL_ADDITIVE) - Esta técnica renderiza cada luz como una pasada aditiva separada en la escena. Esto es muy duro para la tarjeta grafica ya que cada luz adicional necesita una pasada adicional en el renderizado de la escena.


external image Ogreshadows.jpg

Ogre no soporta las sombras suaves como parte de su motor. si quieres sombras suaves necesitarás escribir tus propios programas de vértices y fragmentos. Nota que esto es sólo una rápida introducción - El manual de Ogre describe completamente las sombras y las implicaciones de usarlas.

Usando las Sombras en Ogre


Usar las sombras en Ogre es relativamente simple. La clase SceneManager tiene un miembro de función setShadowTechnique que podemos usar para establecer el tipo de sombras que queremos. Entonces crearás una Entity, y llamarás a la función setCastShadows para establecer si se arrojan o no sombras.

Estableceremos la luz de ambiente a oscuridad completa, y estableceremos el tipo de sombra. Encuentra el miembro de función BasicTutorial2::createScene y añádele este código:
mSceneMgr->setAmbientLight(Ogre::ColourValue(0, 0, 0));
mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
Ahora el SceneManager usa sombras aditivas stencil. Crea un objeto sobre la escena y haz que arroje sombras.
Ogre::Entity* entNinja = mSceneMgr->createEntity("Ninja", "ninja.mesh");
entNinja->setCastShadows(true);
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entNinja);
También necesitamos algo para que el Ninja permanezca de pie (asi que tendrá algo sobre lo que se arrojarán las sombras). Para hacer esto crearemos un plano simple. Esto no significa que este es un tutorial sobre el uso de MeshManager, pero lo trataremos por encima ya que lo necesitamos para crear un plano. Lo primero que necesitamos para definir es el objeto Plane por si mismo, lo cual se hace proporcionando una normal y la distancia desde el origen. Podriamos (por ejemplo) usar planos para hacer la geometria del mundo, en este caso necesitariamos algo diferente de 0 para nuestra distancia al origen. Por ahora solo queremos un plano para tener el eje positivo de y como su normal (lo que signifca que queremos que apunte hacia arriba) , y ninguna distancia desde el origen:
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
Ahora necesitamos registrar el plano para poder usarlo en nuestra aplicación. La clase MeshManager guarda la pista de todas las mallas que hemos cargado en nuestra aplicación (por ejemplo, esto guarda la pista de robot.mesh y el ninja.mesh que hemos estado usando). La función miembro createPlane toma una definición de Plano y hace una malla desde los parámetros. Esto registra nuestro plano para usarse:
Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
plane, 1500, 1500, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
Otra vez, no vamos a entrar en detalles específicos de como usar MeshManager por ahora (consulta la API de referencia si quieres ver exáctamente que está haciendo cada parámetro). Básicamente hemos registrado nuestro plano para que sea de 1500 por 1500 de tamaño y la nueva malla se llamará "ground" (suelo). Ahora, podemos crear una Entity de la forma de esta malla y colocarla en la escena:
Ogre::Entity* entGround = mSceneMgr->createEntity("GroundEntity", "ground");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entGround);
Hay dos cosas más que tenemos que hacer con nuestro ground antes para terminar. La primera es decirle al SceneManager que no queremos que arroje sombras ya que es usado para que las sombras se proyecten sobre él. La segunda cosa es que necesitamos poner una textura en él. Nuestras mallas robot y ninja ya tienen scripts de material definidos para ellas. Cuando creemos nuestra malla ground manualmente, no especificamos que textura usar en ella. Usaremos el script de material "Examples/Rockwall" que incluye Ogre con sus ejemplos:
entGround->setMaterialName("Examples/Rockwall");
entGround->setCastShadows(false);
Asi es como será nuestra función createScene:
void BasicTutorial2::createScene(void)
{
mSceneMgr->setAmbientLight(Ogre::ColourValue(0, 0, 0));
mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
 
Ogre::Entity* entNinja = mSceneMgr->createEntity("Ninja", "ninja.mesh");
entNinja->setCastShadows(true);
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entNinja);
 
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
 
Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
plane, 1500, 1500, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
 
Ogre::Entity* entGround = mSceneMgr->createEntity("GroundEntity", "ground");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entGround);
 
entGround->setMaterialName("Examples/Rockwall");
entGround->setCastShadows(false);
 
}
Ahora que tenemos un Ninja y un ground en la escena, compilemos y ejecutemos el programa. Vemos ... Nada! ¿Qué está pasando? En el tutorial previo añadimos Robots y se mostraron correctamente. La razon de que el Ninja no lo haga es porque la luz ambiental de la escena esta establecida a oscuridad. Asi que añade una luz y veamos lo que pasa.

Tipos de Luz


Estos son los tres tipos de iluminación que proporciona Ogre.

  1. Point (Ogre::Light::LT_POINT) - Las fuentes de luz puntual desde ellas en todas direcciones.
  2. Spotlight (Ogre::Light::LT_SPOTLIGHT) - Una spotlight trabaja exactamente igual que una luz de flash. Tiene una posición donde la luz comienza, y entonces la luz se lanza en una dirección. También le puedes decir a la luz como de largo puede ser un ángulo para usarla para el círculo interior y el círculo exterior de la luz (sabes que las luces de flash son brillantes en el centro y luego decaen hasta un cierto punto).
  3. Directional (Ogre::Light::LT_DIRECTIONAL) - La luz direccional simula la luz lejana que da sobre todo en la escena desde una dirección. Si tienes una escena nocturna y quieres simular la luz de luna. Podrias hacer esto estableciendo los ajustes de luz de ambiente para la escena, pero no será exactamente realista ya que la luz de la luna no es igual para todo (como lo es la del sol). Un modo de hacer esto podria ser establecer una luz direccional y apuntarla en la dirección en la que la luna podría brillar.

Las luces tienen un amplio rango de propiedades que describen como se representa la luz. Dos de las más importantes propiedades de la luz son su color de difusión y el color especular. Cada script de material define cuanta cantidad de iluminación especular y difusa refleja el material, por lo que aprenderemos a como controlarla en un tutorial posterior.

Creando las luces


Para crear una Light (luz) en Ogre llamamos a la función miembro createLight del SceneManager y proporcionamos un nombre para la luz, muy parecido a como lo haciamos para crear una Entity o una Camera.
Después creamos una luz (Light), podemos establecer su posición manualmente o acoplarla a un SceneNode para su movimiento. A diferencia de un objeto Camera, la luz solo tiene setPosition y setDirection (y no la amplitud de funciones de movimiento como son translate, pitch, yaw, roll, etc). Asi si necesitas crear una luz estacionaria, deberías llamar a la función miembro setPosition. Si necesitas que la luz se mueva (por ejemplo creando una luz que siga al personaje), entonces deberías acoplarla a un SceneNode en su lugar.

Asi que, comencemos con un ejemplo de iluminación puntual básico. La primera cosa que necesitamos hacer es crear la luz, establecer su tipo, y establecer su posición:
Ogre::Light* pointLight = mSceneMgr->createLight("pointLight");
pointLight->setType(Ogre::Light::LT_POINT);
pointLight->setPosition(Ogre::Vector3(0, 150, 250));
Ahora que hemos creado la luz, podemos establecer color difuso y especular. Hagámoslo rojo:
pointLight->setDiffuseColour(1.0, 0.0, 0.0);
pointLight->setSpecularColour(1.0, 0.0, 0.0);
Ahora compila y ejecuta la aplicación. Fantástico! Podemos ver ahora al Ninja y a su sombra arrojada. Asegúrate de también mirarle desde el frente, una silueta completa. Una cosa que tienes que notar es que no "ves" la fuente de luz. Muchos de los tutoriales de Ogre añaden una entity simple para mostrar donde la luz esta siendo emitida. Si tienes problemas con las luces en tu aplicación deberías considerar crear algo similar a lo que ellos hacen para ver exactamente donde esta tu luz.

Siguiente, intentemoslo con una luz direccional. Nota como el frente del ninja está en penumbra? vamos a añadir una pequeña cantidad de luz direccional amarilla que brille en el frente de su cuerpo. Creamos la luz y establecemos el color como hicimos para la luz puntual:
Ogre::Light* directionalLight = mSceneMgr->createLight("directionalLight");
directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
directionalLight->setDiffuseColour(Ogre::ColourValue(.25, .25, 0));
directionalLight->setSpecularColour(Ogre::ColourValue(.25, .25, 0));
Ya que la luz direccional se supone que viene desde una distancia lejana, no tenemos que establecer su posición, sólo su dirección. Estableceremos la dirección de la luz para que sea positiva al eje z y negativa a la dirección y (viniendo desde 45 grados en el frente y debajo del ninja):
directionalLight->setDirection(Ogre::Vector3( 0, -1, 1 ));
Compila y ejecuta la aplicación. Ahora tenemos dos sombras en la pantalla, ya que la luz direccional es tan ficticia, la sombra también lo será. El último tipo de luz con el que vamos a jugar es la luz spot(luz de foco). Ahora creamos un foco azul:
createLight("spotLight">También necesitamos establecer ambas la posición y la dirección en la que la dirección la luz de spot brillará. Crearemos una luz de spot que se ubique por encima del hombro derecho del ninja, y brille directamente sobre él:
[[code format="cpp"]]
spotLight->setDirection(-1, -1, 0);
spotLight->setPosition(Ogre::Vector3(300, 300, 0));
Las luces de spot nos permiten especificar como de ancho es el rayo de luz. Imagina un rayo de luz de flash por un segundo. Hay un núcleo en el rayo en el centro que es más luminoso que lo que lo rodea. Podemos establecer el ancho de ambos de estos rayos llamando a la función miembro setSpotlightRange:
spotLight->setSpotlightRange(Ogre::Degree(35), Ogre::Degree(50));
Compila y ejecuta la aplicación. Ninja Purpura... peligroso!

Así es como quedará nuestra createScene:
void BasicTutorial2::createScene(void)
{
mSceneMgr->setAmbientLight(Ogre::ColourValue(0, 0, 0));
mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
 
Ogre::Entity* entNinja = mSceneMgr->createEntity("Ninja", "ninja.mesh");
entNinja->setCastShadows(true);
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entNinja);
 
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
 
Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
plane, 1500, 1500, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
 
Ogre::Entity* entGround = mSceneMgr->createEntity("GroundEntity", "ground");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entGround);
 
entGround->setMaterialName("Examples/Rockwall");
entGround->setCastShadows(false);
 
Ogre::Light* pointLight = mSceneMgr->createLight("pointLight");
pointLight->setType(Ogre::Light::LT_POINT);
pointLight->setPosition(Ogre::Vector3(0, 150, 250));
 
pointLight->setDiffuseColour(1.0, 0.0, 0.0);
pointLight->setSpecularColour(1.0, 0.0, 0.0);
 
Ogre::Light* directionalLight = mSceneMgr->createLight("directionalLight");
directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
directionalLight->setDiffuseColour(Ogre::ColourValue(.25, .25, 0));
directionalLight->setSpecularColour(Ogre::ColourValue(.25, .25, 0));
 
directionalLight->setDirection(Ogre::Vector3( 0, -1, 1 ));
 
Ogre::Light* spotLight = mSceneMgr->createLight("spotLight");
spotLight->setType(Ogre::Light::LT_SPOTLIGHT);
spotLight->setDiffuseColour(0, 0, 1.0);
spotLight->setSpecularColour(0, 0, 1.0);
 
spotLight->setDirection(-1, -1, 0);
spotLight->setPosition(Ogre::Vector3(300, 300, 0));
 
spotLight->setSpotlightRange(Ogre::Degree(35), Ogre::Degree(50));
}

Cosas a intentar


Diferentes tipos de sombras


En esta demo sólo establecemos el tipo de sombra para que sea SHADOWTYPE_STENCIL_ADDITIVE. Intenta ajustarla en los otros dos tipos de sombras y mira que ocurre. Hay muchas otras funciones relacionadas con sombras en la clase SceneManager. Intenta jugar con algunas de ellas y mira que ocurre.

Atenuación de la luz


Las luces definen una función setAttenuation la cual te permite tener control sobre como la luz que se disipa cuanto más te alejas de ella. Añade una llamada a la función de la luz puntual que establezca la atenuación a diferentes valores. ¿Cómo afectará esto a la luz?

SceneManager::setAmbientLight


Experimenta con la función setAmbientLight de mSceneMgr.

Color de Fondo del Viewport


Cambia el valor del color por defecto en la función createViewports. No es realmente apropiado cambiarlo a algo diferente a negro en esta situación, pero es buena idea saber como cambiarlo.

Camera::setFarClipDistance


En createCamera establecemos la distancia de recorte cercana. Añadimos una llamada a la función setFarClipDistance y la establecemos para que sea 500, mira lo que ocurre cuando te mueves desde ver al Ninja y ya no ves al Ninja con las sombras stencil encendidas.
Notas la lenta subida?

Nota: Necesitarás establecer mSceneMgr->setShadowUseInfiniteFarPlane(false), para este trabajo, y deberías conseguir algunas sombras extrañas. (Mirar este hilo)

Planos


No hemos hablado sobre los Planos en este tutorial (este no era el tema principal). Volveremos sobre él y revisaremos el tema en otro tutorial, pero por ahora deberías poner atención a la función createPlane e intentar jugar con algunas de las entradas a la función.

Código Completo


Si estas teniendo problemas para compilar este tutorial, echa un vistazo al código fuente y compáralo con tu proyecto.

Siguiente Tutorial Básico 3 Terreno, Cielo, y Niebla