穩扎穩打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
[源碼下載]