稳扎稳打Silverlight(68) - 5.0 XNA 之绘制 3D 图形
作者:webabcd
介绍
Silverlight 5.0 XNA
- XNA 绘制 3D 图形的 Demo
在线DEMO
http://www.cnblogs.com/webabcd/archive/2012/03/05/2379862.html
示例
Cube.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Xna.Framework;
namespace Silverlight50.XNA
{
/// <summary>
/// 描述正方体的相关信息
/// </summary>
public static class Cube
{
/// <summary>
/// 正方体的每个顶点的位置(正方体一共 8 个顶点)
/// </summary>
public static Vector3[] Corners = new Vector3[]
{
new Vector3(1f, 1f, 1f),
new Vector3(1f, -1f, 1f),
new Vector3(-1f, -1f, 1f),
new Vector3(-1f, 1f, 1f),
new Vector3(1f, 1f, -1f),
new Vector3(1f, -1f, -1f),
new Vector3(-1f, -1f, -1f),
new Vector3(-1f, 1f, -1f)
};
/// <summary>
/// 指定 Corners 里的 4 个顶点组成一个面(正方体一共 4 个面)
/// </summary>
public static int[][] Faces = new int[][]
{
new int[] { 0, 1, 2, 3 },
new int[] { 0, 3, 7, 4 },
new int[] { 0, 4, 5, 1 },
new int[] { 1, 5, 6, 2 },
new int[] { 2, 6, 7, 3 },
new int[] { 4, 7, 6, 5 }
};
}
}
PolygonHelper.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Windows.Graphics;
namespace Silverlight50.XNA
{
/// <summary>
/// 绘制多边体的帮助类
/// </summary>
public class PolygonHelper
{
// 顶点缓冲器,可以将顶点信息以流的方式输出到图形设备中
protected VertexBuffer vb;
// 纹理
protected Texture2D texture;
/*
* BasicEffect - 基础效果,可以通过简单的属性设置来实现包含光照、纹理、变换等效果的物体的呈现
* BasicEffect.View - 视图矩阵(View 矩阵)
* BasicEffect.Projection - 投影矩阵(Projection 矩阵)
* BasicEffect.VertexColorEnabled - 是否允许在此效果中启用顶点信息中的颜色数据
*/
protected BasicEffect be;
protected Matrix world;
public Matrix World { get { return world; } set { world = value; } }
/// <summary>
/// 初始化多变形体
/// </summary>
/// <param name="corners">顶点位置信息数组</param>
/// <param name="faces">组成每个面的点集合数组</param>
/// <param name="color">多变形体的颜色</param>
public PolygonHelper(Vector3[] corners, int[][] faces, Color color)
{
GraphicsDevice g = GraphicsDeviceManager.Current.GraphicsDevice;
VertexPositionNormalTexture[] vertices = CreateVertices(corners, faces);
vb = new VertexBuffer(g, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
vb.SetData(0, vertices, 0, vertices.Length, VertexPositionNormalTexture.VertexDeclaration.VertexStride);
texture = new Texture2D(g, 1, 1, false, SurfaceFormat.Color);
texture.SetData<Color>(new Color[1] { color });
be = new BasicEffect(g);
be.EnableDefaultLighting(); // 使用默认光源效果
be.LightingEnabled = true;
be.Texture = texture;
be.TextureEnabled = true;
}
/// <summary>
/// 绘制多变形体
/// </summary>
/// <param name="view">视图矩阵</param>
/// <param name="projection">投影矩阵</param>
public void Draw(Matrix view, Matrix projection)
{
GraphicsDevice g = GraphicsDeviceManager.Current.GraphicsDevice;
g.SetVertexBuffer(vb); // 绑定顶点缓冲器到图形设备中
be.World = world;
be.View = view;
be.Projection = projection;
be.CurrentTechnique.Passes[0].Apply();
g.DrawPrimitives(PrimitiveType.TriangleList, 0, vb.VertexCount / 3); // 绘制基元
}
/// <summary>
/// 返回一个 VertexPositionNormalTexture 数组
/// </summary>
/// <param name="corners">顶点位置信息数组</param>
/// <param name="faces">组成每个面的点集合数组</param>
private static VertexPositionNormalTexture[] CreateVertices(Vector3[] corners, int[][] faces)
{
int triangleCount = 0;
// 组成一个面所用的顶点数-2就是所用的三角形数
foreach (int[] face in faces)
{
triangleCount += face.Length - 2;
}
// 用到的顶点数 = 用到的三角形数 * 3
VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[triangleCount * 3];
int i = 0;
foreach (int[] face in faces)
{
// 定义每个三角形的顶点信息
for (int j = 0; j < face.Length - 2; j++)
{
vertices[i++] = new VertexPositionNormalTexture(corners[face[0]], Vector3.Zero, Vector2.Zero);
vertices[i++] = new VertexPositionNormalTexture(corners[face[j + 1]], Vector3.Zero, Vector2.Zero);
vertices[i++] = new VertexPositionNormalTexture(corners[face[j + 2]], Vector3.Zero, Vector2.Zero);
}
Vector3 vectorA = vertices[i - 1].Position - vertices[i - 3].Position;
Vector3 vectorB = vertices[i - 1].Position - vertices[i - 2].Position;
Vector3 normal = Vector3.Cross(vectorB, vectorA);
for (int j = 0; j < (face.Length - 2) * 3; j++)
vertices[i - 1 - j].Normal = normal;
}
return vertices;
}
}
}
XNA/Demo.xaml
<navigation:Page x:Class="Silverlight50.XNA.Demo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
d:DesignWidth="640" d:DesignHeight="480"
Title="Demo Page">
<Grid x:Name="LayoutRoot" Background="White">
<DrawingSurface Name="drawingSurface" Loaded="drawingSurface_Loaded" Draw="drawingSurface_Draw" SizeChanged="drawingSurface_SizeChanged" />
</Grid>
</navigation:Page>
XNA/Demo.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;
using System.Windows.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Silverlight50.XNA
{
public partial class Demo : Page
{
// 可视区的长宽比,一般就是游戏窗口的宽除以游戏窗口的高
private float _aspectRatio = 1f;
// 用于绘制多边体的对象
private PolygonHelper _polygonHelper;
public Demo()
{
InitializeComponent();
}
private void drawingSurface_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
}
/// <summary>
/// 检查 GPU 渲染模式是否可用
/// </summary>
private bool CheckAvailable()
{
// 检查当前是否是 GPU 渲染模式
if (GraphicsDeviceManager.Current.RenderMode == RenderMode.Hardware)
return true;
// 无法启用 GPU 渲染模式时,显示其原因
string errorMsg = "";
switch (GraphicsDeviceManager.Current.RenderModeReason)
{
case RenderModeReason.Not3DCapable:
errorMsg = "显卡不支持 Shader Model 2.0 +";
break;
case RenderModeReason.GPUAccelerationDisabled:
errorMsg = "请设置 <param name=\"EnableGPUAcceleration\" value=\"true\" />";
break;
case RenderModeReason.TemporarilyUnavailable:
errorMsg = "显卡有问题,请重启后再试";
break;
case RenderModeReason.SecurityBlocked:
errorMsg = "请通过右键配置 Silverlight,在权限选项卡中允许此站点进行 3D 图形加速";
break;
}
MessageBox.Show(errorMsg);
return false;
}
private void drawingSurface_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
// DrawingSurface 就相当于游戏窗口,所以 DrawingSurface 的宽高比就是 aspectRatio
_aspectRatio = (float)(drawingSurface.ActualWidth / drawingSurface.ActualHeight);
}
private void drawingSurface_Draw(object sender, DrawEventArgs e)
{
if (_polygonHelper == null && CheckAvailable())
_polygonHelper = new PolygonHelper(Cube.Corners, Cube.Faces, new Color(1f, 0f, 0f));
GraphicsDevice g = GraphicsDeviceManager.Current.GraphicsDevice;
/*
* Matrix CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector) - 实例化视图矩阵
* Vector3 cameraPosition - 摄像机的位置坐标
* Vector3 cameraTarget - 摄像机镜头的朝向向量
* Vector3 cameraUpVector - 摄像机机身的顶部的上方的向量
*/
Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 8.0f), Vector3.Zero, Vector3.Up);
/*
* CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) - 实例化投影矩阵
* float fieldOfView - Y 轴方向上的视角弧度,一般是四分之一个 PI
* float aspectRatio - 可视区的长宽比,一般就是游戏窗口的宽除以游戏窗口的高
* float nearPlaneDistance - 当物体离摄像机多近时无法看清
* float farPlaneDistance - 当物体离摄像机多远时无法看清
*/
Matrix projection = Matrix.CreatePerspectiveFieldOfView(0.85f, _aspectRatio, 0.01f, 1000.0f);
// 指定旋转轴
Vector3 axis = new Vector3(-0.5f, 1, -0.5f);
axis.Normalize();
// 通过四元数旋转
_polygonHelper.World = Matrix.CreateFromQuaternion(Quaternion.CreateFromAxisAngle(axis, (float)e.TotalTime.TotalSeconds * 3));
// 清除游戏窗口上的所有对象,然后以指定的颜色作为背景
g.Clear(new Color(0.8f, 0.8f, 0.8f, 1.0f));
// 绘制图像
_polygonHelper.Draw(view, projection);
// 结束本次 Draw ,并再次触发 Draw 事件
e.InvalidateSurface();
}
}
}
OK
[源码下载]