准备

  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简单示例(二):快速开始你的3D编程

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

  2. WPF MVVM+EF增删改查 简单示例(二) 1对1 映射

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

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

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

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

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

  5. UWP简单示例(三):快速开发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.2.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. Appium初识

    一. Appium工作原理 基本工作流程如下: Appium提供了一套web服务,Appium起一个Server(4723端口),用于与脚本client通信. server接收web driver(即 ...

  2. Apache POI导出excel表格

    项目中我们经常用到导出功能,将数据导出以便于审查和统计等.本文主要使用Apache POI实现导出数据. POI中文文档 简介 ApachePOI是Apache软件基金会的开放源码函式库,POI提供A ...

  3. 常用css字体英文写法

    font-family: 'Microsoft Yahei',sans-serif; 宋体:SimSun 黑体:SimHei

  4. golang中的init函数以及main函数

    首先我们看一个例子:init函数: init 函数可在package main中,可在其他package中,可在同一个package中出现多次. main函数 main 函数只能在package ma ...

  5. Tomcat 访问页面或服务器异常,请检查这些方面

    若还没有部署网站,请检查 防火墙是否关闭 数据库服务是否打开 浏览器访问的地址和端口是否正确 tomcat 配置文件中的端口是否发生冲突,换一个试试 若出现的是"拒绝连接",检查阿 ...

  6. Axure RP Pro7.0的key注册码加汉化非破解

    上次我们刚分享过Axure RP Pro6.5 key注册码加汉化非破解,我还要分享一个Axure RP Pro7.0的key注册码加汉化,非破解哦. 当然方法还是不变,先用下面的密钥激活.用户名就是 ...

  7. Cocos2d-x 线程的使用及线程使用中遇到的问题

    .h文件: #if CC_PLATFORM_ANDROID == CC_TARGET_PLATFORM #include "pthread.h" #endif #if CC_PLA ...

  8. tomcat健康检查监控脚本

    #!/bin/sh#自动监控tomcat脚本并且执行重启操作#获取tomcat_IDTomcatID=`ps -ef|grep tomcat|grep -v "grep"|grep ...

  9. UVA12171-Sculpture(离散化+floodfill)

    Problem UVA12171-Sculpture Accept: 196  Submit: 1152 Time Limit: 3000 mSec Problem Description Imagi ...

  10. ESP-手机--双向通信模式

    1 AP 接受手机 2 STA(密码固定)连接路由器,AP接受手机 3 STA(密码灵活)连接路由器,AP接受手机 1 AP 接受手机 #include <ESP8266WiFi.h>   ...