Tutorial 7 - como crear una camara y controlarla
Friday, March 23, 2007 10:38:35 PM
La nueva version de este tutorial (mejorado) esta en mi nuevo blog.
http://aarcoraci.homeip.net/blog/post/Tutorial-XNA---Camara-flotante.aspx
No voy a seguir la linea de desarrollo de los otros tutoriales por 2 motivos:
Primero, seguir tocando el codigo como lo venia haciendo va a ser mas confuso que educativo.
Segundo, creo que si llegaron hasta este tutorial son capaces de entender el modelo orientado a objetos y agregar la camara a sus proyectos sin mayores problemas.
Conceptos de la camara:
Vi muchos papers respecto a las camaras, y la mayoria o eran muy dificiles o no cumplian los objetivos que queria.
El ejemplo que presenta microsoft en msdn2 depende de un modelo o un "avatar" y no tiene movimiento arriba y abajo.
Otros ejemplos que si tienen movimiento arriba y abajo tienen el siguiente problema:
Si miro hacia arriba y luego hacia adelante, la camara viaja en esa direccion, cuando lo que yo quiero es que se camine hacia adelante mirando hacia arriba y no "nadar" en el espacio por asi decirlo.
De todas formas voy a cubrir ese tipo de camara en este tutorial.
Conceptos del mundo 3D - repaso
Recordemos que en XNA las cordenadas son como siguen:
Osea que:
Si quiero ir hacia adelante, aumento Z.
Si quiero girar sobre mi eje, aplico rotacion sobre Y.
Si quiero "volar" hacia arriba, aumento Y.
ejemplo:
Variables:
La camara sera la encargada de manejar las matrices view,world y projection.
La camara va a tener una posicion, un objetivo y una definicion de que eje apunta arriba (eje Y)
La camara va a manejar diferentes velocidades.
Codigo:
Primero que nada, este codigo es de un proyecto personal y yo siempre programo en ingles como norma, pero voy a explicar todo en español:
#region using
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endregion
namespace FantasyCamera
{
public class camera
{
#region vars
//matrices
private Matrix view;
public Matrix View
{
get { return view; }
}
private Matrix projection;
public Matrix Projection
{
get { return projection; }
}
private Matrix world;
public Matrix World
{
get { return world; }
}
//end matrices
private Vector3 position;
private float ratio;
public float Ratio
{
set { ratio = value; }
}
private float nearClip = 1.0f;
private float farClip = 1000.0f;
private float fov = MathHelper.PiOver4;
private float yaw;
private float pitch;
private float rotationSpeed = 1f / 160f;
private float forwardSpeed = 50f / 60f;
#endregion vars
public camera(int w, int h)
{
ratio = w/h;
}
public void update()
{
KeyboardState state = Keyboard.GetState();
Vector3 movement = Vector3.Zero;
//movement
if (state.IsKeyDown(Keys.Up))
{
movement.Z -= forwardSpeed;
}
if (state.IsKeyDown(Keys.Down))
{
movement.Z += forwardSpeed;
}
if (state.IsKeyDown(Keys.W))
{
movement.Y += forwardSpeed;
}
if (state.IsKeyDown(Keys.S))
{
movement.Y -= forwardSpeed;
}
//lock sides
if (state.IsKeyDown(Keys.Left))
{
yaw += rotationSpeed;
}
if (state.IsKeyDown(Keys.Right))
{
yaw -= rotationSpeed;
}
//look up and down
if (state.IsKeyDown(Keys.Q))
{
pitch -= rotationSpeed;
}
if (state.IsKeyDown(Keys.E))
{
pitch += rotationSpeed;
}
Matrix rotationMatrix = Matrix.CreateRotationY(yaw);
Vector3.Transform(ref movement, ref rotationMatrix, out movement);
position += movement;
// matrices
view = Matrix.CreateLookAt(position, position + rotationMatrix.Forward + new Vector3(0,pitch,0), Vector3.Up);
projection = Matrix.CreatePerspectiveFieldOfView(fov, ratio, nearClip, farClip);
world = Matrix.Identity;
}
}
}
Explicacion:
//matrices
private Matrix view;
public Matrix View
{
get { return view; }
}
Aca tenemos un ejemplo de como tratar una variable con visibilidad privada, observen que cuando uso "public" cambia la mayuscula.
La variable ratio dice como dibujar los objetos dependiendo la resolucion.
farClip y nearClip indican el alcance de la camara, no se dibujara lo que este a menos de 1 unidad y mas lejos de 1000 unidades.
"fov" o Field of View o Campo de vision indica como vemos, piOver4 o pi/4 son 45 grados.
las variables yaw y pitch (no se si estos nombres estan bien) indican el movimiento hacia los lados y hacia arriba y abajo de la camara.
private float rotationSpeed = 1f / 160f;
private float forwardSpeed = 50f / 60f;
Esas son faciles, son solo las variables de velocidad de rotacion y que tan rapido corremos.
public camera(int w, int h)
{
ratio = w/h;
}
El constructor es facil, solo necesitan pasarle el alto y ancho de la pantalla, si usan monitores regulares, pueden pasarle por ejemplo 800x600.
Lo que resta del codigo es facil, pero me voy a detener en la siguiente linea:
view = Matrix.CreateLookAt(position, position + rotationMatrix.Forward + new Vector3(0,pitch,0), Vector3.Up);
CreateLookAt recibe 3 valores, posicion de la camara, objetivo y el direccion arribe.
Si ven, en objetivo esta "posicion + rotationMatrix.Forward + " un nuevo vector.
Ese "nuevo vector" indica que se suma una rotacion sin desplazamiento hacia arriba y hacia abajo. Esto es para que la camara no salga flotando hacia arriba o abajo.
Imaginen en el quake 1 si cuando miramos para arriba el personaje empezara a volar, malisimo.
Ahora, para los que quieran estar en un ambiente submarino, remplacen el codigo como sigue:
Matrix rotationMatrix = Matrix.CreateRotationY(yaw) * Matrix.CreateRotationX(pitch);
Vector3.Transform(ref movement, ref rotationMatrix, out movement);
position += movement;
// matrices
view = Matrix.CreateLookAt(position, position + rotationMatrix.Forward, Vector3.Up);
projection = Matrix.CreatePerspectiveFieldOfView(fov, ratio, nearClip, farClip);
world = Matrix.Identity; Cualquier duda pregunten.
NOTA Recuerden que cuando necesiten las matrices world view y projection, se las tienen que "pedir" a camera.
Ejemplo si quieren dibujar un objeto:
objeto.draw( instanciaCamara.World, instanciaCamara.View, instanciaCamara.Projection )
DISCUTI ESTE ARTICULO ACA


.









