添加变形目标
This article describes how to work with the morph target animation also known as blend shapes in UNIGINE. Usually, morph targets are used to change facial expressions of characters.本文描述了如何使用 morph target(变形目标)动画,在UNIGINE中也称为blend shape(混合形状)。通常,变形目标是用来改变人物的面部表情。
The article shows how to export the mesh with morph targets from Autodesk Maya and then add it to UNIGINE.这篇文章展示了如何从Autodesk Maya导出带有变形目标的网格,然后将其添加到UNIGINE。
The model used in this tutorial is Spot by Keenan Crane distributed under CC0 1.0 Universal.本教程中使用的模型是分布在CC0 1.0 Universal下的Spot 由 Keenan Crane。
Requirements需求#
- It is supposed that you already have a 3D model with blend shapes ready to be exported, and this model is within the limitations set in UNIGINE.假设您已经有一个混合形状的3D模型准备导出,并且该模型在UNIGINE设置的限制范围内。
- It is supposed that you already have a world created.假设您已经创造了一个世界。
See Also另请参阅#
- Description of the ObjectMeshSkinned class functionsObjectMeshSkinned类函数的描述
Step 1. Export a Mesh with Blend Shapes from Maya步骤1。从玛雅导出一个网格与混合形状#
This section shows the way of exporting meshes with blend shapes in the FBX format from Autodesk Maya. It contains an example mesh of a calf, which has 2 blend shapes (morph targets).本节展示了从Autodesk Maya导出FBX格式的混合形状网格的方法。它包含一个小牛的示例网格,它有2个混合形状(变形目标)。
To export the mesh with blend shapes, do the following:要导出具有混合形状的网格,请执行以下操作:
-
In Autodesk Maya, select the mesh with blend shapes to be exported.在Autodesk Maya中,选择要导出的混合形状网格。
In the main menu, click File -> Export Selection...在主菜单中,单击File -> Export Selection...
- In the Export Selection window, choose a folder to save the mesh and specify a name for the FBX file. In the Files of type drop-down list, choose FBX export.在Export Selection窗口中,选择一个文件夹来保存网格,并为FBX文件指定一个名称。在Files of type下拉列表中选择FBX export。
- In the File Type Specific Options tab with export options, specify parameters to export the mesh.在带有导出选项的File Type Specific Options选项卡中,指定参数以导出网格。
- In the Deformed Models tab, check the Blend Shapes checkbox to export blend shapes.在Deformed Models选项卡中,选中Blend Shapes复选框以导出混合形状。
- Click Export Selection.单击Export Selection。
Now you have the mesh in the FBX format that can be easily added to your project.现在您有了FBX格式的网格,可以很容易地添加到您的项目中。
Step 2. Add a Mesh into the World步骤2。在世界中添加网格#
This section shows how to add the exported mesh to the world and set up morph target animation.本节将展示如何添加导出的网格动画世界,建立变形目标。
To add the exported mesh to the world:将导出的网格添加到世界中:
-
Import the *.fbx file with the Import Morph Targets option enabled.启用 Import Morph Targets 选项并导入*.fbx文件。
- Add the imported file to the scene.将导入的文件添加到场景中。
- Save the world.保存世界。
Each blend shape of the mesh is a target. You need to enable morph targets for the mesh surface and set parameters to these targets to control the morph target animation. The following example shows how to create morph targets and set parameters via code:网格的每个混合形状都是一个目标。您需要为网格的表面启用变形目标,并为这些目标设置参数来控制变形目标动画。下面的例子展示了如何从代码中创建变形目标和设置参数:
#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);
}
The code given above gets the node that refers to the FBX file and sets parameters to morph targets. Let's clarify the essential things:上面给出的代码获取引用FBX文件的节点,并设置参数以变形目标。让我们来澄清一些重要的事情:
-
The mesh was obtained by casting the node that refers to the FBX asset to ObjectMeshSkinned. The node to be cast is the one to which the component is assigned. Prior to casting this node, you may also want to add a check if it is ObjectMeshSkinned:网格是通过将指向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);
- The setSurfaceTargetEnabled() function sets the target for the specified mesh surface. setSurfaceTargetEnabled() 函数为指定的网格表面设置目标。
-
By using setSurfaceTargetWeight(), weights for morph targets are set. Each target has its target weight. Weights affect coordinates of the mesh: coordinates are multiplied by their weights. Thus, all enabled targets are multiplied by their weights and the new mesh is created: 通过 setSurfaceTargetWeight() 函数设置变形目标的权值。 每个目标都有其目标权重。权重对网格的坐标有影响:坐标乘以它们的权重。因此,所有启用的目标都乘以它们的权重,并创建新的网格:
final_xyz = target_0_xyz * weight_0 + target_1_xyz * weight_1 + ... -
Three targets are enabled for the object and sin() and cos() functions are used for animation blending of these targets in the following way:为对象启用了三个目标,并以以下方式使用sin()和cos()函数对这些目标进行动画混合:
-
Subtract the impact of the other two morph targets from the bind pose to receive a normalized weight for blending.从绑定姿态(bind pose)减去其他两个变形目标的影响,以获得用于混合的规范化权重。
mesh->setSurfaceTargetWeight(0, 0, 1.0f - k0 - k1);
-
The first target weight is modified using the sin() function.使用sin()函数修改第一个目标权重。
mesh->setSurfaceTargetWeight(0, 1, k0);
-
The second target weight is modified using the cos() function.使用cos()函数修改第二个目标权重。
mesh->setSurfaceTargetWeight(0, 2, k1);
-
After assigning the component to the mesh, the result looks as follows:将组件分配给网格后,结果如下: