码迷,mamicode.com
首页 > 其他好文 > 详细

UWP简单示例(二):快速开始你的MineCraft

时间:2016-06-24 01:39:35      阅读:757      评论:0      收藏:0      [点我收藏+]

标签:

准备

  IDE:Visual Studio 2015

  了解并学习:SharpDx官方示例

第一节 世界

  在他诞生之初,天地还是一片混沌。

  世界坐标系

  世界坐标系是一个特殊的坐标系,它建立了描述其他坐标系所需要的参考框架

  从另一方面说,不能用更大的、外部的坐标系来描述世界坐标系

  关于世界坐标系的典型问题都是关于初始位置和环境的:

  •   每个物体的位置和方向
  •   摄像机的位置和方向
  •   世界中没一点的地形是什么(如山丘、建筑、湖泊等)
  •   个物体从哪里来,到哪里去(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
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

  通常物体角位移有欧拉角和四元数两种表示方式

  欧拉角:

  •   欧拉角有三个分量,偏航角Yaw、俯仰角Pitch、横滚角Roll
  •   给定方位的表达方式不唯一
  •   两个角度间求插值非常困难
  •   万向锁是一个底层问题,至今没有简单的解决方案

  四元数:

  •   四元数(Quaternion)有四个分量,它是一个超复数
  •   四元数能够平滑插值,但它比欧拉角多占用33.3%的存储空间
  •   多个四元数表示一系列旋转变换时,将它们相乘(而非直接相加)
  •   四元数“减法”,一个变换Q1到另一个变换Q2的差△Q等于Q1的逆乘以Q2(而非直接相减)
  •   通过标准化四元数确保它为单位大小,否则它将不合法
技术分享
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
RigidBody接口
技术分享
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
World类

第三节 矩阵变换

  终于,巍峨巨人从沉睡中醒来。

  模型与世界空间

  物体最开始由物体空间来描述。其中常见的信息包括顶点位置和表面法向量。

  可将坐标从物体空间转换到世界空间中,此过程称作模型变换

  通常,光照计算使用世界空间,其实光照计算只需确保几何体和光线在同一空间

  摄像机空间

  通过视变换,顶点从世界空间变换到摄像机空间,此空间也称作眼睛空间

  裁剪与屏幕空间

  裁剪空间又名标准视体空间,它是为透视投影做准备

  一旦用视锥完成了几何体裁剪,即可向屏幕空间投影

  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 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
Camera类

第四节 三角网格

  天地开分,孤独的开辟者化作了万物。

 

技术分享
    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
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
CreateCube函数

第五节 创建人物

  世界一隅,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
Human类
技术分享
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
BoneIndex类
技术分享
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
Bone类

附录

  这只是开始你的Minecraft的第一步

  需要注意哪些问题?

  目前SharpDx无法编译UWP平台的Release版本

  3D数学编程中,形式转换经常是错误的根源,尤其要注意坐标系的手性。

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

  (额外说明一点,UWP的CompositeTransform使用的就是限制欧拉角)

  其它

  开源链接:ExperDot.SharpDx3DEngine

  参考书籍:《3D数学基础:图形与游戏开发》[美]Fletcher Dunnlan Parberry著 清华大学出版社

UWP简单示例(二):快速开始你的MineCraft

标签:

原文地址:http://www.cnblogs.com/experdot/p/5605439.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!