混合姿势节点
概述
混合姿势(Blend Pose)节点包括按布尔型混合姿势(Blend Pose By Bool)节点和按整型混合姿势(Blend Pose By Int)节点,使用该类节点可切换不同的姿势,并且切换时过渡自然流畅,不会过于突兀。
按布尔型混合姿势节点
按布尔型混合姿势(Blend Pose By Bool)节点根据各类参数(除向量参数)结合操作符的使用来控制输出姿势在两个输入姿势之间进行切换,最终结果为false时输出假姿势(False Pose),为true时输出真姿势(True Pose)。
节点使用
在动画树(Anim Tree)空白处右键打开节点选择面板,展开混合(Blends)分类并从中选取按布尔型混合姿势(Blend Pose By Bool)。
成功添加节点:
可以继续为节点配置合适的输入/输出。
属性
选中节点后,可以在属性窗口(Property Window)中看到该节点的各项属性。
属性 | 说明 |
---|---|
过渡模式(Transition Mode) | 播放节点时采用的过渡模式。
|
假混合时间(False Blend Time) | 混入假姿势混合所需的时间。 |
真混合时间(True Blend Time) | 混入真姿势混合所需的时间。 |
回调字符串(Callback String) | 配置回调函数,根据返回值决定是否迁移。 |
是否使用条件(Use Conditions) | 勾选后,可选择除向量外的其他参数用于条件表达式,将最终结果用于控制节点混合,可参考动画参数文档中的使用参数部分。 |
按整型混合姿势节点
按整型混合姿势(Blend Pose By Int)节点可根据整型参数控制输出姿势在多个输入姿势中进行切换,整型参数值为0时输出混合姿势0(Blend Pose 0),为1时输出混合姿势1(Blend Pose 1),依此类推。
节点使用
在动画树(Anim Tree)空白处右键打开节点(Nodes)选择面板,展开混合(Blends)分类并从中选取按整型混合姿势(Blend Pose By Int)。
成功添加节点:
点击节点上添加引脚(Add Pin)可以为其添加新的引脚。
成功添加引脚:
若要删除新添加的引脚,可右击引脚,选择删除引脚(Delete Pin)即可删除该引脚。初始的两个混合姿势引脚不可删除。
然后可以继续为节点配置合适的输入/输出。
属性
选中节点后,可以在属性窗口(Property Window)中看到该节点的各项属性。
属性 | 说明 |
---|---|
过渡模式(Transition Mode) | 播放节点时采用的过渡模式。
|
混合时间列表(Blend Time) | 各姿势混入所需要的时间。 |
回调字符串(Callback String) | 配置回调函数,根据返回值决定是否迁移。 |
参数(Parameter) | 勾选后代表该属性使用动画整型参数。在下拉列表中指定从哪个参数中获取参数控制量。 |
示例
以下是使用按整型混合姿势(Blend Pose By Int)节点来切换动画姿势的一个简单示例。
创建组合体
参考Actor组装创建一个组合体(Actor),包含SK_Human_tpose、ALS_CLF_Walk_B和ALS_N_Run_F动画资产。
配置动画树
在该组合体编辑器(Actor Editor)的动作列表(Action List)中双击一个骨架资产打开动画编辑器(Animation Editor)。
创建一个动画树。在打开的动画编辑器(Animation Editor)中,依次点击菜单栏文件(File)-> 创建(Create),在弹出的窗口中点击下拉框选择动画树(AnimTree),为其命名并选择创建路径,点击是(Yes)完成创建并进入到动画树编辑器(Anim Tree Editor)。
在动画树中添加一个按整型混合姿势(Blend Pose By Int)节点,分别为混合姿势0(Blend Pose 0)和混合姿势1(Blend Pose 1)引脚链接一个序列播放节点,最后将按整型混合姿势节点链接到最终动画姿势(Final Animation Pose)节点。
在动画参数(Animation Parameter)窗口中,点击 按钮后选择整型(Int) 创建一个整型参数。
创建完成后,修改它的参数名称(Parameter Name)为WalkIndex。
选中按整型混合姿势(Blend Pose By Int)节点,在属性窗口(Property Window)中勾选参数(Parameter),然后在其下拉框中选择刚才所创建的WalkIndex整型参数。其他属性可根据需求自行设置。
编辑完成后,点击应用(Apply)按钮,在其旁边的下拉框中选择预览对象(Preview Object),然后后续可在预览(Preview)窗口中查看效果。
在动画参数(Animation Parameter)窗口的参数实例值(Parameter Instance Value)中输入0则会播放输入到混合姿势0(Blend Pose 0)引脚的动画,输入1则会播放输入到混合姿势1(Blend Pose 1)引脚的动画。
点击保存(Save)按钮保存动画树。
配置组合体
在组合体编辑器中点击资产细项(Asset Details),将默认动作(Default Action)设置为所创建的动画树test_tree,然后点击保存(Save)。
输入设置
在组件编辑器中,依次点击菜单栏配置(Config) -> 项目设置(Project Settings)打开项目设置窗口。
在项目设置(Project Settings)窗口中点击输入设置(Input Settings),点击组合映射列表(Combination Mapping List)栏中的 按钮添加一个新的组合映射。
在新创建的组合映射中,输入组合名称(Combination Name),并在键名(Key Name)中指定一个按键。
创建角色
在组件编辑器中创建一个关卡,然后依次点击创建游戏对象(Create Game Object)-> 角色(Character)。
在大纲(Hierarchy)面板中选中该角色对象,然后在观察器(Inspector)面板中选中CharacterMesh0(Inherited),从资源预览窗口中将所创建的组合体(Actor)文件拖到骨架网格体配置文件(Skeletal Mesh Config File)的插槽中。
在观察器(Inspector)面板中,选中CollisionCylinder(Inherited) 和 CharacterMesh0(Inherited) 分别调整该角色胶囊体和网格体的位置,使胶囊体尽可能在包裹角色的前提下,让蒙皮角色的脚部贴地,胶囊体也需在地面上方。
在观察器(Inspector)面板中,选中CharacterMesh0(Inherited),然后点击添加组件(Add Component),选择摄像机组件(Camera Component)。
添加完成:
调整所创建的摄像机到合适位置和角度。
在观察器(Inspector)面板中,选中LCharacter(Instance),将自动持有玩家(Auto Possess Player)设置为玩家0(Player 0)。
为角色绑定脚本
在观察器(Inspector)面板中选中LCharacter(Instance),然后点击添加组件(Add Component)按钮,选择脚本组件(Script Component)。
添加完成:
为该角色绑定脚本。编写一个脚本并将其保存在项目资源中的脚本文件夹中。在大纲(Hierarchy)面板中选中LCharacter,然后在观察器(Inspector)面板中选中LScript,从资源预览窗口中将脚本拖入到脚本文件(Script File)插槽中。
绑定完成:
脚本
以下脚本仅供参考:
robot_character.lua
--script template
require("public_attr")
local IE_Pressed = 0 --按键按下
local IE_Released = 1 --按键抬起
local IE_Repeat = 2
local IE_DoubleClick = 3
local IE_Axis = 4
local IE_MAX = 5
--获取actor
function character_get_actor(character)
if nx_is_valid(character) then
local mesh_component = character.MeshComponent
if nx_is_valid(mesh_component) then
local vis_base = mesh_component.VisBase
if nx_is_valid(vis_base) and nx_is_kind(vis_base, "Actor") then
return vis_base
end
end
end
return nx_null()
end
--walk
function on_enable_walk_pressed(owner)
local actor = character_get_actor(owner)
if not nx_is_valid(actor) then
return
end
local action_name = actor:GetBlendActionName(0)
local action_type = actor:GetActionType(action_name)
local action_index = actor:GetActionIndex(action_name)
if action_type == AT_ANIMTREE then
if actor:GetAnimTreeValue(action_index, "WalkIndex") == 0 then
actor:SetAnimTreeValue(action_index, "WalkIndex", 1)
else
actor:SetAnimTreeValue(action_index, "WalkIndex", 0)
end
end
end
function get_object_by_tag(lscene, tag_name, class_type_name)
--local lscene = nx_value("lscene")
if not nx_is_valid(lscene) then
return nx_null()
end
if tag_name == nil then
return nx_null()
end
local tag_table = lscene:QueryObjectListByTag(tag_name, class_type_name)
local tag_count = #tag_table
if tag_count == 0 then
return nx_null()
elseif tag_count == 1 then
return tag_table[1]
elseif tag_count > 1 then
for i = 1, tag_count do
nx_log("info, get_object_by_tag, "
..nx_string(i) .." : "..nx_string(tag_table[i].StringTag))
end
return nx_null()
end
end
function input_comp_init_bind(component)
local owner = component.GameObjectOwner
if nx_is_valid(owner) then
local input_comp = owner.InputComponent
if nx_is_valid(input_comp) then
nx_bind_script(owner, nx_current())
input_comp:AddCombinationBinding("EnableWalk", IE_Pressed, true, false, true, "InputActionEvent_EnableWalk_Pressed")
nx_callback(owner, "InputActionEvent_EnableWalk_Pressed", "on_enable_walk_pressed")
end
end
end
--use this for initialization
function on_begin_play(component)
input_comp_init_bind(component)
nx_callback(component, "on_tick", "tick")
end
function tick(component, delta_time)
if not nx_is_valid(component) then
return
end
local lscene = component.Scene
local owner = component.GameObjectOwner
local actor = character_get_actor(owner)
local target_pawn = get_object_by_tag(lscene, "Pawn_0", "LCharacter")
if not nx_is_valid(target_pawn) then
return
end
end
public_attr.lua
--资源管理器:全局变量
MODEL_PATH = "mdl\\"
MODEL_PATH_DX9 = ""
ACTOR_PATH = "ini\\actor\\"
ACTOR_PATH_DX9 = "ini\\actor\\"
LIGHT_PATH = "ini\\light\\"
LIGHT_PATH_DX9 = "ini\\light\\"
EFFECT_PATH = "ini\\effect\\"
PARTICLE_PATH = "ini\\particle\\"
SOUND_PATH = "snd\\"
REVERB_PATH = "reverb\\"
TRIGGER_PATH = "ini\\trigger\\"
PROBE_PATH = "ini\\light_probe\\"
VOLUME_FOG_PATH = "ini\\volume_fog\\"
MATERIAL_PATH = ""
--资源类型定义
TYPE_MODEL = "model"
TYPE_ACTOR = "actor"
TYPE_LIGHT = "light"
TYPE_EFFECT = "effect"
TYPE_PARTICLE = "particle"
TYPE_SOUND = "sound"
TYPE_REVERB = "reverb"
TYPE_TRIGGER = "trigger"
TYPE_PROBE = "light_probe"
TYPE_VOLUME_FOG = "volume_fog"
TYPE_DECAL = "decal"
TYPE_GROUP = "group"
TYPE_RIPPLE = "ripple"
TYPE_SNOW = "snow"
TYPE_RAIN = "rainlayer"
TYPE_UI3D = "ui3d"
--动画资源类型
AT_UNKNOWN = 0
AT_SKELETON = 1
AT_SKELETON_AS_ANIMSEQUENCE = 2
AT_ANIMSEQUENCE = 3
AT_MONTAGE = 4
AT_BLENDSPACE = 5
AT_BLENDSPACE1D = 6
AT_AIMOFFSETBLENDSPACE = 7
AT_ANIMTREE = 8
TYPE_LIST = {
"model",
"actor",
"light",
"effect",
"particle",
"decal",
"sound",
"reverb",
"trigger",
"light_probe",
"volume_fog",
"ripple",
"snow",
"rainlayer",
}
FORM_TREE_BROWSER = "common_form\\form_tree_browser"
SEARCH_PATH = "ini\\common_form\\form_tree_browser\\"
SEARCH_CONFIG = SEARCH_PATH .. "form_put_visual.ini"
SEARCH_CONFIG_TEMP = "cache\\common_form\\form_tree_browser\\form_put_visual_temp.ini"
GROUP_CONFIG = "ter\\visual_group.ini"
--获取visual_put文件
function get_search_file()
local ini = nx_create("IniDocument")
ini.FileName = nx_resource_path() .. SEARCH_CONFIG
if not ini:LoadFromFile() then
nx_destroy(ini)
return 0
end
local file = ini:ReadString("SEARCH_CONFIG", "search_file", "form_put_visual.ini")
nx_destroy(ini)
return nx_resource_path() .. SEARCH_PATH .. file, file
end
运行
点击运行按钮后,按5键可切换角色动画。