其实我们在游戏中,会常会应用到动画。所以今天小编与大家一起来深入了解“动画”,其实动画主要分为关节动画、骨骼动画、单一网格模型动画(关键帧动画)。
1)关节动画:把角色分成若干独立部分,一个部分对应一个网格模型,部分的动画连接成一个整体的动画,角色比较灵活,Quake2中使用这种动画;
2)骨骼动画:广泛应用的动画方式,集成了以上两个方式的优点,骨骼按角色特点组成一定的层次结构,有关节相连,可做相对运动,皮肤作为单一网格蒙在骨骼之外,决定角色的外观;
3)单一网格模型动画:由一个完整的网格模型构成,在动画序列的关键帧里记录各个顶点的原位置及其改变量,然后插值运算实现动画效果,角色动画较真实。
第一部分:掌握基础概念
-
骨骼动画原理
骨骼动画的想法来源于人体骨骼。例如说,人的上肢所有肌肉和皮肤都受上肢骨胳的影响,而人的踝关节则分别承受小腿骨胳和脚骨的影响。根据这个我们可以将骨骼动画理解为两个概念: 骨骼:用以控制蒙皮的一种抽象的概念,如人体骨骼控制皮肤。 蒙皮:被骨骼控制、并显示在外的因素,如人体的皮肤被骨骼所影响。
-
蒙皮
在最终的渲染结果中,蒙皮将完全显示出来,蒙皮实际上就是顶点、法线和纹理坐标等将被渲染的元素。而其中,最关键的当然是顶点,顶点将直接被骨头牵扯运动,因而使得整个模型呈现骨骼所决定的样子。
-
骨骼
骨骼是一种抽象的概念,在最终的渲染结果中,它不可见。类如人体骨骼、骨骼是若干骨头(Bone)成树状的集合体,而每块骨头又分别与若干数量的蒙皮顶点关联。当骨头运动的时候,与之关联的所有蒙皮顶点也会受骨骼的影响而运动。 骨头与蒙皮顶点的关联需要考虑到每块骨头对蒙皮顶点的影响。 尽管大部分情况下,一个顶点将仅仅被一个骨头的影响,但是关节处的顶点往往被多根骨头影响,例如踝关节,可能会分别受小腿骨50%和脚骨50%的影响,这种影响叫作权重(Weight)。在这种情况下,我们称踝关节的这些顶点,受小腿骨影响的权重是50%,受脚骨影响的权重也是50%。
-
核心
通过骨骼带动皮肤运动,也就是通过骨骼的移动动态计算Mesh上的点的位置。
-
骨骼动画转换过程
1)将Mesh上的点转换为骨骼空间上的点。骨骼空间就是以关节为原点确定的空间,并不是一个实体。
2)通过缩放、旋转、平移将骨骼移动到新的位置。
3)根据骨骼的新位置计算Mesh顶点新世界坐标(骨骼移动,但Mesh顶点与骨骼的相对位置不变,所以产生了顶点随骨骼移动的感觉),若一个顶点被多个骨骼影响,则要进行顶点混合计算新世界坐标。
特别普及点:补间与帧动画
骨骼动画的本质,便是在不同的时间点为某节骨骼定义了特定的位置、缩放、旋转。动画的运作便是根据两个时间点之间的骨骼数据做数值变化,这种行为称之为补间(Tweens),同理骨骼动画也就是一种补间动画。与补间动画相对应的概念是帧动画,帧动画只会在特定的时间点发生变化,时间点之间的运动途中是不变的,在许多经典的2D游戏动画便是这种做法。
第二部分:实战应用
1、学习Unity3D人体18节点骨骼动态简单点线模型的建立,我们以火柴人模型为主,这种模型具有结构简单、直观、响应速度快等优点。我们使用LineRendderer,进行绘制,即为物体间增加线条。
-
第一步,准备核心组件类,绘制火柴人的脚本CreateSkeletonController.cs、JsonJointSerializable.cs 辅助加载类。
JsonJointSerializable.cs核心代码如下:
using
UnityEngine
;
using
System
.
IO
;
using
System
.
Text
;
using
System
;
using
System
.
Collections
.
Generic
;
[
System
.
Serializable
]
public
class
ModelData
{
public
float
version
;
public
List
<
People_sets
>
people
;
}
[
System
.
Serializable
]
public
class
People_sets
{
public
float
[
]
pose_keypoints_2d
;
// public float[] hand_left_keypoints_2d;
// public float[] hand_right_keypoints_2d;
}
public
class
JsonJointSerializable
:
MonoBehaviour
{
static
public
float
[
]
pose_joint_x
=
new
float
[
20
]
;
static
public
float
[
]
pose_joint_y
=
new
float
[
20
]
;
int
num
=
0
;
// Use this for initialization
void
Start
(
)
{
}
// Update is called once per frame
void
Update
(
)
{
try
{
//test:1帧数据
num
=
2
;
//get the last file name
string
numString
=
Convert
.
ToString
(
num
)
;
string
zero
=
""
;
string
pathBefore
=
"/Resources/OpenPose/"
;
for
(
int
j
=
0
;
j
<
(
12
-
numString
.
Length
)
;
j
++
)
{
zero
=
zero
+
"0"
;
}
Debug
.
Log
(
pathBefore
+
zero
+
numString
+
"_keypoints.json"
)
;
//analysis data from json
string
jsonTest
=
File
.
ReadAllText
(
Application
.
dataPath
+
pathBefore
+
zero
+
numString
+
"_keypoints.json"
,
Encoding
.
UTF8
)
;
Debug
.
Log
(
Application
.
dataPath
+
pathBefore
+
zero
+
numString
+
"_keypoints.json"
)
;
ModelData
obj
=
JsonUtility
.
FromJson
<
ModelData
>
(
jsonTest
)
;
Debug
.
Log
(
obj
)
;
//pervent joints return to (0,0,0)
for
(
int
i
=
0
;
i
<
18
;
I
++
)
{
if
(
obj
.
people
[
0
]
.
pose_keypoints_2d
[
3
*
i
]
==
0.0f
)
{
}
else
{
pose_joint_x
[
i
]
=
obj
.
people
[
0
]
.
pose_keypoints_2d
[
3
*
I
]
;
}
if
(
obj
.
people
[
0
]
.
pose_keypoints_2d
[
3
*
i
+
1
]
==
0.0f
)
{
}
else
{
pose_joint_y
[
i
]
=
obj
.
people
[
0
]
.
pose_keypoints_2d
[
3
*
i
+
1
]
;
}
}
}
catch
(
ArgumentOutOfRangeException
)
{
}
//stay if file doesn't reach the num
catch
(
FileNotFoundException
)
{
num
=
num
-
1
;
}
}
}
CreateSkeletonController.cs核心代码如下:
using
System
.
Collections
.
Generic
;
using
UnityEngine
;
public
class
CreateSkeletonController
:
MonoBehaviour
{
#
region
definition
public
float
speed
=
5f
;
/// <summary>
/// line renderer*4 。表示MNose0,MMid1,LShoulder2,LElbow3 关键渲染点,对象需要挂上LineRenderer
/// </summary>
private
List
<
LineRenderer
>
lineRendererSet
=
new
List
<
LineRenderer
>
(
)
;
public
int
lineLength
=
300
;
/// <summary>
/// SkeletonPointType:骨骼节点的类型(18节点),GameObject:骨骼点预设对象(18节点)
/// </summary>
public
Dictionary
<
SkeletonPointType
,
GameObject
>
SkeletonPointDict
;
[
System
.
Serializable
]
public
enum
SkeletonPointType
{
LEar16
,
LEye14
,
MNose0
,
REye15
,
REar17
,
MMid1
,
LShoulder2
,
RShoulder5
,
LElbow3
,
RElbow6
,
LWrist4
,
RWrist7
,
LAss8
,
RAss11
,
LKnee9
,
RKnee12
,
LFoot10
,
RFoot13
,
}
[
System
.
Serializable
]
public
struct
SkeletonPointPrefab
{
public
SkeletonPointType
type
;
public
GameObject
prefab
;
}
public
SkeletonPointPrefab
[
]
SkeletonPointPrefabs
;
#
endregion
//将场景的物体关联到该脚本中
void
InitObject
(
)
{
// 字典内容
SkeletonPointDict
=
new
Dictionary
<
SkeletonPointType
,
GameObject
>
(
)
;
for
(
int
i
=
0
;
i
<
SkeletonPointPrefabs
.
Length
;
I
++
)
{
if
(
!
SkeletonPointDict
.
ContainsKey
(
SkeletonPointPrefabs
[
i
]
.
type
)
)
{
SkeletonPointDict
.
Add
(
SkeletonPointPrefabs
[
i
]
.
type
,
SkeletonPointPrefabs
[
i
]
.
prefab
)
;
}
}
lineRendererSet
.
Add
(
(
LineRenderer
)
SkeletonPointDict
[
SkeletonPointType
.
MNose0
]
.
GetComponent
(
"LineRenderer"
)
)
;
lineRendererSet
.
Add
(
(
LineRenderer
)
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
GetComponent
(
"LineRenderer"
)
)
;
lineRendererSet
.
Add
(
(
LineRenderer
)
SkeletonPointDict
[
SkeletonPointType
.
LShoulder2
]
.
GetComponent
(
"LineRenderer"
)
)
;
lineRendererSet
.
Add
(
(
LineRenderer
)
SkeletonPointDict
[
SkeletonPointType
.
LElbow3
]
.
GetComponent
(
"LineRenderer"
)
)
;
}
// Use this for initialization
void
Start
(
)
{
InitObject
(
)
;
lineRendererSet
[
0
]
.
positionCount
=
lineLength
;
lineRendererSet
[
1
]
.
positionCount
=
lineLength
;
lineRendererSet
[
2
]
.
positionCount
=
lineLength
;
lineRendererSet
[
3
]
.
positionCount
=
lineLength
;
lineRendererSet
[
0
]
.
positionCount
=
7
;
lineRendererSet
[
1
]
.
positionCount
=
7
;
lineRendererSet
[
2
]
.
positionCount
=
4
;
lineRendererSet
[
3
]
.
positionCount
=
4
;
}
// Update is called once per frame
void
Update
(
)
{
float
step
=
speed
*
Time
.
deltaTime
;
//move joints using interpolation method
SkeletonPointDict
[
SkeletonPointType
.
LEar16
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LEar16
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
16
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LEar16
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
16
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
MNose0
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
MNose0
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
0
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
MNose0
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
0
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
LEye14
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LEye14
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
14
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LEye14
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
14
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
REye15
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
REye15
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
15
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
REye15
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
15
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
1
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
1
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
LShoulder2
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LShoulder2
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
2
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LShoulder2
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
2
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
RShoulder5
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RShoulder5
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
5
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RShoulder5
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
5
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
LElbow3
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LElbow3
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
3
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LElbow3
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
3
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
RElbow6
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RElbow6
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
6
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RElbow6
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
6
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
LWrist4
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LWrist4
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
4
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LWrist4
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
4
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
RWrist7
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RWrist7
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
7
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RWrist7
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
7
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
LAss8
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LAss8
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
8
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LAss8
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
8
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
RAss11
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RAss11
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
11
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RAss11
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
11
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
LKnee9
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LKnee9
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
9
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LKnee9
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
9
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
RKnee12
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RKnee12
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
12
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RKnee12
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
12
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
LFoot10
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LFoot10
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
10
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
LFoot10
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
10
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
RFoot13
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RFoot13
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
13
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
RFoot13
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
13
]
,
step
)
,
0
)
;
SkeletonPointDict
[
SkeletonPointType
.
REar17
]
.
transform
.
localPosition
=
new
Vector3
(
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
REar17
]
.
transform
.
localPosition
.
x
,
0.1f
*
JsonJointSerializable
.
pose_joint_x
[
17
]
,
step
)
,
Mathf
.
Lerp
(
SkeletonPointDict
[
SkeletonPointType
.
REar17
]
.
transform
.
localPosition
.
y
,
-
0.1f
*
JsonJointSerializable
.
pose_joint_y
[
17
]
,
step
)
,
0
)
;
//it requires 4 lines to connect all the joints
lineRendererSet
[
0
]
.
SetPosition
(
0
,
SkeletonPointDict
[
SkeletonPointType
.
LEar16
]
.
transform
.
localPosition
)
;
lineRendererSet
[
0
]
.
SetPosition
(
1
,
SkeletonPointDict
[
SkeletonPointType
.
LEye14
]
.
transform
.
localPosition
)
;
lineRendererSet
[
0
]
.
SetPosition
(
2
,
SkeletonPointDict
[
SkeletonPointType
.
MNose0
]
.
transform
.
localPosition
)
;
lineRendererSet
[
0
]
.
SetPosition
(
3
,
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
transform
.
localPosition
)
;
lineRendererSet
[
0
]
.
SetPosition
(
4
,
SkeletonPointDict
[
SkeletonPointType
.
LShoulder2
]
.
transform
.
localPosition
)
;
lineRendererSet
[
0
]
.
SetPosition
(
5
,
SkeletonPointDict
[
SkeletonPointType
.
LElbow3
]
.
transform
.
localPosition
)
;
lineRendererSet
[
0
]
.
SetPosition
(
6
,
SkeletonPointDict
[
SkeletonPointType
.
LWrist4
]
.
transform
.
localPosition
)
;
lineRendererSet
[
1
]
.
SetPosition
(
0
,
SkeletonPointDict
[
SkeletonPointType
.
REar17
]
.
transform
.
localPosition
)
;
lineRendererSet
[
1
]
.
SetPosition
(
1
,
SkeletonPointDict
[
SkeletonPointType
.
REye15
]
.
transform
.
localPosition
)
;
lineRendererSet
[
1
]
.
SetPosition
(
2
,
SkeletonPointDict
[
SkeletonPointType
.
MNose0
]
.
transform
.
localPosition
)
;
lineRendererSet
[
1
]
.
SetPosition
(
3
,
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
transform
.
localPosition
)
;
lineRendererSet
[
1
]
.
SetPosition
(
4
,
SkeletonPointDict
[
SkeletonPointType
.
RShoulder5
]
.
transform
.
localPosition
)
;
lineRendererSet
[
1
]
.
SetPosition
(
5
,
SkeletonPointDict
[
SkeletonPointType
.
RElbow6
]
.
transform
.
localPosition
)
;
lineRendererSet
[
1
]
.
SetPosition
(
6
,
SkeletonPointDict
[
SkeletonPointType
.
RWrist7
]
.
transform
.
localPosition
)
;
lineRendererSet
[
2
]
.
SetPosition
(
0
,
SkeletonPointDict
[
SkeletonPointType
.
LFoot10
]
.
transform
.
localPosition
)
;
lineRendererSet
[
2
]
.
SetPosition
(
1
,
SkeletonPointDict
[
SkeletonPointType
.
LKnee9
]
.
transform
.
localPosition
)
;
lineRendererSet
[
2
]
.
SetPosition
(
2
,
SkeletonPointDict
[
SkeletonPointType
.
LAss8
]
.
transform
.
localPosition
)
;
lineRendererSet
[
2
]
.
SetPosition
(
3
,
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
transform
.
localPosition
)
;
lineRendererSet
[
3
]
.
SetPosition
(
0
,
SkeletonPointDict
[
SkeletonPointType
.
RFoot13
]
.
transform
.
localPosition
)
;
lineRendererSet
[
3
]
.
SetPosition
(
1
,
SkeletonPointDict
[
SkeletonPointType
.
RKnee12
]
.
transform
.
localPosition
)
;
lineRendererSet
[
3
]
.
SetPosition
(
2
,
SkeletonPointDict
[
SkeletonPointType
.
RAss11
]
.
transform
.
localPosition
)
;
lineRendererSet
[
3
]
.
SetPosition
(
3
,
SkeletonPointDict
[
SkeletonPointType
.
MMid1
]
.
transform
.
localPosition
)
;
}
}
骨骼数据文件(Json格式),测试使用。文件放置Resources/OpenPose/000000000002_keypoints.json 文件夹下。
{
"version"
:
1.2
,
"people"
:
[
{
"pose_keypoints_2d"
:
[
273.264
,
38.5963
,
0.869616
,
301.865
,
147.37
,
0.80189
,
219.778
,
147.363
,
0.74485
,
177.866
,
278.962
,
0.660513
,
149.317
,
387.645
,
0.783981
,
389.568
,
145.525
,
0.69237
,
418.295
,
294.246
,
0.581674
,
429.69
,
420.184
,
0.744175
,
225.593
,
439.214
,
0.393213
,
364.144
,
650.645
,
0.848758
,
364.144
,
650.645
,
0.848758
,
357.144
,
450.645
,
0.348758
,
364.144
,
650.645
,
0.848758
,
364.144
,
650.645
,
0.848758
,
252.327
,
21.455
,
0.845018
,
296.116
,
17.6204
,
0.78486
,
236.984
,
38.5901
,
0.239763
,
330.499
,
36.6363
,
0.860353
]
,
"face_keypoints_2d"
:
[
]
,
"hand_left_keypoints_2d"
:
[
430.255
,
424.202
,
0.255266
,
416.676
,
452.158
,
0.343294
,
421.469
,
486.505
,
0.0764938
,
419.073
,
497.688
,
0.0160631
,
424.664
,
501.682
,
0.00270473
,
414.28
,
496.091
,
0.0290727
,
396.707
,
488.902
,
0.00831178
,
395.11
,
489.7
,
0.00435322
,
413.481
,
540.822
,
0.00356947
,
423.066
,
497.688
,
0.0233392
,
411.884
,
504.078
,
0.00861702
,
422.268
,
503.28
,
0.00597289
,
415.878
,
540.822
,
0.00381597
,
423.865
,
496.091
,
0.0400665
,
412.682
,
504.078
,
0.0124277
,
423.865
,
503.28
,
0.00940899
,
412.682
,
540.023
,
0.00571543
,
424.664
,
486.505
,
0.0412582
,
395.11
,
488.103
,
0.0168368
,
423.865
,
501.682
,
0.00908826
,
424.664
,
505.676
,
0.00689844
]
,
"hand_right_keypoints_2d"
:
[
159.561
,
374.712
,
0.0309012
,
142.809
,
387.822
,
0.0350077
,
142.809
,
419.14
,
0.0447348
,
163.202
,
436.62
,
0.0462346
,
149.364
,
443.174
,
0.0316575
,
160.289
,
403.845
,
0.064782
,
142.809
,
430.065
,
0.0809698
,
153.734
,
449.001
,
0.128932
,
164.659
,
466.481
,
0.114184
,
160.289
,
406.03
,
0.0501139
,
155.919
,
427.88
,
0.0803895
,
163.202
,
454.828
,
0.162599
,
169.757
,
470.851
,
0.186943
,
161.746
,
405.301
,
0.0399239
,
160.289
,
424.966
,
0.0734568
,
165.387
,
444.631
,
0.164918
,
170.486
,
470.851
,
0.246341
,
166.116
,
404.573
,
0.0298664
,
166.116
,
423.51
,
0.0586659
,
169.757
,
441.718
,
0.0851868
,
174.856
,
465.753
,
0.0832467
]
,
"pose_keypoints_3d"
:
[
]
,
"face_keypoints_3d"
:
[
]
,
"hand_left_keypoints_3d"
:
[
]
,
"hand_right_keypoints_3d"
:
[
]
}
]
}
附加说明:然后之前有一个插件专门研究解决多人骨骼和手势、面部识别的问题。上面测试数据也来源于OpenPose。
-
第二步,在项目中设置预设对象,可以选择Sphere或者Cube对象。并且附加CreateSkeletonController.cs、JsonJointSerializable.cs组件。

-
第三步,直接运行项目可以看到绘制的火柴人。

后续小编这边会继续分享骨骼动画在Unity3D中的应用。期待关注哈!
Mixamo 动画资源的网站(免费):
http://www.360doc.com/content/20/0117/17/21412_886713704.shtml