绘制几何类型
当绘制3D几何对象时,你首先需要使用primitives(图元)定义它的形状。Primitives (图元)是可以被XNA绘制的最基本的对象,最常被使用的图元是三角形。任何形状,包括圆,如果圆的数量足够多的话,都能用来表示三角形。XNA Framework可以将点,线、三角形作为图元绘制。
XNA允许你定义这些图元的所有3D坐标。当你调用DrawUserPrimitives方法时,只要你提供正确的观察矩阵和投影矩阵,XNA会自动将这些3D坐标转换为对应的屏幕坐标。
XNA中有很多现成的结构来储存常见顶点类型,比如:VertexPositionColor, VertexPositionNormalTexture,VertexPositionTexture等结构。你也可以定义新的顶点类型。 目前,简单的VertexPositionColor类型就能满足需要,正如它的名字所示,这种顶点格式包含顶点的位置和颜色信息。位置是包含三个分量的矢量,定义顶点在3D空间中的坐标。XNA有自己的颜色系统,所以不需要使用System.Draw中的Color类。
要将3D坐标转换为屏幕上的像素位置,XNA需要知道相机的位置(存储在观察矩阵中)和关于相机镜头的某些细节(存储在投影矩阵中)。相机系统 代码 using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; namespace xnaDraw_test { class QuakeCamera { Matrix viewMatrix; Matrix projectionMatrix; Viewport viewPort; float leftrightRot; float updownRot; const float rotationSpeed = 0.005f ; Vector3 cameraPosition; MouseState originalMouseState; public QuakeCamera(Viewport viewPort) : this (viewPort, new Vector3( 0 , 1 , 15 ), 0 , 0 ) { // calls the constructor below with default startingPos and rotation values } public QuakeCamera(Viewport viewPort, Vector3 startingPos, float lrRot, float udRot) { this .leftrightRot = lrRot; this .updownRot = udRot; this .cameraPosition = startingPos; this .viewPort = viewPort; float viewAngle = MathHelper.PiOver4; float nearPlane = 0.5f ; float farPlane = 1000.0f ; projectionMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, viewPort.AspectRatio, nearPlane, farPlane); UpdateViewMatrix(); #if XBOX #else Mouse.SetPosition(viewPort.Width / 2 , viewPort.Height / 2 ); originalMouseState = Mouse.GetState(); #endif } public void Update(MouseState currentMouseState, KeyboardState keyState, GamePadState gamePadState) { if (currentMouseState != originalMouseState) { float xDifference = currentMouseState.X - originalMouseState.X; float yDifference = currentMouseState.Y - originalMouseState.Y; leftrightRot -= rotationSpeed * xDifference; updownRot -= rotationSpeed * yDifference; Mouse.SetPosition(viewPort.Width / 2 , viewPort.Height / 2 ); UpdateViewMatrix(); } if (keyState.IsKeyDown(Keys.Up) || keyState.IsKeyDown(Keys.W)) // Forward AddToCameraPosition( new Vector3( 0 , 0 , - 1 )); if (keyState.IsKeyDown(Keys.Down) || keyState.IsKeyDown(Keys.S)) // Backward AddToCameraPosition( new Vector3( 0 , 0 , 1 )); if (keyState.IsKeyDown(Keys.Right) || keyState.IsKeyDown(Keys.D)) // Right AddToCameraPosition( new Vector3( 1 , 0 , 0 )); if (keyState.IsKeyDown(Keys.Left) || keyState.IsKeyDown(Keys.A)) // Left AddToCameraPosition( new Vector3( - 1 , 0 , 0 )); if (keyState.IsKeyDown(Keys.Q)) // Up AddToCameraPosition( new Vector3( 0 , 1 , 0 )); if (keyState.IsKeyDown(Keys.Z)) // Down AddToCameraPosition( new Vector3( 0 , - 1 , 0 )); } private void AddToCameraPosition(Vector3 vectorToAdd) { float moveSpeed = 0.5f ; Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot); Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation); cameraPosition += moveSpeed * rotatedVector; UpdateViewMatrix(); } private void UpdateViewMatrix() { Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot); Vector3 cameraOriginalTarget = new Vector3( 0 , 0 , - 1 ); Vector3 cameraOriginalUpVector = new Vector3( 0 , 1 , 0 ); Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation); Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget; Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation); Vector3 cameraFinalUpVector = cameraPosition + cameraRotatedUpVector; viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector); } public float UpDownRot { get { return updownRot; } set { updownRot = value; } } public float LeftRightRot { get { return leftrightRot; } set { leftrightRot = value; } } public Matrix ProjectionMatrix { get { return projectionMatrix; } } public Matrix ViewMatrix { get { return viewMatrix; } } public Vector3 Position { get { return cameraPosition; } set { cameraPosition = value; UpdateViewMatrix(); } } public Vector3 TargetPosition { get { Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot); Vector3 cameraOriginalTarget = new Vector3( 0 , 0 , - 1 ); Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation); Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget; return cameraFinalTarget; } } public Vector3 Forward { get { Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot); Vector3 cameraForward = new Vector3( 0 , 0 , - 1 ); Vector3 cameraRotatedForward = Vector3.Transform(cameraForward, cameraRotation); return cameraRotatedForward; } } public Vector3 SideVector { get { Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot); Vector3 cameraOriginalSide = new Vector3( 1 , 0 , 0 ); Vector3 cameraRotatedSide = Vector3.Transform(cameraOriginalSide, cameraRotation); return cameraRotatedSide; } } public Vector3 UpVector { get { Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot); Vector3 cameraOriginalUp = new Vector3( 0 , 1 , 0 ); Vector3 cameraRotatedUp = Vector3.Transform(cameraOriginalUp, cameraRotation); return cameraRotatedUp; } } } }自定义顶点类型
当XNA中的预定义顶点类型不能满足要求时,可以手动创建结构来保存顶点数据。假设我们希望顶点中包含位置,纹理坐标,法线和切线信息,把这个结构称为VertexPosTexNorTan,它只是一个简单的数据集合:
struct VertexPosTexNorTan { public Vector3 Position; public Vector3 Normal; public Vector2 UV; public Vector3 Tangent; } 对于创建VertexDeclaration来说就稍微麻烦一点,它的构造函数需要一个VertexElement类型的数组,需要先构造出这个数组: 代码 VertexElement[] element = new VertexElement[] { new VertexElement( 0 , 0 ,VertexElementFormat.Vector3,VertexElementMethod.Default,VertexElementUsage.Position, 0 ), new VertexElement( 0 , 12 ,VertexElementFormat.Vector3,VertexElementMethod.Default,VertexElementUsage.Normal, 0 ), new VertexElement( 0 , 24 ,VertexElementFormat.Vector2,VertexElementMethod.Default,VertexElementUsage.TextureCoordinate, 0 ), new VertexElement( 0 , 32 ,VertexElementFormat.Vector3,VertexElementMethod.Default,VertexElementUsage.Tangent, 0 ), }; VertexElement里每个元素对应VertexPosTexNorTan中的一个成员。第一个参数表示关联到顶点分量的数据流索引。大多数情况下一条数据流就可以了,索引0表示第一条流。第二个参数是成员在顶点结构中的偏移值。Positon是结构中的第一个元素,因此偏移为0。Position是Vector3类型的变量,所以对第二个成员Normal来说,它在结构中的偏移值为12。这里的偏移值都以Byte为单位。下一个参数是VertexElementFormat类型的枚举,用来表示每个成员的数据类型。接下来的VertexElementMethod枚举表示在图形流水线中的图元镶嵌光栅化阶段如何对当前变量进行插值,一般使用默认值就可以。VertexElementUsage是一个比较重要的参数,指定当前成员的用途。比如,定义Position变量在程序中表示顶点的位置。最后一个变量也和VertexElementUsage枚举有关。有时,一个顶点可能会有一个以上的同用途元素,比如,有两组纹理坐标,为了区分两组不同的纹理坐标,必须指定一个索引值。这里,并没有重复用途的元素,所用使用0表示它是该用途的第一组数据就可以。有了VertexElement数据,创建VertexPosTexNorTan顶点相应的VertexDeclaration就很简单了:
decl = new VertexDeclaration(graphicsDevice, element);转载于:https://www.cnblogs.com/alex_85/archive/2010/03/01/1675695.html
相关资源:数据结构—成绩单生成器