添加变形目标
本文描述了如何使用 morph target(变形目标)动画,在UNIGINE中也称为blend shape(混合形状)。通常,变形目标是用来改变人物的面部表情。
这篇文章展示了如何从Autodesk Maya导出带有变形目标的网格,然后将其添加到UNIGINE。
本教程中使用的模型是分布在CC0 1.0 Universal下的Spot 由 Keenan Crane。
需求#
- 假设您已经有一个混合形状的3D模型准备导出,并且该模型在UNIGINE设置的限制范围内。
- 假设您已经创造了一个世界。
另请参阅#
- ObjectMeshSkinned类函数的描述
步骤1。从玛雅导出一个网格与混合形状#
本节展示了从Autodesk Maya导出FBX格式的混合形状网格的方法。它包含一个小牛的示例网格,它有2个混合形状(变形目标)。
要导出具有混合形状的网格,请执行以下操作:
-
在Autodesk Maya中,选择要导出的混合形状网格。
在主菜单中,单击File -> Export Selection...
- 在Export Selection窗口中,选择一个文件夹来保存网格,并为FBX文件指定一个名称。在Files of type下拉列表中选择FBX export。
- 在带有导出选项的File Type Specific Options选项卡中,指定参数以导出网格。
- 在Deformed Models选项卡中,选中Blend Shapes复选框以导出混合形状。
- 单击Export Selection。
现在您有了FBX格式的网格,可以很容易地添加到您的项目中。
步骤2。在世界中添加网格#
本节将展示如何添加导出的网格动画世界,建立变形目标。
将导出的网格添加到世界中:
-
启用 Import Morph Targets 选项并导入*.fbx文件。
- 将导入的文件添加到场景中。
- 保存世界。
网格的每个混合形状都是一个目标。您需要为网格的表面启用变形目标,并为这些目标设置参数来控制变形目标动画。下面的例子展示了如何从代码中创建变形目标和设置参数:
#pragma once
#include <UnigineComponentSystem.h>
#include <UnigineWorld.h>
#include <UnigineGame.h>
class Morph :
public Unigine::ComponentBase
{
public:
// declare constructor and destructor for the Morph class
COMPONENT_DEFINE(Morph, Unigine::ComponentBase);
// declare methods to be called at the corresponding stages of the execution sequence
COMPONENT_INIT(init);
COMPONENT_UPDATE(update);
private:
Unigine::ObjectMeshSkinnedPtr mesh;
protected:
// world main loop
void init();
void update();
};
#include "Morph.h"
REGISTER_COMPONENT(Morph); // macro for component registration by the Component System
using namespace Unigine;
using namespace Math;
void Morph::init()
{
// get the node and cast it to a skinned mesh
mesh = static_ptr_cast<ObjectMeshSkinned>(node);
// enable targets of the surface
mesh->setSurfaceTargetEnabled(0, 1, true);
mesh->setSurfaceTargetEnabled(0, 2, true);
}
void Morph::update()
{
float time = Game::getTime() * 2.0f;
// calculate weights of targets
float k0 = Unigine::Math::sin(time * 3.0f) + 0.75f;
float k1 = Unigine::Math::cos(time * 3.0f) + 0.75f;
// set targets with parameters
mesh->setSurfaceTargetWeight(0, 0, 1.0f - k0 - k1);
mesh->setSurfaceTargetWeight(0, 1, k0);
mesh->setSurfaceTargetWeight(0, 2, k1);
}
上面给出的代码获取引用FBX文件的节点,并设置参数以变形目标。让我们来澄清一些重要的事情:
-
网格是通过将指向FBX资源的节点强制转换到ObjectMeshSkinned来获得的。要强制转换的节点是组件分配给的节点。在强制转换该节点之前,您可能还需要添加一个检查,以确定该节点是否为ObjectMeshSkinned。
//check if the node to which the component is assigned is MeshSkinned if (node->getType() != Node::OBJECT_MESH_SKINNED) return; // get the node and cast it to a skinned mesh mesh = static_ptr_cast<ObjectMeshSkinned>(node);
- setSurfaceTargetEnabled() 函数为指定的网格表面设置目标。
-
通过 setSurfaceTargetWeight() 函数设置变形目标的权值。 每个目标都有其目标权重。权重对网格的坐标有影响:坐标乘以它们的权重。因此,所有启用的目标都乘以它们的权重,并创建新的网格:
final_xyz = target_0_xyz * weight_0 + target_1_xyz * weight_1 + ... -
为对象启用了三个目标,并以以下方式使用sin()和cos()函数对这些目标进行动画混合:
-
从绑定姿态(bind pose)减去其他两个变形目标的影响,以获得用于混合的规范化权重。
mesh->setSurfaceTargetWeight(0, 0, 1.0f - k0 - k1);
-
使用sin()函数修改第一个目标权重。
mesh->setSurfaceTargetWeight(0, 1, k0);
-
使用cos()函数修改第二个目标权重。
mesh->setSurfaceTargetWeight(0, 2, k1);
-
将组件分配给网格后,结果如下: