¡Bienvenid@ a La bloguera.net! Iniciar sesión | ÚNETE a la web | Ayuda

XNACommunity Blog

XNAndo todo lo XNAble
Making of Blue Dragon

Bueno la idea de escribir este artículo surgió del foro de XNACommunity, donde se preguntó cómo se podría hacer en XNA una situación parecida a la de las luchas que aparecen en Blue Dragon, donde aparecen los luchadores y a la izquierda una pequeña pantalla que enfoca en primer plano a alguno de estos. Aquí podéis ver una imagen en donde veréis mejor a que me refiero:

 

Manos a la obra
Bien lo primero será tener claro que es lo que queremos hacer, simplemente haremos dos renders de la escena, uno desde una posición cercana a alguno de los luchadores y otra desde un punto de vista más global. Por lo que necesitaremos dos cámaras y dos superficies sobre las que pintar, empezaremos hablando sobre las superficies.
Sobre un renderTarget pintaremos la imagen desde cámara zoom, que será la que recoja un primer plano de alguno de los luchadores, para ello nos creamos un atributo de tipo RenderTarget:

RenderTarget2D RT;

Inicializamos el renderTarget dentro de método Initialize, con unos parámetros habituales y con un tamaño de 512 pixeles.
protected override void Initialize()
{
 base.Initialize();
 
 RT = new RenderTarget2D(GraphicsDevice, 512, 512, 1, SurfaceFormat.Color);
}

Ahora para la otra superficie usaremos directamente el target buffer, por lo que no hace falta nada más.
Ahora necesitamos crear dos cámaras que capten la escena desde cada uno de los puntos de vista que queremos. Para ello crearemos una clase camera dentro de un nuevo fichero camera.cs, este será una cámara muy simple con unos atributos habituales. Para más información mirar directamente el fichero en el ejemplo, nosotros ahora solo le echaremos un vistazo al constructor para conocer sus parámetros:
public Camera(Vector3 position, Vector3 lookat, float nearPlane, float farPlane, float aspectRatio, float fieldOfView)

Bien una vez que tenemos esto ya podemos crear las dos cámaras que necesitábamos, e inicializarlas con los parámetros correctos:
Camera camera;
Camera cameraZoom;
 
protected override void Initialize()
{
    base.Initialize();
 
    RT = new RenderTarget2D(GraphicsDevice, 512, 512, 1, SurfaceFormat.Color);
 
    camera = new Camera(new Vector3(0, 20, 50), Vector3.Zero, 1, 10000,
        GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, MathHelper.PiOver4);
    cameraZoom = new Camera(new Vector3(0, 10, 1), new Vector3(5, 10, 0), 1, 10000, 1, MathHelper.PiOver4);
}

Ok, el siguiente paso será usar la cámara normal para renderizar la escena:
protected override void Draw(GameTime gameTime)
{
    RenderScene();
 
    base.Draw(gameTime);
}
 
private void RenderScene()
{
    GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0);
 
    DrawTerrain(camera);
 
    DrawMD3();
 
    DrawText();
}


El resultado de nuestra escena en estos momentos es:

 

Bien el siguiente paso será renderizar sobre el rendertarget la escena desde el punto de vista de camerazoom. Para ello crearemos un método llamado DrawCameraZoom, que se encargará de hacer esto:

protected override void Draw(GameTime gameTime)
{
    DrawCameraZoom();
 
    RenderScene();
 
    base.Draw(gameTime);
}
 
private void DrawCameraZoom()
{
    GraphicsDevice.SetRenderTarget(0, RT);
 
    GraphicsDevice.Clear(Color.CornflowerBlue);
 
    DrawTerrain(cameraZoom);
 
    models[0].render(GraphicsDevice,
                        getLocalWorld(new Vector3(40, 70, 0), new Vector3(-MathHelper.PiOver2, -MathHelper.PiOver2, 0), 0.1f),
                        cameraZoom.View,
                        cameraZoom.Projection); 
 
    GraphicsDevice.SetRenderTarget(0, null);
}


Como se puede ver en el código, lo primero que hacemos es configurar el GraphicsDevice para que renderize sobre nuestro renderTarget, después limpiamos la escena y renderizamos esta. Como solo va a aparecer un modelo en pantalla será este el único que dibujemos y por último configuramos otra vez el device para que pinte sobre el target por defecto.


Bien en este momento ya tenemos dentro de RT.GetTexture() almacenada la siguiente imagen:

 

Que es precisamente con la que vamos a texturizar el plano que vamos a colocar en la escena con forma de pantalla. Por lo que añadiremos un nuevo método DrawPlane() al método RenderScene():

private void RenderScene()
{
    GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0);
 
    DrawPlane();
 
    DrawTerrain(camera);
 
    DrawMD3();
 
    DrawText();
}

En este método renderizaremos el plano y utilizando basicEffect le aplicaremos la textura de nuestro renderTarget:
private void DrawPlane()
        {
            foreach (ModelMesh mesh in plane.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.Texture = RT.GetTexture();
                    effect.TextureEnabled = true;
                    effect.World = getLocalWorld(new Vector3(-100, 140, 50), new Vector3(MathHelper.PiOver2, MathHelper.Pi / 2.5f, 0), 0.12f);
                    effect.View = camera.View;
                    effect.Projection = camera.Projection;
                }
                mesh.Draw();
            }
        }


Ahora ya tenemos la escena terminada:

 

En el juego BlueDragon esta pantalla aparece y desaparece durante las luchas, pero eso ya lo dejo en vuestras manos XD. Espero que os haya ayudado este artículo y el ejemplo en donde se aplica todo lo explicado.

Bueno, todo este artículo y el código correspondiente lo podéis encontrar en XNACommunity. Todo gentileza de Javier Cantón.

SaludetesCool

Posted: miércoles, 20 de agosto de 2008 1:16 por csharp
Archivado en: ,

Comentarios

alberto_corrales ha opinado:

joer, que crack Cantón

# agosto 21, 2008 18:28
No se permiten comentarios de usuarios anónimos