物体移动与旋转
The objects existing in the virtual world are often moving somewhere and rotating, in general, transforming. Each node has a transformation matrix that encodes its position, rotation, and scale in the world. If a node is a child of another node (part of its hierarchy), it has a transformation matrix associated with the parent (local). This is why the Node class has two different properties: Transform and WorldTransform, which handle local and world transformation matrices respectively.虚拟世界中的物体经常需要进行移动、旋转等变换操作。每个节点都拥有一个变换矩阵,用于记录其在世界中的位置、旋转和缩放比例。当节点作为子节点存在时(属于某个父节点层级),它将拥有一个相对于父节点的局部变换矩阵。因此,Node类提供了两种不同的属性:Transform(局部变换)和WorldTransform(世界变换),分别处理局部和世界坐标系的变换矩阵。
The following code shows how basic node transformations are performed:以下代码展示了基本的节点变换操作实现方式:
// 将Unigine命名空间注入全局命名空间
using namespace Unigine;
using namespace Unigine::Math;
// 沿X/Y/Z轴移动指定距离
node->setWorldPosition(node->getWorldPosition() + Vec3(X, Y, Z));
// 沿Y轴移动1个单位
node->worldTranslate(0.0f, 1.0f, 0.0f);
// 绕(X,Y,Z)轴旋转Alpha角度
node->setWorldRotation(node->getWorldRotation() * quat(Vec3(X, Y, Z), Alpha));
// 绕X/Y/Z轴分别旋转指定角度 (angle_X, angle_Y, angle_Z)
node->setWorldRotation(node->getWorldRotation() * quat(angle_X, angle_Y, angle_Z));
// 绕Z轴旋转45度
node->worldRotate(0.0f, 0.0f, 45.0f);
// 使用方向向量和上向量设置节点朝向
node->setWorldDirection(vec3(0.5f, 0.5f, 0.0f), vec3_up, AXIS_Y);
// 设置节点沿各轴的缩放比例
node->setWorldScale(vec3(Scale_X, Scale_Y, Scale_Z));
// 创建复合变换矩阵:整体缩放2倍 + Z轴旋转45度 + 各轴平移1单位
Mat4 transform = Mat4(translate(vec3(1.0f, 1.0f, 1.0f)) * rotate(quat(0.0f, 0.0f, 1.0f, 45.0f)) * scale(vec3(2.0f)));
// 设置相对于父节点的变换矩阵
node->setTransform(transform);
// 设置相对于世界原点的变换矩阵
node->setWorldTransform(transform);
Practice实践#
Let's add a fan to our scene and try to breathe life into it:让我们为场景添加风扇并实现动态旋转效果:
- Open the archviz/interior/fan folder in the Asset Browser, drag the fan asset fan.fbx to the scene and place it on the table near the bed.在资源浏览器中导航至 archviz/interior/fan 目录并将 fan.fbx 模型拖拽至场景,精确定位于床头桌面上。
-
Open the archviz/interior/fan/materials folder and drag the fan_body_mat_0 material to the fan body, and the fan_propeller_mat_0 material — to the blades.打开 archviz/interior/fan/materials 材质目录,fan_body_mat_0 材质指定给风扇主体和 fan_propeller_mat_0 材质指定给扇叶组件。
-
Now, let's write a component that will rotate its blades. Create a new component, name it Fan and write the following code:现在,我们来编写一个用于旋转风扇叶片的组件。创建一个新组件,命名为 Fan,并编写以下代码:
Fan.h#pragma once #include <UnigineComponentSystem.h> class Fan : public Unigine::ComponentBase { public: // 声明组件构造函数/析构函数,并定义关联属性(property)名称 // 首次运行后将在项目data目录生成Fan.prop属性文件 COMPONENT_DEFINE(Fan, ComponentBase); // 组件参数声明及初始化 PROP_PARAM(Node, fan_node, nullptr); // 需要旋转的扇叶节点 PROP_PARAM(Float, speed, 720.0f); // 旋转速度 // 注册将在世界逻辑相应阶段调用的方法(方法在下面的protected部分中声明) COMPONENT_UPDATE(update); protected: // 声明将在世界逻辑相应阶段调用的方法 void update(); };
Fan.cpp#include "Fan.h" #include <UnigineGame.h> // 注册Fan组件 REGISTER_COMPONENT(Fan); // 注入必要的命名空间 using namespace Unigine; using namespace Math; // 每帧调用的组件 update 方法 void Fan::update() { // 如果风扇叶片节点未分配,则不执行任何操作 if (!fan_node) return; // 以指定速度旋转节点 fan_node->rotate(0, speed * Game::getIFps(), 0); }
-
Let's save our files and then build and run our application by hitting Ctrl + F5 to make the Component System generate a property to be used to assign our component to nodes. Close the application after running it and switch to UnigineEditor.保存文件,然后按Ctrl + F5构建并运行应用程序,使组件系统生成用于将组件分配给节点的属性文件。运行应用程序后将其关闭,然后切换到UnigineEditor。
Create NodeDummy, name it fan_rotator, and assign our new generated Fan property to it. Customize the Fan component by dragging the fan_table_propeller node into the Fan Node field and setting the rotation speed of the blades.创建NodeDummy节点,命名为fan_rotator,并将我们新生成的Fan属性分配给它。通过将fan_table_propeller节点拖到Fan Node字段并设置叶片的旋转速度来自定义Fan组件。
- Let's add fan_rotator to the child nodes of fan_table_lod_0, assign the Toggle component to the fan_table_switch node, and drag the fan_rotator node into the Control Node field.将fan_rotator添加为fan_table_lod_0的子节点,为fan_table_switch节点分配Toggle组件,并将fan_rotator节点拖到Control Node字段。
-
然后我们应该禁用fan_rotator节点(通过在Parameters(参数)窗口中取消节点名称旁边的复选框),以防止旋转扇叶的组件代码在我们打开开关前执行。
-
We're going to rotate the fan_table_propeller node, by default it's Mobility is set to Immovable, so we have to switch it to Dynamic.我们将旋转 fan_table_propeller节点,默认情况下它的Mobility设置为Immovable,因此我们需要将其改为Dynamic。
-
Save the world by hitting Ctrl + S. Switch to SDK Browser and launch our application by clicking the Run button on our project's card to see the result.按Ctrl + S保存场景。切换到SDK Browser,通过点击项目卡片上的Run按钮启动我们的应用程序以查看结果。
本页面上的信息适用于 UNIGINE 2.20 SDK.