English Version

Making of Blue Dragon

Introducción

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:

BlueDragon.jpg

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 abituales 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:

Image1.jpg

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:

Image2.jpg

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:

Image3.jpg

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.

Ejemplo

BlueDragon.part1.rar
BlueDragon.part2.rar
BlueDragon.part3.rar
BlueDragon.part4.rar



Created by Javier Cantón Ferrero.
MVP XNA-DirectX 2007/2009
MSP 2006/2008
Date 19/08/2008
Web www.codeplex.com/XNACommunity
Email javiuniversidad@gmail.com
blog: mirageproject.blogspot.com

Last edited Sep 6, 2008 at 2:06 PM by khronos, version 6

Comments

No comments yet.