跳到主要内容

角色控制器的应用

概述

在IdeaXR中角色控制器是作为一个用于控制人物模型的外形以及行为等一系列属性的工具,它主要包括、网格、骨骼、骨骼绑定、还有一些动画的添加等操作。通过熟练的使用角色控制器,我们可以在项目中导入自己喜欢的人物模型,并赋予其相应的一些行为和功能。

导入人物模型

IdeaXR中支持人物模型的导入,我们可以从引擎资源库、mixamo网站等下载自己喜欢的人物模型,并导入到IdeaXR中进行使用,接下来我们会对一个标准人物模型所包含的数据进行介绍:

角色的网格(Meshinstance)

在IdeaXR中,一个人物模型主要由骨骼(Skeleton)与网格(Meshinstance)组成

运动员角色模型

其中网格的介绍可以参考3-1-模型与材质中的网格栏目,其中详细介绍了网格的基本属性,功能等。

角色的网格与其他网格大致相同,需要依附于人物的骨骼,以下是上图中运动员的网格实例属性:

网格属性

其中网格实例中的网格采用了ArrayMesh类型。

骨骼(Skeleton)

角色模型的另一大组成部分为骨骼(Skeleton)组成,我们将人物模型的网格节点隐藏就可以观察到骨骼节点,它是固定人物模型,并使各个关节能够关联活动的重要节点。

人物骨架

我们在一个默认场景中,选择资源—>人物库—>将运动员模型拖拽到场景中。

拖动人物模型

此时我们可以看到节点栏中的骨骼属性,同时其子节点有骨骼绑定(BoneAttachment)与网格(Meshinstance)

骨骼绑定节点

我们将网格属性隐藏,就可以看到本模型的完整骨架

隐藏网格

选中骨骼节点,可以在属性栏中看到它的各项属性

  • 变换:一些对骨骼位置与大小属性的设置
  • 平移:该骨骼位于平面中的空间位置
  • 旋转角度:该骨骼相对于水平面旋转的角度
  • 缩放:该骨骼相对于原始大小的比例
  • 网格实例:骨骼网格的基本属性
  • 网格:骨骼节点使用的网格类型
  • 皮肤:骨骼节点的皮肤类型
  • 骨骼:该骨骼节点依附的根节点
  • 材质:该骨骼所使用的材质
  • 几何实例:该骨骼的几何属性
  • 可见性:骨骼节点的隐藏与显示
  • 节点:一些公共节点属性。
  • 暂停模式:如果SceneTree暂停,节点将如何运行。
  • 功能开关:是否开启动画功能。
  • 多人协同:多人交互的通用节点属性。
  • 脚本:节点绑定的脚本属性。

骨骼绑定

ideaeVR的骨骼绑定(BoneAttachment)是一个非常重要的节点,使用它可以在场景运行时,动态地为骨骼添加附加物体,比如可以动态拾取场景中的物件,并使其成为骨架中某根骨头的子物体。本文将用一个小案例来介绍它的使用方法

首先我们要准备一个带有骨骼的模型,可以选择自己创建后导入,也可以直接使用IdeaXR中提供的素材库里的基本人物模型,本案例中选择使用运动员模型

配置BoneAttachment节点

我们首先为Skeleton节点添加一个BoneAttachment的子节点

添加骨骼绑定节点

此时 BoneAttachment可以从 Skeleton中读取骨头的列表,我们可以选择所需的骨头,本例选择了左手LeftArm。


小贴士

一个 Skeleton可以添加多个 BoneAttachment子节点,用于不同的用途


骨骼的多个子节点

我们选择启用编辑骨骼就可以看到骨骼的详细信息并进行编辑

编辑骨骼

骨骼属性

在这里我们可以看到每一块骨骼的详细信息。

静态添加附加物

我们在刚刚新建的骨骼绑定模型下新建一个球型的网格

新建球型网格

我们修改一下其网格实例,以及调整一下其大小

修改网络实例

我们看一下效果:

网格吸附效果

可以看到,我们创建的网格吸附到了骨骼上。我们选中动画播放器,试着播放一下动画

静态添加附加物的示例

可以看到,我们添加的小球是可以随着骨架运动的,以上就是静态添加附加物的基本介绍

动态添加附加物

我们可以使用动态定义的方法来模拟将东西拿起的情景

我们在默认场景中导入一个运动员模型与一个立方体cube

导入运动员与立方体

<font size="2">导入运动员与立方体</font>

然后如同上个案例一样添加一个骨骼绑定到人物的骨骼,并将骨骼名称选择为LeftHandMiddle2

添加人物骨骼

<font size="2">添加人物骨骼</font>

然后我们在运动员这一节点上编写脚本,这个脚本主要用于获取“骨骼绑定”节点并在其上添加附加物


extends Spatial

onready var attachment = $RootNode/Score_man/Skeleton/骨骼绑定

func _ready():
add_to_group("player")

func grab(a:Spatial):
if not attachment.is_a_parent_of(a):
a.get_parent().remove_child(a)
attachment.add_child(a)
a.transform.origin = Vector3.ZERO


func go_and_grab(a:Spatial):
grab(a)

运动员节点的脚本

根节点上的脚本

extends Spatial

onready var cube = $cube

func _process(delta):
if Input.is_mouse_button_pressed(2):
get_tree().call_group("player","go_and_grab",cube)

根节点上的脚本

由于人物比例的原因,为了使正方体在附着到人物手上的大小可以正常显示,我们可以调整正方体的大小为555

调整正方体大小

为了美观,我们将正方体放在地面下方进行一个隐藏

隐藏正方体

最后我们在运动员节点上添加一个组“player”

添加组player

添加组player

然后让我们的人物动起来!选择动画running,并设置加载后自动播放

设置动画奔跑

运行一下让我们看下效果,当我们点击鼠标右键时,方块就会被人物拿到手里。

人物动画

在角色控制器中,我们对一个人物模型的动画制作主要依靠对其具有的骨骼以此设定动画,从而形成一个整体的动画效果,进而实现人物的一些行为与功能,这一切,我们都可以使用动画树来进行实现。

人物动作控制

动画树的应用

动画树的内容我们在之前的单元有介绍过,现在我们可以通过使用动画树控制骨骼来实 但我们制作完每个人物模型的所需要的动作时,我们如何在程序运行时调用它们呢?如何通过控制方向键或空格键来使角色行走或者跳跃?这个时候我们就需要用到动画树了。

奔跑动画

图中示例为第三人称相机的模型的动画树,通过如上图所示的动画树系统,我们可以通过调用各个动作,来实现角色的各类行为,同时,在IdeaXR中,我们可以通过编写脚本的方式来控制上述动画树。

第三人称相机动画树

脚本控制动作切换

人物模型控制脚本1

人物模型控制脚本2

上述代码为第三人在相机的部分脚本代码,主要用于控制其方向的移动,该脚本通过控制上述动画树中的各个动作的开始与进行,从而对人物模型的行为进行控制。

我们也可以自行查看IdeaXR中自带的第三人称相机的脚本与动画书来进一步提升对脚本控制动作切换的了解。

在默认场景中使用快速创建的方式创建一个第三人称相机

导入第三人称相机

然后选中在编辑器中打开

在编辑器中打开第三人称相机

在这里我们就可以查看这个第三人称相机的全部代码。

第三人称相机代码

相机控制

弹簧臂(用于第三人称相机)

弹簧臂是IdeaXR中一个辅助节点,主要用于第三人称相机。

弹簧臂节点是沿其Z轴投射射线(或碰撞形状)的节点,并将其所有的直接子节点移动到碰撞点,减去边距。

最常见的使用情况是制作第三人称相机,对环境中的碰撞做出反应。

弹簧臂创建实例

弹簧臂将投射一条射线,或者给出形状,它将在其Z轴的方向上投射该形状。

如果你使用弹簧臂作为玩家的相机控制器,你可能需要将玩家的碰撞器排除在弹簧臂的碰撞检查之外。

弹簧臂属性

当我们制作第三人称相机时,我们可以通过将弹簧臂节点作为相机的父节点来防止相机在接触墙面时导致的一些穿模。 弹簧臂位置

围绕角色的相机控制脚本

我们可以通过对一个人物模型添加相机的方法来使其成为一个第三人称相机,这样我们的视角就可以跟随角色移动来进行移动,同时,我们也可以在其中添加弹簧臂,防止相机在近距离靠近墙面时的穿模现象。

func _input(event):
#通过点击鼠标操作来进行视角的旋转
if event is InputEventMouseMotion and Input.is_mouse_button_pressed(2):
#水平角度与竖直角度旋转控制
yaw = fmod(yaw - event.relative.x * MOUSE_SENSITIVITY,360)
pitch = clamp(pitch - event.relative.y * MOUSE_SENSITIVITY,-30,30)
if camera_mode == CameraMode.TP and $TPController1/TPController2/SpringArm/TPCamera.current:
$TPController1.rotation_degrees.y = yaw
$TPController1/TPController2.rotation_degrees.x = pitch
elif camera_mode == CameraMode.FP and $FPCamera.current:
$FPCamera.rotation_degrees = Vector3(pitch, yaw, 0)
if event is InputEventMouseButton:
#通过滚轮来控制弹簧臂的长度
if event.button_index == BUTTON_WHEEL_UP and event.pressed:
if camera_mode == CameraMode.TP and $TPController1/TPController2/SpringArm/TPCamera.current:
$TPController1/TPController2/SpringArm/TPCamera.translation.z = clamp($TPController1/TPController2/SpringArm/TPCamera.translation.z - 0.2, 0.5, 3.0)
$TPController1/TPController2/SpringArm.spring_length = $TPController1/TPController2/SpringArm/TPCamera.translation.z
if event.button_index == BUTTON_WHEEL_DOWN and event.pressed:
if camera_mode == CameraMode.TP and $TPController1/TPController2/SpringArm/TPCamera.current:
$TPController1/TPController2/SpringArm/TPCamera.translation.z = clamp($TPController1/TPController2/SpringArm/TPCamera.translation.z + 0.2, 0.5, 3.0)
$TPController1/TPController2/SpringArm.spring_length = $TPController1/TPController2/SpringArm/TPCamera.translation.z
if event.button_index == BUTTON_LEFT and event.pressed:

以上为给人物模型添加相机后的控制方法脚本案例,我们可以通过类似上述脚本来对人物模型与相机以及弹簧臂进行操作