程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> UWP簡單示例(二):快速開始你的3D編程,uwp3d

UWP簡單示例(二):快速開始你的3D編程,uwp3d

編輯:C#入門知識

UWP簡單示例(二):快速開始你的3D編程,uwp3d


准備

  IDE:Visual Studio 2015

  了解並學習:SharpDx官方GitHub

  推薦Demo:SharpDX_D3D12HelloWorld

第一節 世界

  世界坐標系是一個特殊的坐標系,它建立了描述其他坐標系所需要的參考框架。

  世界坐標系

  從另一方面說,不能用更大的、外部的坐標系來描述世界坐標系

  關於世界坐標系的典型問題都是關於初始位置和環境的:

  • 每個物體的位置和方向
  • 攝像機的位置和方向
  • 世界中每一點的地形是什麼(如山丘、建築、湖泊等)
  • 一個物體從哪裡來,到哪裡去(NPC的運動策略)

  左、右手坐標系

  所有的2D坐標系是等價的,但3D坐標系有“手性”之分

  左、右手坐標系可以互相轉換,最簡單的方法是只翻轉一個軸的符號

  傳統的計算機圖形學使用左手坐標系,而線性代數則傾向於使用右手坐標系

  SharpDx采用左手坐標系,即X軸由右向左,Y軸由下至上,Z軸由裡至外

  SharpDx的世界有多大

  首先,這個世界是有限且離散的

  描述三維坐標需要使用SharpDx或System.Numerics命名空間下的Vector3類型

  Vector3表示一個三維向量,它的x,y,z分量都是float類型(單精度浮點數),我們知道float范圍是-3.40E+38 ~ +3.40E+38

  而原子的直徑是0.1nm級別,若以它作為基本單位,那麼這個世界大約是一個邊長6.80E+25公裡的方盒(約71877億光年)

  這個世界足夠大了嗎

  目前認為銀河系直徑是10~12萬光年,宇宙可視直徑是920億光年

  單精度浮點數可精確到小數點後6位,即當前世界最小分辨率是10-6倍原子大小

  那麼離散的float類型足以描述現實世界了嗎?向您介紹計算機圖形學第一准則,留給您思考:

  • 計算機圖形學第一准則:近似原則如果它看上去是對的它就是對的:)
Imports SharpDX ''' <summary> ''' 表示一個三維世界 ''' </summary> Public Interface IWorld ''' <summary> ''' 模型頂點變換矩陣的數組 ''' </summary> ''' <returns></returns> Property ModelMatrix As Matrix() ''' <summary> ''' 更新模型頂點變換矩陣 ''' </summary> Sub Update() End Interface VB.NET-IWorld using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using SharpDX; /// <summary> /// 表示一個三維世界 /// </summary> public interface IWorld { /// <summary> /// 模型頂點變換矩陣的數組 /// </summary> /// <returns></returns> Matrix[] ModelMatrix { get; set; } /// <summary> /// 更新模型頂點變換矩陣 /// </summary> void Update(); } C#-IWorld

第二節 物體

  在編程中,具有宏觀形狀、體積或質量的抽象對象。

  位置Location

  一個三維向量,它表示當前物體在世界坐標系中的絕對位置

  比例Scale

  一個三維向量,表示當前物體x,y,z軸縮放比例

  旋轉Rotation

  通常物體角位移有歐拉角和四元數兩種表示方式

  歐拉角:

  • 歐拉角有三個分量,偏航角Yaw、俯仰角Pitch、橫滾角Roll
  • 給定方位的表達方式不唯一
  • 兩個角度間求插值非常困難
  • 萬向鎖是一個底層問題,至今沒有簡單的解決方案

  四元數:

  • 四元數(Quaternion)有四個分量,它是一個超復數
  • 四元數能夠平滑插值,但它比歐拉角多占用33.3%的存儲空間
  • 多個四元數表示一系列旋轉變換時,將它們相乘(而非直接相加)
  • 四元數“減法”,一個變換Q1到另一個變換Q2的差△Q等於Q1的逆乘以Q2(而非直接相減)
  • 通過標准化四元數確保它為單位大小,否則它將不合法
Imports SharpDX ''' <summary> ''' 表示一個可包含若干子對象的剛體 ''' </summary> Public Interface IRigidBody ''' <summary> ''' 子物體 ''' </summary> ''' <returns></returns> Property Children As List(Of IRigidBody) ''' <summary> ''' 父物體 ''' </summary> ''' <returns></returns> Property Parent As IRigidBody ''' <summary> ''' 位置 ''' </summary> ''' <returns></returns> Property Location As Vector3 ''' <summary> ''' 縮放 ''' </summary> ''' <returns></returns> Property Scale As Vector3 ''' <summary> ''' 旋轉 ''' </summary> ''' <returns></returns> Property Qua As Quaternion ''' <summary> ''' 可見性 ''' </summary> ''' <returns></returns> Property Visible As Boolean Sub Update() End Interface VB.NET-IRigidBody using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using SharpDX; /// <summary> /// 表示一個可包含若干子對象的剛體 /// </summary> public interface IRigidBody { /// <summary> /// 子物體 /// </summary> /// <returns></returns> List<IRigidBody> Children { get; set; } /// <summary> /// 父物體 /// </summary> /// <returns></returns> IRigidBody Parent { get; set; } /// <summary> /// 位置 /// </summary> /// <returns></returns> Vector3 Location { get; set; } /// <summary> /// 縮放 /// </summary> /// <returns></returns> Vector3 Scale { get; set; } /// <summary> /// 旋轉 /// </summary> /// <returns></returns> Quaternion Qua { get; set; } /// <summary> /// 可見性 /// </summary> /// <returns></returns> bool Visible { get; set; } void Update(); } C#-IRigidBody

第三節 矩陣與線性變換

  線性變換總是把線性子空間變為線性子空間,但是維數可能降低。矩陣的本質就是描述線性變換。

  模型與世界空間

  物體最開始由物體空間來描述。其中常見的信息包括頂點位置和表面法向量

  可將坐標從物體空間轉換到世界空間中,此過程稱作模型變換

  通常,光照計算使用世界空間,其實光照計算只需確保幾何體和光線在同一空間

  攝像機空間

  通過視變換,頂點從世界空間變換到攝像機空間,此空間也稱作眼睛空間

  裁剪與屏幕空間

  裁剪空間又名標准視體空間,它是為透視投影做准備

  一旦用視錐完成了幾何體裁剪,即可向屏幕空間投影

  ModelMatrix=World*View*Projection

  World=ScaleMatrix*RotationMatrix*TranslateMatrix:

  • 縮放矩陣 ScaleMatrix=Matrix.Scaling(Object.Scale)
  • 旋轉矩陣 RotationMatrix=Matrix.RotationQuaternion(Object.Quaternion)
  • 平移矩陣 TranslateMatrix=Matrix.Translation(Object.Location)
  • 默認旋轉中心是原點,所以這三者相乘的順序不能變

  View=Matrix.LookAtLH(eye,target,up):

  • 眼睛位置 eye=New Vector3(0,0,100),表示當前攝像機位於Z軸100值處
  • 視點位置 target=New Vector3(0,0,0),表示當前攝像機看向3D空間的原點
  • 向上向量 up=Vector.UnitY,當前攝像機的向上方向
  • LH表示左手坐標系,Matrix.LookAtRH是用於右手坐標系

  Projection=Matrix.PerspectiveFovLH(fov, aspect, znear, zfar):

  • 視椎體水平角 fov=Math.PI/ 3.0F,即水平可視角范圍,通常為60度
  • 視錐體寬高比 aspect=ScreenWidth/ScreenHeight,通常和屏幕寬高比一致
  • 近裁面深度值 znear=1,即最近可視范圍,用戶可自由設置
  • 遠裁面深度值 zfar=10000,即最遠可視范圍,用戶可自由設置
  • 實際上這是裁剪變換矩陣,投影到屏幕是由API完成的
Imports SharpDX ''' <summary> ''' 表示用於視變換的攝像機 ''' </summary> Public Interface ICamera ''' <summary> ''' 獲取或設置攝像機位置 ''' </summary> ''' <returns></returns> Property Eye As Vector3 ''' <summary> ''' 獲取或設置目標視點位置 ''' </summary> ''' <returns></returns> Property Target As Vector3 ''' <summary> ''' 獲取或設置攝像機向上方向 ''' </summary> ''' <returns></returns> Property Up As Vector3 ''' <summary> ''' 獲取當前視變換矩陣 ''' </summary> ''' <returns></returns> ReadOnly Property View As Matrix End Interface VB.NET-ICamera using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using SharpDX; /// <summary> /// 表示用於視變換的攝像機 /// </summary> public interface ICamera { /// <summary> /// 獲取或設置攝像機位置 /// </summary> /// <returns></returns> Vector3 Eye { get; set; } /// <summary> /// 獲取或設置目標視點位置 /// </summary> /// <returns></returns> Vector3 Target { get; set; } /// <summary> /// 獲取或設置攝像機向上方向 /// </summary> /// <returns></returns> Vector3 Up { get; set; } /// <summary> /// 獲取當前視變換矩陣 /// </summary> /// <returns></returns> Matrix View { get; } } C#-ICamera

第四節 三角網格

  多邊形網格用來模擬復雜物體的表面,任意多邊形網格都能轉成三角網格。

  表示網格

  多邊形和三角網格在圖形學和建模中廣泛使用,最直接表示方法是用三角形數組

  三角網格需要存儲三類信息:

  • 頂點 每個三角形都有三個頂點,各頂點都有可能和其他三角形共享
  • 邊    連接兩個頂點的邊,每個三角形有三條邊
  • 面    每個三角形對應一個面,我們可以用頂點或者邊列表表示面

  索引三角網格

  在索引三角網格中,我們維護兩個列表:頂點表和三角形表

  每個頂點包含一個3D位置,也可能有如紋理映射坐標、表面法向量、光照值等復雜數據

  每個三角形由頂點列表的三個索引組成

  頂點列出的順序非常重要,它決定面是“正面”還是“反面”

  另外,表面法向量、紋理映射保存在三角形一級

  索引三角形列表中的鄰接信息是隱含的,邊信息不會被直接存儲

  我們可以通過搜索三角形表找出公共邊

  創建一個立方體

  一個立方體有6個矩形面,每個面有4個頂點

  一個矩形面由兩個三角形組成

  可見我們共需要24個頂點,12個三角形

  假若不分開描述各面,8個頂點就足夠描述一個六面體,但仍需要12個三角形

''' <summary> ''' 表示一個頂點 ''' </summary> Public Structure Vertex Public Position As Vector3 Public Color As Vector4 Public Sub New(position As Vector3, color As Vector4) Me.Position = position Me.Color = color End Sub End Structure VB.NET-Vertex ''' <summary> ''' 返回一個指定長寬高的正六面體的頂點數組 ''' </summary> Public Shared Function CreateCube(w As Single, h As Single, d As Single) As Vertex() w = w / 2 h = h / 2 d = d / 2 Dim vertices As Vertex() = New Vertex() { New Vertex(New Vector3(-w, h, d), New Vector4(0, 1, 0, 1)), New Vertex(New Vector3(w, h, d), New Vector4(0, 1, 0, 1)), New Vertex(New Vector3(w, h, -d), New Vector4(0, 1, 0, 1)), New Vertex(New Vector3(-w, h, -d), New Vector4(0, 1, 0, 1)), New Vertex(New Vector3(-w, -h, d), New Vector4(1, 0, 1, 1)), New Vertex(New Vector3(w, -h, d), New Vector4(1, 0, 1, 1)), New Vertex(New Vector3(w, -h, -d), New Vector4(1, 0, 1, 1)), New Vertex(New Vector3(-w, -h, -d), New Vector4(1, 0, 1, 1)), New Vertex(New Vector3(-w, -h, d), New Vector4(1, 0, 0, 1)), New Vertex(New Vector3(-w, h, d), New Vector4(1, 0, 0, 1)), New Vertex(New Vector3(-w, h, -d), New Vector4(1, 0, 0, 1)), New Vertex(New Vector3(-w, -h, -d), New Vector4(1, 0, 0, 1)), New Vertex(New Vector3(w, -h, d), New Vector4(1, 1, 0, 1)), New Vertex(New Vector3(w, h, d), New Vector4(1, 1, 0, 1)), New Vertex(New Vector3(w, h, -d), New Vector4(1, 1, 0, 1)), New Vertex(New Vector3(w, -h, -d), New Vector4(1, 1, 0, 1)), New Vertex(New Vector3(-w, h, d), New Vector4(0, 1, 1, 1)), New Vertex(New Vector3(w, h, d), New Vector4(0, 1, 1, 1)), New Vertex(New Vector3(w, -h, d), New Vector4(0, 1, 1, 1)), New Vertex(New Vector3(-w, -h, d), New Vector4(0, 1, 1, 1)), New Vertex(New Vector3(-w, h, -d), New Vector4(0, 0, 1, 1)), New Vertex(New Vector3(w, h, -d), New Vector4(0, 0, 1, 1)), New Vertex(New Vector3(w, -h, -d), New Vector4(0, 0, 1, 1)), New Vertex(New Vector3(-w, -h, -d), New Vector4(0, 0, 1, 1))} Return vertices End Function VB.NET-CreateCube using SharpDx; /// <summary> /// 表示一個存儲3D位置與顏色信息的頂點 /// </summary> public struct Vertex { public Vector3 Position; public Vector4 Color; public Vertex(Vector3 position, Vector4 color) { this.Position = position; this.Color = color; } } C#-Vertex /// <summary> /// 返回一個指定長寬高的正六面體的頂點數組 /// </summary> public static Vertex[] CreateCube(float w, float h, float d) { w = w / 2; h = h / 2; d = d / 2; Vertex[] vertices = new Vertex[] { new Vertex(new Vector3(-w, h, d), new Vector4(0, 1, 0, 1)), new Vertex(new Vector3(w, h, d), new Vector4(0, 1, 0, 1)), new Vertex(new Vector3(w, h, -d), new Vector4(0, 1, 0, 1)), new Vertex(new Vector3(-w, h, -d), new Vector4(0, 1, 0, 1)), new Vertex(new Vector3(-w, -h, d), new Vector4(1, 0, 1, 1)), new Vertex(new Vector3(w, -h, d), new Vector4(1, 0, 1, 1)), new Vertex(new Vector3(w, -h, -d), new Vector4(1, 0, 1, 1)), new Vertex(new Vector3(-w, -h, -d), new Vector4(1, 0, 1, 1)), new Vertex(new Vector3(-w, -h, d), new Vector4(1, 0, 0, 1)), new Vertex(new Vector3(-w, h, d), new Vector4(1, 0, 0, 1)), new Vertex(new Vector3(-w, h, -d), new Vector4(1, 0, 0, 1)), new Vertex(new Vector3(-w, -h, -d), new Vector4(1, 0, 0, 1)), new Vertex(new Vector3(w, -h, d), new Vector4(1, 1, 0, 1)), new Vertex(new Vector3(w, h, d), new Vector4(1, 1, 0, 1)), new Vertex(new Vector3(w, h, -d), new Vector4(1, 1, 0, 1)), new Vertex(new Vector3(w, -h, -d), new Vector4(1, 1, 0, 1)), new Vertex(new Vector3(-w, h, d), new Vector4(0, 1, 1, 1)), new Vertex(new Vector3(w, h, d), new Vector4(0, 1, 1, 1)), new Vertex(new Vector3(w, -h, d), new Vector4(0, 1, 1, 1)), new Vertex(new Vector3(-w, -h, d), new Vector4(0, 1, 1, 1)), new Vertex(new Vector3(-w, h, -d), new Vector4(0, 0, 1, 1)), new Vertex(new Vector3(w, h, -d), new Vector4(0, 0, 1, 1)), new Vertex(new Vector3(w, -h, -d), new Vector4(0, 0, 1, 1)), new Vertex(new Vector3(-w, -h, -d), new Vector4(0, 0, 1, 1)) }; return vertices; } C#-CreateCube

第五節 方塊人物

  可直接用一個骨骼模型描述生物外形,至少MineCraft是這樣的。

  骨骼關系

  一個骨骼節點有若干子骨骼,但只能有一個父骨骼

  易見我們可以用一個樹形結構來描述骨骼系統

  父子骨骼間存在一種“聯動”關系,比如我們移動右手手臂,右手也會跟隨移動

  為體現這種“聯動”,在編程中需要將作用於某個骨骼的的變換也同等作用於它的子骨骼

  人體骨骼方塊

  上部(10塊):頭部、頸部、左右肩、左右上臂,左右下臂,左右手

  中部(2 塊):胸部、腰部

  下部(8 塊):左右骻、左右大腿,左右小腿和左右腳

  通常,腰部是根節點的較好選擇

Imports SharpDX ''' <summary> ''' 表示骨骼結點 ''' </summary> Public Class Bone Inherits RigidBodyBase Public Overrides Property Qua As Quaternion Set(value As Quaternion) If IsNewQua Then IsNewQua = False sQua = value sQua.Invert() sQua.Normalize() End If mQua = value End Set Get Return Quaternion.Normalize(sQua * mQua) End Get End Property ''' <summary> ''' 絕對坐標 ''' </summary> Public AbsoluteLoc As Vector3 ''' <summary> ''' 相對坐標 ''' </summary> Public RelativeLoc As Vector3 ''' <summary> ''' 父骨骼 ''' </summary> Public ParentBone As Bone ''' <summary> ''' 骨骼相對旋轉 ''' </summary> Public BoneQua As New Quaternion(0, 0, 0, 1) ''' <summary> ''' 子骨骼 ''' </summary> Public ChildrenBone As New List(Of Bone) ''' <summary> ''' 索引 ''' </summary> Public Index As Integer Private mQua As New Quaternion(0, 0, 0, 1) Private sQua As New Quaternion(0, 0, 0, 1) Private IsNewQua As Boolean = True Public Sub New(loc As Vector3, scale As Vector3) Me.RelativeLoc = loc * 10 Me.Scale = scale End Sub End Class VB.NET-Bone Imports SharpDX ''' <summary> ''' 表示一個用於描述骨骼信息的對象 ''' </summary> Public Class BoneInf Public Loc As Vector3 Public Scale As Vector3 Public ParentIndex As Integer Public ChildIndexArr() As Integer Public Sub New(l As Vector3, s As Vector3, p As Integer, c As Integer()) Loc = New Vector3(l.Z, l.Y, l.X) Scale = New Vector3(s.Z, s.Y, s.X) ParentIndex = p ChildIndexArr = c End Sub End Class VB.NET-BoneInf Imports SharpDX ''' <summary> ''' 表示一個人類模型 ''' </summary> Public Class Human Inherits RigidBodyBase Public RootBone As Bone Dim BoneInfArr() As BoneInf = { New BoneInf(New Vector3(0, 0, 0), New Vector3(1, 1, 1), 0, New Integer() {1, 12, 16}),'腰部0 New BoneInf(New Vector3(0, 5, 0), New Vector3(2.5, 5, 1), 0, New Integer() {2, 4, 8}),'胸部1 New BoneInf(New Vector3(0, 1, 0), New Vector3(0.7, 1, 1), 1, New Integer() {3}),'頸部2 New BoneInf(New Vector3(0, 1.5, 0), New Vector3(1.3, 1.5, 1), 2, New Integer() {}),'頭部3 New BoneInf(New Vector3(-2, 0, 0), New Vector3(2, 1, 1), 1, New Integer() {5}),'左肩4 New BoneInf(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 4, New Integer() {6}),'左上臂5 New BoneInf(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 5, New Integer() {7}),'左小臂6 New BoneInf(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 6, New Integer() {}),'左手7 New BoneInf(New Vector3(2, 0, 0), New Vector3(2, 1, 1), 1, New Integer() {9}),'右肩8 New BoneInf(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 8, New Integer() {10}),'右上臂9 New BoneInf(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 9, New Integer() {11}),'右小臂10 New BoneInf(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 10, New Integer() {}),'右手11 New BoneInf(New Vector3(-0.8, 0, 0), New Vector3(0.8, 1, 1), 0, New Integer() {13}),'左骻12 New BoneInf(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 12, New Integer() {14}),'左大腿13 New BoneInf(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 13, New Integer() {15}),'左小腿14 New BoneInf(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 14, New Integer() {}),'左腳15 New BoneInf(New Vector3(0.8, 0, 0), New Vector3(0.8, 1, 1), 0, New Integer() {17}),'右骻16 New BoneInf(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 16, New Integer() {18}),'右大腿17 New BoneInf(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 17, New Integer() {19}),'右小腿18 New BoneInf(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 18, New Integer() {})'右腳19 } Public Sub New() CreateBody() CalcBone(RootBone) End Sub ''' <summary> ''' 更新指定索引的骨骼 ''' </summary> ''' <param name="qua">旋轉</param> ''' <param name="index">骨骼索引</param> Public Sub UpdateBone(qua As Quaternion, index As Integer) qua.Normalize() DirectCast(Children(index), Bone).Qua = qua CalcBone(DirectCast(Children(index), Bone).ParentBone) End Sub ''' <summary> ''' 更新所有子骨骼 ''' </summary> ''' <param name="parent"></param> Private Sub CalcBone(parent As Bone) For Each SubBone As Bone In parent.ChildrenBone SubBone.BoneQua = Quaternion.Normalize(Me.Qua * SubBone.Qua) Dim tempLoc = (Matrix.Translation(SubBone.RelativeLoc) * Matrix.RotationQuaternion(SubBone.BoneQua)).TranslationVector SubBone.AbsoluteLoc = parent.AbsoluteLoc + tempLoc SubBone.Location = parent.AbsoluteLoc + tempLoc / 2 CalcBone(SubBone) Next End Sub ''' <summary> ''' 創建人物身體的所有骨骼 ''' </summary> Private Sub CreateBody() For i = 0 To BoneInfArr.Count - 1 Children.Add(New Bone(BoneInfArr(i).Loc, BoneInfArr(i).Scale)) DirectCast(Children(i), Bone).Index = i Next For i = 0 To BoneInfArr.Count - 1 DirectCast(Children(i), Bone).ParentBone = Children(BoneInfArr(i).ParentIndex) For Each SubIndex In BoneInfArr(i).ChildIndexArr DirectCast(Children(i), Bone).ChildrenBone.Add(Children(SubIndex)) Next Next RootBone = DirectCast(Children(0), Bone) RootBone.Parent = RootBone End Sub End Class VB.NET-Human using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using SharpDX; /// <summary> /// 表示骨骼結點 /// </summary> public class Bone : RigidBodyBase { public override Quaternion Qua { get { return Quaternion.Normalize(sQua * mQua); } set { if (IsNewQua) { IsNewQua = false; sQua = value; sQua.Invert(); sQua.Normalize(); } mQua = value; } } /// <summary> /// 絕對坐標 /// </summary> public Vector3 AbsoluteLoc; /// <summary> /// 相對坐標 /// </summary> public Vector3 RelativeLoc; /// <summary> /// 父骨骼 /// </summary> public Bone ParentBone; /// <summary> /// 骨骼相對旋轉 /// </summary> public Quaternion BoneQua = new Quaternion(0, 0, 0, 1); /// <summary> /// 子骨骼 /// </summary> public List<Bone> ChildrenBone = new List<Bone>(); /// <summary> /// 索引 /// </summary> public int Index; private Quaternion mQua = new Quaternion(0, 0, 0, 1); private Quaternion sQua = new Quaternion(0, 0, 0, 1); private bool IsNewQua = true; public Bone(Vector3 loc, Vector3 scale) { this.RelativeLoc = loc * 10; this.Scale = scale; } } C#-Bone using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using SharpDX; /// <summary> /// 表示一個用於描述骨骼信息的對象 /// </summary> public class BoneInf { public Vector3 Loc; public Vector3 Scale; public int ParentIndex; public int[] ChildIndexArr; public BoneInf(Vector3 l, Vector3 s, int p, int[] c) { Loc = new Vector3(l.Z, l.Y, l.X); Scale = new Vector3(s.Z, s.Y, s.X); ParentIndex = p; ChildIndexArr = c; } } C#-BoneInf using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using SharpDX; /// <summary> /// 表示一個人類模型 /// </summary> public class Human : RigidBodyBase { public Bone RootBone; BoneInf[] BoneInfArr = { new BoneInf(new Vector3(0, 0, 0), new Vector3(1, 1, 1), 0, new int[] { 1, 12, 16 }), //腰部0 new BoneInf(new Vector3(0, 5, 0), new Vector3(2.5, 5, 1), 0, new int[] { 2, 4, 8 }), //胸部1 new BoneInf(new Vector3(0, 1, 0), new Vector3(0.7, 1, 1), 1, new int[] { 3 }), //頸部2 new BoneInf(new Vector3(0, 1.5, 0), new Vector3(1.3, 1.5, 1), 2, new int[]), //頭部3 new BoneInf(new Vector3(-2, 0, 0), new Vector3(2, 1, 1), 1, new int[] { 5 }), //左肩4 new BoneInf(new Vector3(0, -2.5, 0), new Vector3(1, 2.5, 1), 4, new int[] { 6 }), //左上臂5 new BoneInf(new Vector3(0, -2.5, 0), new Vector3(1, 2.5, 1), 5, new int[] { 7 }), //左小臂6 new BoneInf(new Vector3(0, -1, 0), new Vector3(1, 1, 1), 6, new int[]), //左手7 new BoneInf(new Vector3(2, 0, 0), new Vector3(2, 1, 1), 1, new int[] { 9 }), //右肩8 new BoneInf(new Vector3(0, -2.5, 0), new Vector3(1, 2.5, 1), 8, new int[] { 10 }), //右上臂9 new BoneInf(new Vector3(0, -2.5, 0), new Vector3(1, 2.5, 1), 9, new int[] { 11 }), //右小臂10 new BoneInf(new Vector3(0, -1, 0), new Vector3(1, 1, 1), 10, new int[]), //右手11 new BoneInf(new Vector3(-0.8, 0, 0), new Vector3(0.8, 1, 1), 0, new int[] { 13 }), //左骻12 new BoneInf(new Vector3(0, -4, 0), new Vector3(1, 4, 1), 12, new int[] { 14 }), //左大腿13 new BoneInf(new Vector3(0, -4, 0), new Vector3(1, 4, 1), 13, new int[] { 15 }), //左小腿14 new BoneInf(new Vector3(0, -1, 0), new Vector3(1, 1, 1), 14, new int[]), //左腳15 new BoneInf(new Vector3(0.8, 0, 0), new Vector3(0.8, 1, 1), 0, new int[] { 17 }), //右骻16 new BoneInf(new Vector3(0, -4, 0), new Vector3(1, 4, 1), 16, new int[] { 18 }), //右大腿17 new BoneInf(new Vector3(0, -4, 0), new Vector3(1, 4, 1), 17, new int[] { 19 }), //右小腿18 new BoneInf(new Vector3(0, -1, 0), new Vector3(1, 1, 1), 18, new int[]) //右腳19 }; public Human() { CreateBody(); CalcBone(RootBone); } /// <summary> /// 更新指定索引的骨骼 /// </summary> /// <param name="qua">旋轉</param> /// <param name="index">骨骼索引</param> public void UpdateBone(Quaternion qua, int index) { qua.Normalize(); ((Bone)Children(index)).Qua = qua; CalcBone(((Bone)Children(index)).ParentBone); } /// <summary> /// 更新所有子骨骼 /// </summary> /// <param name="parent"></param> private void CalcBone(Bone parent) { foreach (Bone SubBone in parent.ChildrenBone) { SubBone.BoneQua = Quaternion.Normalize(this.Qua * SubBone.Qua); dynamic tempLoc = (Matrix.Translation(SubBone.RelativeLoc) * Matrix.RotationQuaternion(SubBone.BoneQua)).TranslationVector; SubBone.AbsoluteLoc = parent.AbsoluteLoc + tempLoc; SubBone.Location = parent.AbsoluteLoc + tempLoc / 2; CalcBone(SubBone); } } /// <summary> /// 創建人物身體的所有骨骼 /// </summary> private void CreateBody() { for (i = 0; i <= BoneInfArr.Count - 1; i++) { Children.Add(new Bone(BoneInfArr[i].Loc, BoneInfArr[i].Scale)); ((Bone)Children(i)).Index = i; } for (i = 0; i <= BoneInfArr.Count - 1; i++) { ((Bone)Children(i)).ParentBone = Children(BoneInfArr[i].ParentIndex); foreach (object SubIndex_loopVariable in BoneInfArr[i].ChildIndexArr) { SubIndex = SubIndex_loopVariable; ((Bone)Children(i)).ChildrenBone.Add(Children(SubIndex)); } } RootBone = (Bone)Children(0); RootBone.Parent = RootBone; } } C#-Human

附錄

  這是開始你的3D編程的第一步

  需要注意哪些問題?

  3D編程中,形式轉換經常是錯誤的根源,尤其要注意坐標系的手性

  在限制歐拉角中,俯仰角Pitch的范圍是±90º,偏航角Yaw的范圍是±180º

  (額外說明一點,UWP的CompositeTransform3D使用的就是限制歐拉角)

  為什麼選擇SharpDx?

  SharpDx庫與UWP兼容,其他如SharpGL不兼容

  如果你是C#開發者,Unity3D會是更好的選擇

  Direct3D是底層的3D圖形庫,通過接觸它你可以學習到很多底層圖形編程知識

  了解底層知識會使你在接觸並使用Unity3D等引擎時更加得心應手

  其它

  開源鏈接:ExperDot.SharpDx3DEngine

  參考書籍:《3D數學基礎:圖形與游戲開發》[美]Fletcher Dunnlan Parberry著 清華大學出版社(史銀雪、陳洪和王榮靜譯)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved