标签:
IDE:Visual Studio 2015
了解并学习:SharpDx官方示例
在他诞生之初,天地还是一片混沌。
世界坐标系
世界坐标系是一个特殊的坐标系,它建立了描述其他坐标系所需要的参考框架
从另一方面说,不能用更大的、外部的坐标系来描述世界坐标系
关于世界坐标系的典型问题都是关于初始位置和环境的:
左、右手坐标系
所有的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 Public Class World ‘‘‘ <summary> ‘‘‘ 当前世界所有的模型 ‘‘‘ </summary> Public RigidBodys As New List(Of IRigidBody) ‘‘‘ <summary> ‘‘‘ 当前世界所有物体的顶点变换矩阵 ‘‘‘ </summary> Public ModelMatrix() As Matrix Public Sub New() ‘这里初始化世界 End Sub ‘‘‘ <summary> ‘‘‘ 更新当前世界所有物体的顶点变换矩阵 ‘‘‘ </summary> Public Sub Update() End Sub End Class
他在混沌之中孕育着。
有了世界,那么物体该怎么描述呢?
位置Location
一个三维向量,它表示当前物体在世界坐标系中的绝对位置
比例Scale
一个三维向量,表示当前物体x,y,z轴缩放比例
旋转Rotation
通常物体角位移有欧拉角和四元数两种表示方式
欧拉角:
四元数:
Imports SharpDX 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
Imports SharpDX Public Class World Public MyHuman As Human ‘‘‘ <summary> ‘‘‘ 当前世界所有的模型 ‘‘‘ </summary> Public RigidBodys As New List(Of IRigidBody) ‘‘‘ <summary> ‘‘‘ 当前世界所有物体的模型矩阵 ‘‘‘ </summary> Public ModelMatrix() As Matrix Private MList As New List(Of Matrix) Public Sub New() ‘RigidBodys.Add(New Human) ‘MyHuman = RigidBodys(0) ‘MyHuman.Visible = False For i = 0 To 0 RigidBodys.Add(New Ground With {.Location = New Vector3((i) * 50, 0, 0)}) Next Update() End Sub ‘‘‘ <summary> ‘‘‘ 更新当前世界所有物体的模型矩阵 ‘‘‘ </summary> Public Sub Update() MList.Clear() CalcMatrix(RigidBodys, New Vector3(1, 1, 1), New Quaternion(0, 0, 0, 1), Vector3.Zero) ModelMatrix = MList.ToArray End Sub ‘‘‘ <summary> ‘‘‘ 计算指定物体List(包括它的子物体)的顶点变换矩阵 ‘‘‘ </summary> Public Sub CalcMatrix(bodys As List(Of IRigidBody), scale As Vector3, qua As Quaternion, loc As Vector3) For Each SubBody In bodys If SubBody.Visible Then Dim s = MultiScale(SubBody.Scale, scale) ‘当前对象的比例 Dim q = qua * SubBody.Qua ‘当前对象的旋转 Dim p As Vector3 If SubBody.Parent Is Nothing Then p = loc + SubBody.Location ‘父对象为空,则位置为绝对位置 Else p = loc + (Matrix.Translation(SubBody.Location) * Matrix.RotationQuaternion(q)).TranslationVector ‘旋转变换后的位置 End If Dim tempWorld As Matrix = Matrix.Scaling(s) * Matrix.RotationQuaternion(q) * Matrix.Translation(p) MList.Add(tempWorld) CalcMatrix(SubBody.Children, s, q, p) End If Next End Sub ‘‘‘ <summary> ‘‘‘ 相乘指定的两个缩放 ‘‘‘ </summary> Private Function MultiScale(v1, v2) As Vector3 Return New Vector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z) End Function End Class
终于,巍峨巨人从沉睡中醒来。
模型与世界空间
物体最开始由物体空间来描述。其中常见的信息包括顶点位置和表面法向量。
可将坐标从物体空间转换到世界空间中,此过程称作模型变换
通常,光照计算使用世界空间,其实光照计算只需确保几何体和光线在同一空间
摄像机空间
通过视变换,顶点从世界空间变换到摄像机空间,此空间也称作眼睛空间
裁剪与屏幕空间
裁剪空间又名标准视体空间,它是为透视投影做准备
一旦用视锥完成了几何体裁剪,即可向屏幕空间投影
ModelMatrix=World*View*Projection
World=ScaleMatrix*RotationMatrix*TranslateMatrix:
View=Matrix.LookAtLH(eye,target,up):
Projection=Matrix.PerspectiveFovLH(fov, aspect, znear, zfar):
Imports SharpDX ‘‘‘ <summary> ‘‘‘ 摄像机空间基类 ‘‘‘ </summary> Public MustInherit Class CameraBase ‘‘‘ <summary> ‘‘‘ 摄像机位置 ‘‘‘ </summary> ‘‘‘ <returns></returns> Public Property EyeOfView As Vector3 Get Return mEye End Get Set(value As Vector3) mEye = value ChangeView() End Set End Property ‘‘‘ <summary> ‘‘‘ 目标视点位置 ‘‘‘ </summary> ‘‘‘ <returns></returns> Public Property TargetOfView As Vector3 Get Return mTarget End Get Set(value As Vector3) mTarget = value ChangeView() End Set End Property Protected View As Matrix = Matrix.LookAtLH(New Vector3(0, 50, 200), New Vector3(), Vector3.UnitY) Private mEye As Vector3 Private mTarget As Vector3 Private Sub ChangeView() View = Matrix.LookAtLH(mEye, mTarget, Vector3.UnitY) End Sub End Class ‘‘‘ <summary> ‘‘‘表示一个摄像机空间 ‘‘‘ </summary> Public Class CameraSpace Inherits CameraBase Public Property Width As Integer = 600 Public Property Height As Integer = 400 Public Property World As WorldSpace Public Function GetTransforms() As List(Of CustomMath.Transform) Dim tempTransforms As New List(Of CustomMath.Transform) If World IsNot Nothing Then Dim aspect As Single = CSng(Width) / CSng(Height) Dim projection As Matrix = Matrix.PerspectiveFovLH(CSng(Math.PI) / 2.0F, aspect, 1, 10000) For Each SubMatrix In World.ModelMatrix tempTransforms.Add(New CustomMath.Transform() With {.WVP = SubMatrix * View * projection}) Next End If Return tempTransforms End Function End Class
天地开分,孤独的开辟者化作了万物。
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
‘‘‘ <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
世界一隅,Steve开始了他的MineCraft人生。
Imports SharpDX Public Class Human Inherits RigidBodyBase Public RootBone As Bone Public Sub New() CreateBone() CalcBone(RootBone) End Sub Public Sub UpdateBone(qua As Quaternion, index As Integer) Children(index).Qua = qua CalcBone(RootBone) End Sub Private Sub CalcBone(parent As Bone) For Each SubBone In parent.Children Dim tempLoc = (Matrix.Translation(SubBone.RaletiveLoc) * Matrix.RotationQuaternion(SubBone.Qua)).TranslationVector SubBone.AbsoluteLoc = parent.AbsoluteLoc + tempLoc SubBone.Location = parent.AbsoluteLoc + tempLoc / 2 CalcBone(SubBone) Next End Sub Dim BoneIndexArr() As BoneIndex = { New BoneIndex(New Vector3(0, 0, 0), New Vector3(1, 1, 1), 0, New Integer() {1, 12, 16}),‘腰部0 New BoneIndex(New Vector3(0, 5, 0), New Vector3(2.5, 5, 1), 0, New Integer() {2, 4, 8}),‘胸部1 New BoneIndex(New Vector3(0, 1, 0), New Vector3(0.7, 1, 1), 1, New Integer() {3}),‘颈部2 New BoneIndex(New Vector3(0, 1.5, 0), New Vector3(1.3, 1.5, 1), 2, New Integer() {}),‘头部3 New BoneIndex(New Vector3(-2, 0, 0), New Vector3(2, 1, 1), 1, New Integer() {5}),‘左肩4 New BoneIndex(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 4, New Integer() {6}),‘左上臂5 New BoneIndex(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 5, New Integer() {7}),‘左小臂6 New BoneIndex(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 6, New Integer() {}),‘左手7 New BoneIndex(New Vector3(2, 0, 0), New Vector3(2, 1, 1), 1, New Integer() {9}),‘右肩8 New BoneIndex(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 8, New Integer() {10}),‘右上臂9 New BoneIndex(New Vector3(0, -2.5, 0), New Vector3(1, 2.5, 1), 9, New Integer() {11}),‘右小臂10 New BoneIndex(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 10, New Integer() {}),‘右手11 New BoneIndex(New Vector3(-0.8, 0, 0), New Vector3(0.8, 1, 1), 0, New Integer() {13}),‘左骻12 New BoneIndex(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 12, New Integer() {14}),‘左大腿13 New BoneIndex(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 13, New Integer() {15}),‘左小腿14 New BoneIndex(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 14, New Integer() {}),‘左脚15 New BoneIndex(New Vector3(0.8, 0, 0), New Vector3(0.8, 1, 1), 0, New Integer() {17}),‘右骻16 New BoneIndex(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 16, New Integer() {18}),‘右大腿17 New BoneIndex(New Vector3(0, -4, 0), New Vector3(1, 4, 1), 17, New Integer() {19}),‘右小腿18 New BoneIndex(New Vector3(0, -1, 0), New Vector3(1, 1, 1), 18, New Integer() {})‘右脚19 } Private Sub CreateBone() For i = 0 To BoneIndexArr.Count - 1 Children.Add(New Bone(BoneIndexArr(i).Loc, BoneIndexArr(i).Scale)) Next For i = 0 To BoneIndexArr.Count - 1 Dim tempBone = DirectCast(Children(i), Bone) tempBone.Parent = Children(BoneIndexArr(i).ParentIndex) For Each SubIndex In BoneIndexArr(i).ChildIndexArr tempBone.Children.Add(Children(SubIndex)) Next Next RootBone = DirectCast(Children(0), Bone) End Sub End Class
Imports SharpDX Public Class BoneIndex 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 = l Scale = s ParentIndex = p ChildIndexArr = c End Sub End Class
Imports SharpDX ‘‘‘ <summary> ‘‘‘ 表示骨骼结点 ‘‘‘ </summary> Public Class Bone Inherits RigidBodyBase Public Shadows Parent As Bone Public Shadows Children As List(Of Bone) Public AbsoluteLoc As Vector3 Public RaletiveLoc As Vector3 Public rQua As Quaternion Public Overrides Property Qua As Quaternion Set(value As Quaternion) If IsNewQua Then IsNewQua = False rQua = value rQua.Invert() End If mQua = value End Set Get Return rQua * mQua End Get End Property Private mQua As Quaternion Private IsNewQua As Boolean = True Public Sub New(loc As Vector3, scale As Vector3) Me.RaletiveLoc = loc * 10 Me.Scale = scale Children = New List(Of Bone) End Sub End Class
这只是开始你的Minecraft的第一步
需要注意哪些问题?
目前SharpDx无法编译UWP平台的Release版本
3D数学编程中,形式转换经常是错误的根源,尤其要注意坐标系的手性。
在限制欧拉角中,俯仰角Pitch的范围是±90º,偏航角Yaw的范围是±180º
(额外说明一点,UWP的CompositeTransform使用的就是限制欧拉角)
其它
参考书籍:《3D数学基础:图形与游戏开发》[美]Fletcher Dunnlan Parberry著 清华大学出版社
标签:
原文地址:http://www.cnblogs.com/experdot/p/5605439.html