UWP简单示例(二):快速开始你的3D编程

时间:2022-01-03 06:30:52

准备

  IDE:Visual Studio

  开源库:GitHub.SharpDx

  入门示例:SharpDX_D3D12HelloWorld

  为什么选择 SharpDx?

  SharpDx 库与 UWP 兼容,其他如 SharpGL 不兼容

  如果你是 C# 开发者,Unity3D 会是更好的选择

  Direct3D 是底层的 3D 图形库,通过接触它你可以学习到很多底层图形编程知识

  了解底层知识会使你在接触并使用 Unity3D 等引擎时更加得心应手

第一节 世界

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

  世界坐标系

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

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

  • 每个物体的位置和方向
  • 摄像机的位置和方向
  • 世界中每一点的地形是什么(如山丘、建筑、湖泊等)
  • 一个物体从哪里来,到哪里去(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% 的存储空间
  • 多个四元数表示一系列旋转变换时,将它们相乘(而非直接相加)
  • 四元数“减法”,一个变换 Q到另一个变换 Q的差 △Q 等于 Q的逆乘以 Q(而非直接相减)
  • 通过标准化四元数确保它为单位大小,否则它将不合法
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 /
h = h /
d = d /
Dim vertices As Vertex() = New Vertex() {
New Vertex(New Vector3(-w, h, d), New Vector4(, , , )), New Vertex(New Vector3(w, h, d), New Vector4(, , , )),
New Vertex(New Vector3(w, h, -d), New Vector4(, , , )), New Vertex(New Vector3(-w, h, -d), New Vector4(, , , )),
New Vertex(New Vector3(-w, -h, d), New Vector4(, , , )), New Vertex(New Vector3(w, -h, d), New Vector4(, , , )),
New Vertex(New Vector3(w, -h, -d), New Vector4(, , , )), New Vertex(New Vector3(-w, -h, -d), New Vector4(, , , )),
New Vertex(New Vector3(-w, -h, d), New Vector4(, , , )), New Vertex(New Vector3(-w, h, d), New Vector4(, , , )),
New Vertex(New Vector3(-w, h, -d), New Vector4(, , , )), New Vertex(New Vector3(-w, -h, -d), New Vector4(, , , )),
New Vertex(New Vector3(w, -h, d), New Vector4(, , , )), New Vertex(New Vector3(w, h, d), New Vector4(, , , )),
New Vertex(New Vector3(w, h, -d), New Vector4(, , , )), New Vertex(New Vector3(w, -h, -d), New Vector4(, , , )),
New Vertex(New Vector3(-w, h, d), New Vector4(, , , )), New Vertex(New Vector3(w, h, d), New Vector4(, , , )),
New Vertex(New Vector3(w, -h, d), New Vector4(, , , )), New Vertex(New Vector3(-w, -h, d), New Vector4(, , , )),
New Vertex(New Vector3(-w, h, -d), New Vector4(, , , )), New Vertex(New Vector3(w, h, -d), New Vector4(, , , )),
New Vertex(New Vector3(w, -h, -d), New Vector4(, , , )), New Vertex(New Vector3(-w, -h, -d), New Vector4(, , , ))}
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 / ;
h = h / ;
d = d / ;
Vertex[] vertices = new Vertex[] {
new Vertex(new Vector3(-w, h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, h, -d), new Vector4(, , , )),
new Vertex(new Vector3(-w, h, -d), new Vector4(, , , )),
new Vertex(new Vector3(-w, -h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, -h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, -h, -d), new Vector4(, , , )),
new Vertex(new Vector3(-w, -h, -d), new Vector4(, , , )),
new Vertex(new Vector3(-w, -h, d), new Vector4(, , , )),
new Vertex(new Vector3(-w, h, d), new Vector4(, , , )),
new Vertex(new Vector3(-w, h, -d), new Vector4(, , , )),
new Vertex(new Vector3(-w, -h, -d), new Vector4(, , , )),
new Vertex(new Vector3(w, -h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, h, -d), new Vector4(, , , )),
new Vertex(new Vector3(w, -h, -d), new Vector4(, , , )),
new Vertex(new Vector3(-w, h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, h, d), new Vector4(, , , )),
new Vertex(new Vector3(w, -h, d), new Vector4(, , , )),
new Vertex(new Vector3(-w, -h, d), new Vector4(, , , )),
new Vertex(new Vector3(-w, h, -d), new Vector4(, , , )),
new Vertex(new Vector3(w, h, -d), new Vector4(, , , )),
new Vertex(new Vector3(w, -h, -d), new Vector4(, , , )),
new Vertex(new Vector3(-w, -h, -d), new Vector4(, , , ))
};
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(, , , )
''' <summary>
''' 子骨骼
''' </summary>
Public ChildrenBone As New List(Of Bone)
''' <summary>
''' 索引
''' </summary>
Public Index As Integer
Private mQua As New Quaternion(, , , )
Private sQua As New Quaternion(, , , )
Private IsNewQua As Boolean = True
Public Sub New(loc As Vector3, scale As Vector3)
Me.RelativeLoc = loc *
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(, , ), New Vector3(, , ), , New Integer() {, , }),'腰部0
New BoneInf(New Vector3(, , ), New Vector3(2.5, , ), , New Integer() {, , }),'胸部1
New BoneInf(New Vector3(, , ), New Vector3(0.7, , ), , New Integer() {}),'颈部2
New BoneInf(New Vector3(, 1.5, ), New Vector3(1.3, 1.5, ), , New Integer() {}),'头部3
New BoneInf(New Vector3(-, , ), New Vector3(, , ), , New Integer() {}),'左肩4
New BoneInf(New Vector3(, -2.5, ), New Vector3(, 2.5, ), , New Integer() {}),'左上臂5
New BoneInf(New Vector3(, -2.5, ), New Vector3(, 2.5, ), , New Integer() {}),'左小臂6
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , New Integer() {}),'左手7
New BoneInf(New Vector3(, , ), New Vector3(, , ), , New Integer() {}),'右肩8
New BoneInf(New Vector3(, -2.5, ), New Vector3(, 2.5, ), , New Integer() {}),'右上臂9
New BoneInf(New Vector3(, -2.5, ), New Vector3(, 2.5, ), , New Integer() {}),'右小臂10
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , New Integer() {}),'右手11
New BoneInf(New Vector3(-0.8, , ), New Vector3(0.8, , ), , New Integer() {}),'左骻12
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , New Integer() {}),'左大腿13
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , New Integer() {}),'左小腿14
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , New Integer() {}),'左脚15
New BoneInf(New Vector3(0.8, , ), New Vector3(0.8, , ), , New Integer() {}),'右骻16
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , New Integer() {}),'右大腿17
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , New Integer() {}),'右小腿18
New BoneInf(New Vector3(, -, ), New Vector3(, , ), , 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 /
CalcBone(SubBone)
Next
End Sub
''' <summary>
''' 创建人物身体的所有骨骼
''' </summary>
Private Sub CreateBody()
For i = To BoneInfArr.Count -
Children.Add(New Bone(BoneInfArr(i).Loc, BoneInfArr(i).Scale))
DirectCast(Children(i), Bone).Index = i
Next
For i = To BoneInfArr.Count -
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(), 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(, , , );
/// <summary>
/// 子骨骼
/// </summary>
public List<Bone> ChildrenBone = new List<Bone>();
/// <summary>
/// 索引
/// </summary>
public int Index;
private Quaternion mQua = new Quaternion(, , , );
private Quaternion sQua = new Quaternion(, , , );
private bool IsNewQua = true;
public Bone(Vector3 loc, Vector3 scale)
{
this.RelativeLoc = loc * ;
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(, , ), new Vector3(, , ), , new int[] {
,
, }),
//腰部0
new BoneInf(new Vector3(, , ), new Vector3(2.5, , ), , new int[] {
,
, }),
//胸部1
new BoneInf(new Vector3(, , ), new Vector3(0.7, , ), , new int[] { }),
//颈部2
new BoneInf(new Vector3(, 1.5, ), new Vector3(1.3, 1.5, ), , new int[]),
//头部3
new BoneInf(new Vector3(-, , ), new Vector3(, , ), , new int[] { }),
//左肩4
new BoneInf(new Vector3(, -2.5, ), new Vector3(, 2.5, ), , new int[] { }),
//左上臂5
new BoneInf(new Vector3(, -2.5, ), new Vector3(, 2.5, ), , new int[] { }),
//左小臂6
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , new int[]),
//左手7
new BoneInf(new Vector3(, , ), new Vector3(, , ), , new int[] { }),
//右肩8
new BoneInf(new Vector3(, -2.5, ), new Vector3(, 2.5, ), , new int[] { }),
//右上臂9
new BoneInf(new Vector3(, -2.5, ), new Vector3(, 2.5, ), , new int[] { }),
//右小臂10
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , new int[]),
//右手11
new BoneInf(new Vector3(-0.8, , ), new Vector3(0.8, , ), , new int[] { }),
//左骻12
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , new int[] { }),
//左大腿13
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , new int[] { }),
//左小腿14
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , new int[]),
//左脚15
new BoneInf(new Vector3(0.8, , ), new Vector3(0.8, , ), , new int[] { }),
//右骻16
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , new int[] { }),
//右大腿17
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , new int[] { }),
//右小腿18
new BoneInf(new Vector3(, -, ), new Vector3(, , ), , 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 / ;
CalcBone(SubBone);
}
}
/// <summary>
/// 创建人物身体的所有骨骼
/// </summary>
private void CreateBody()
{
for (i = ; i <= BoneInfArr.Count - ; i++) {
Children.Add(new Bone(BoneInfArr[i].Loc, BoneInfArr[i].Scale));
((Bone)Children(i)).Index = i;
}
for (i = ; i <= BoneInfArr.Count - ; 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();
RootBone.Parent = RootBone;
}
}

C#-Human

附录

  需要注意哪些问题?

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

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

  《3D数学基础:图形与游戏开发》[美] Fletcher Dunnlan Parberry 著

UWP简单示例(二):快速开始你的3D编程的更多相关文章

  1. UWP简单示例&lpar;二&rpar;:快速开始你的3D编程

    准备 IDE:Visual Studio 2015 了解并学习:SharpDx官方GitHub 推荐Demo:SharpDX_D3D12HelloWorld 第一节 世界 世界坐标系是一个特殊的坐标系 ...

  2. WPF MVVM&plus;EF增删改查 简单示例&lpar;二&rpar; 1对1 映射

    WPF MVVM+EF增删改查 简单示例(一)实现了对学生信息的管理. 现在需求发生变更,在录入学生资料的时候同时需要录入学生的图片信息,并且一名学生只能有一张图片资料.并可对学生的图片资料进行更新. ...

  3. UWP简单示例&lpar;一&rpar;:快速合成音乐MV

    准备 IDE:Visual Studio 2015 为你的项目安装Nuget包 SharpDx.XAudio2 为你的项目安装Nuget包 Win2D.UWP 了解并学习:Win2D官方博客 了解并学 ...

  4. UWP简单示例(一):快速合成音乐MV

    说明 本文发布时间较早,内容可能已过时.最新动态请关注 TypeScript 版本.(2019 年 3 月 注) 在线演示: 音频可视化(TypeScript) 准备 IDE:Visual Studi ...

  5. UWP简单示例&lpar;三&rpar;:快速开发2D游戏引擎

    准备 IDE:VisualStudio 2015 Language:VB.NET/C# 图形API:Win2D MSDN教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面 ...

  6. UWP简单示例(三):快速开发2D游戏引擎

    准备 IDE:Visual Studio 图形 API:Win2D MSDN 教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面你需要考虑图形.输入和网络 以及相对独立的 ...

  7. VC6下OpenGL 开发环境的构建外加一个简单的二维网络棋盘绘制示例

    一.安装GLUT 工具包 GLUT 不是OpenGL 所必须的,但它会给我们的学习带来一定的方便,推荐安装. Windows 环境下的GLUT 本地下载地址:glut-install.zip(大小约为 ...

  8. 2017&period;2&period;20 activiti实战--第二章--搭建Activiti开发环境及简单示例(二)简单示例

    学习资料:<Activiti实战> 第一章 搭建Activiti开发环境及简单示例 2.5 简单流程图及其执行过程 (1)leave.bpmn 后缀名必须是bpmn.安装了activiti ...

  9. 【Apache Kafka】二、Kafka安装及简单示例

    (一)Apache Kafka安装 1.安装环境与前提条件   安装环境:Ubuntu16.04   前提条件: ubuntu系统下安装好jdk 1.8以上版本,正确配置环境变量 ubuntu系统下安 ...

随机推荐

  1. C&num; 异步编程小结

    APM 异步编程模型,Asynchronous Programming Model EAP 基于事件的异步编程模式,Event-based Asynchronous Pattern TAP 基于任务的 ...

  2. 关于Xcode6 Segue 的疑问,没有解决!

    xcode6 的segue 变化了,如图 关于前3个选项,始终没有太明白,我试验结果如下,简单地把几个viewController连接起来时,无论用show,还是showdetail,还是Presen ...

  3. 使用Visual Studio发布应用安装包

    安装包制作方式 使用Visual Studio进行应用的打包分发有两种方式: 1.使用Clickonce发布安装包: 2.使用Setup工程发布安装包. 操作步骤 Clickonce发布安装包 1.右 ...

  4. hadoop错误ERROR namenode&period;NameNode &lpar;NameNode&period;javamain&lpar;1657&rpar;&rpar; - Failed to start namenode java&period;net&period;BindException:Port in use:host1:50070

    解决方法: 1.通过lsof -i:50070(lsof可以通过yum install lsof安装)查看,发现是mysql被占用了 2.修改mysql端口 从/usr/share/mysql/my- ...

  5. asp&period;net mvc Ajax服务器跳转

    1.过滤器权限验证 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowM ...

  6. pythonのdjango CSRF简单使用

    一.简介 django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成.而对于django中设置防跨站请求伪造功 ...

  7. chrome恢复默认搜索引擎为Google

    管理员身份运行cmd RD /S /Q "%WinDir%\System32\GroupPolicyUsers" RD /S /Q "%WinDir%\System32\ ...

  8. 16&period;3 authguard 通过routing path控制显示URL 通过ngif显示和隐藏

    显示或者隐藏component 通常情况下 我们的做法是把它做成class 以上两步完成,我们就可以用service了,再此之前,我们先 这样弄完以后 . 非登录状态键入上面地址会自动返回下面的地址 ...

  9. HDFS 总结

    HDFS是一个分布式文件存储系统 Client  提交读写请求(拆分blocksize) NameNode 全局把控(知道blocksize的地址) dataNode 存储数据(将数据存储进去,且以P ...

  10. IPython介绍

    本文编写时,IPython最新的版本为6.3和5.4. 介绍 IPython 是 Fernando 在 2001 开始开发的一个交互式的Python解释执行环境.众所周知,Python提供了一个交互执 ...