XNA Game Engine教程系列3- Utilities,Camera和Actor

本教程将涵盖一些额外的工具并展示一个基本组件的创建过程。然后,我们将展示如何创建一个相机和演员(actor)。我们将在Engine类中添加两个工具类。第一个是数学辅助类,主要用于为绘制、相机、模型渲染等生成矩阵,第二个是一个图形辅助类,帮助创建渲染目标和resolve纹理。你不明白也没有关系,下面我们暂时还不会用到。首先是MathUtil类的代码:

using Microsoft.Xna.Framework;

namespace Innovation

{

public static class MathUtil

{

// Generates a projection matrix for a draw call

public static Matrix CreateProjectionMatrix()

{

return Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)Engine.GraphicsDevice.Viewport.Width / (float)Engine.GraphicsDevice.Viewport.Height, .01f, 1000000);

}

// Creates a world matrix

public static Matrix CreateWorldMatrix(Vector3 Translation)

{

return CreateWorldMatrix(Translation, Vector3.Zero);

}

// Creates a world matrix

public static Matrix CreateWorldMatrix(Vector3 Translation, Vector3 Rotation)

{

return CreateWorldMatrix(Translation, Rotation, Vector3.One);

}

// Creates a world matrix

public static Matrix CreateWorldMatrix(Vector3 Translation, Vector3 Rotation, Vector3 Scale)

{

return Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Translation);

}

// Converts a rotation vector into a rotation matrix

public static Matrix Vector3ToMatrix(Vector3 Rotation)

{

return Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z);

}

// Converts a rotation matrix into a rotation vector

public static Vector3 MatrixToVector3(Matrix Rotation)

{

Quaternion q = Quaternion.CreateFromRotationMatrix(Rotation);

return new Vector3(q.X, q.Y, q.Z);

}

}

}

其次是GraphicsUtil类的代码:

using Microsoft.Xna.Framework.Graphics;

namespace Innovation

{

public static class GraphicsUtil

{

// Creates a RenderTarget2D with the specified parameters

public static RenderTarget2D CreateRenderTarget()

{

return CreateRenderTarget(Engine.GraphicsDevice.Viewport.Width, Engine.GraphicsDevice.Viewport.Height);

}

// Creates a RenderTarget2D with the specified parameters

public static RenderTarget2D CreateRenderTarget(int Width, int Height)

{

return CreateRenderTarget(Width, Height, Engine.GraphicsDevice.DisplayMode.Format);

}

// Creates a RenderTarget2D with the specified parameters

public static RenderTarget2D CreateRenderTarget(int Width, int Height, SurfaceFormat Format)

{

return CreateRenderTarget(Width, Height, Format, Engine.GraphicsDevice.PresentationParameters.MultiSampleQuality, Engine.GraphicsDevice.PresentationParameters.MultiSampleType);

}

// Creates a RenderTarget2D with the specified parameters

public static RenderTarget2D CreateRenderTarget(int Width, int Height, SurfaceFormat Format, int MultiSampleQuality, MultiSampleType SampleType)

{ return new RenderTarget2D(Engine.GraphicsDevice, Width, Height, 1, Format, SampleType, MultiSampleQuality, RenderTargetUsage.DiscardContents);

}

// Creates a ResolveTexture2D

public static ResolveTexture2D CreateResolveTexture()

{

return new ResolveTexture2D(Engine.GraphicsDevice, Engine.GraphicsDevice.Viewport.Width, Engine.GraphicsDevice.Viewport.Height, 1, Engine.GraphicsDevice.DisplayMode.Format);

}

}

}

现在我们可以开始使用一些基本的组件了。实例只执行了清除backbuffer的操作。在我们开始之前,我们需要在demo项目中清理Game类(在我们的例子中是 “TestEnvironment”项目)。我们要删除大量无用的注释、方法和对象(在Game1.cs)中:

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Input;

using Innovation;

namespace TestEnvironment

{

Game1()

// Setup graphics

graphics = new GraphicsDeviceManager(this);

}

protected override void LoadContent()

{

}

protected override void Update(GameTime gameTime)

{

base.Update(gameTime);

}

protected override void Draw(GameTime gameTime)

{

base.Draw(gameTime);

}

}

}

现在我们要添加代码以初始化引擎。新增以下代码用以LoadContent(),Update()和Draw(),新增的代码要在base类前调用。

// Setup engine. We do this in the load method

// so that we know graphics will be ready for use

Engine.SetupEngine(graphics);

// Update the engine and game

Engine.Update(gameTime);

// Draw the engine and game

Engine.Draw(gameTime, ComponentType.All);

现在,当您按下F5键,您应该可以看到以下内容:

蓝屏

现在,我们可以创建组件。添加一个新的类并输入以下代码:

using Innovation;

using Microsoft.Xna.Framework.Graphics;

namespace TestEnvironment

{

class ClearScreen : Component

{

// Override the component's draw method

public override void Draw()

{

// Simply clear the backbuffer to red

Engine.GraphicsDevice.Clear(Color.Red);

}

}

}

现在,回到Game1类,在LoadContent()方法最后添加添加一个实例,代码如下:

// Create a new ClearScreen. It will automatically

 // be set the engine's DefaultScreen, currently

// Engine.BackGroundScreen

ClearScreen clear = new ClearScreen();

您现在应该可以看到以下画面:

红屏

下面我们开始实现更复杂的组件。首先是相机类。这仅仅是一个基类,其他相机将从它继承。这个相机没有任何运动函数,但它正是我们需要的,现在它仅仅指向一个目标位置并并生成我们需要绘制的矩阵,以下是代码,将这个类添加到游戏引擎的项目中:

using Microsoft.Xna.Framework;

using System;

namespace Innovation

{

// Basic Camera class

public class Camera : Component, I3DComponent

{

// Internal values

Vector3 position = Vector3.Zero;

Matrix rotationMatrix = Matrix.Identity;

Vector3 target = new Vector3(0, 0, -1);

Vector3 up = Vector3.Up;

Matrix view;

Matrix projection;

// The point the camera is looking at

public virtual Vector3 Target { get { return target; } set { target = value; } }

// The View and Projection matrices commonly used for rendering

public virtual Matrix View { get { return view; } set { view = value; } }

public virtual Matrix Projection { get { return projection; } set { projection = value; } }

public virtual Vector3 Up { get { return up; } set { up = value; } }

// Public I3DComponent values

public virtual Vector3 Position { get { return position; } set { position = value; } }

public virtual Vector3 Scale { get { return Vector3.One; } set { } }

public Vector3 EulerRotation { get { return MathUtil.MatrixToVector3(Rotation); } set { Rotation = MathUtil.Vector3ToMatrix(value); } }

// The rotation matrix used by the camera and the current up vector

public virtual Matrix Rotation { get { return rotationMatrix; } set { rotationMatrix = value; } }

public virtual BoundingBox BoundingBox { get { return new BoundingBox(Position - Vector3.One, Position + Vector3.One); } }

// Constructors

public Camera(GameScreen Parent) : base(Parent)

 // Set the rotation matrix's forward to this vector

Matrix rotationMatrixCopy = this.Rotation;

rotationMatrixCopy.Forward = newForward;

// Save a copy of "Up" (0, 1, 0)

Vector3 referenceVector = Vector3.Up;

// On the slim chance that the camera is pointed perfectly parallel with

// the Y Axis, we cannot use cross product with a parallel axis, so we

// change the reference vector to the forward axis (Z).

if (rotationMatrixCopy.Forward.Y == referenceVector.Y || rotationMatrixCopy.Forward.Y == -referenceVector.Y)

referenceVector = Vector3.Backward;

// Calculate the other parts of the rotation matrix

rotationMatrixCopy.Right = Vector3.Cross(this.Rotation.Forward, referenceVector);

rotationMatrixCopy.Up = Vector3.Cross(this.Rotation.Right, this.Rotation.Forward);

this.Rotation = rotationMatrixCopy;

// Use the rotation matrix to find the new up

Up = Rotation.Up;

// Recalculate View and Projection using the new Position, Target, and Up

View = Matrix.CreateLookAt(Position, Target, Up);

Projection = MathUtil.CreateProjectionMatrix();

}

}

}

下一个组件叫actor。这个类只是保存模型的位置,旋转和缩放等,并根据这些属性绘制此模型。你会看到它通过引擎service container的相机绘制。如果不能找到相机,它将会停止执行并抛出一个异常。以下是代码:

using System;

using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework;

namespace Innovation

{

public class Actor : Component, I3DComponent

{

// The model to draw Model model;

// I3DComponent values

public virtual Vector3 Position { get; set; }

public Vector3 EulerRotation { get { return MathUtil.MatrixToVector3(Rotation); } set { Rotation = MathUtil.Vector3ToMatrix(value); } }

public virtual Matrix Rotation { get; set; }

public virtual Vector3 Scale { get; set; }

public virtual BoundingBox BoundingBox { get { return new BoundingBox( Position - (Scale / 2), Position + (Scale / 2) ); } }

// Constructors take a model to draw and a position

public Actor(Model Model, Vector3 Position) : base()

{

Setup(Model, Position);

}

public Actor(Model Model, Vector3 Position, GameScreen Parent) : base(Parent)

{

Setup(Model, Position);

}

// Provide a method to setup the actor so we don't need to

// write it in each constructor void Setup(Model Model, Vector3 Position)

{

this.model = Model;

this.Position = Position;

Scale = Vector3.One;

EulerRotation = Vector3.Zero;

}

public override void Draw() {

// Look for a camera in the service container

Camera camera = Engine.Services.GetService<Camera>();

// Throw an exception if one isn't present

if (camera == null)

{

throw new Exception("Camera not found in engine's" + "service container, cannot draw");

}

// Generate the world matrix (describes the objects movement in 3D)

Matrix world = MathUtil.CreateWorldMatrix(Position, Rotation, Scale);

Matrix[] transforms = new Matrix[model.Bones.Count];

model.CopyAbsoluteBoneTransformsTo(transforms);

// Set some renderstates so the model will draw properly

Engine.GraphicsDevice.RenderState.AlphaBlendEnable = true;

Engine.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;

Engine.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;

Engine.GraphicsDevice.RenderState.DepthBufferEnable = true;

// Loop through meshes and effects and set them up to draw

foreach (ModelMesh mesh in model.Meshes)

{

foreach (BasicEffect effect in mesh.Effects)

{

// Set effect parameters

effect.Parameters["World"].SetValue(transforms[mesh.ParentBone.Index] * world);

effect.Parameters["View"].SetValue(camera.View);

effect.Parameters["Projection"].SetValue(camera.Projection);

// Enable lighting

effect.EnableDefaultLighting();

}

// Draw the mesh

mesh.Draw();

}

}

}

}

最后,我们要添加一个相机和actor。您需要将content文件添加到content项目中,在Game1类的LoadContent()方法最后添加下列代码:

// Create a new Camera

Camera camera = new Camera();

// Setup its position and target

camera.Position = new Vector3(1, 1, 2);

camera.Target = new Vector3(0, 0, 0);

// Add it to the service container

Engine.Services.AddService(typeof(Camera), camera);

// Create a new actor

Actor actor = new Actor(Engine.Content.Load<Model>("Content/ig_box"), new Vector3(0, 0, 0));

现在,当您运行游戏,您应该在屏幕上看到所绘制的模型。

绘制的模型

下次我们将做创建更多的组件!


发布时间:2008/12/25 下午3:30:30  阅读次数:7396

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号