基本的对象运动
待您将对象添加给Unigine之后,就可以通过外部控制设备来控制其变换了。 本文向您展示了如何控制基本的对象运动,如何组合不同的变换。
另请参阅
- 矩阵变换(Matrix Transformations)。
- Unigine数据类型mat4和dmat4。
- 数学矩阵函数(Math Matrix Functions)章节中的描述。
- engine.controls章节中的描述。
方向向量
方向向量是mesh变换的重要概念。 要想向前移动节点,就须知晓mesh的前进方向在哪。 当mesh被从3D设计软件导出时,它是保存有与前进方向有关的信息的。 在您将mesh添加给了Unigine时,其朝向将与它在3D设计软件中的朝向一致。
Maya中的mesh |
相同的mesh在Unigine |
上述两幅图中,方向向量都拥有正的Y方向。 要想向前移动这个mesh,就须通过网格的世界变换矩阵的Y分量(指矩阵的第二列)来获取该mesh的方向。
例如,在City Traffic(城市交通)项目中,方向向量拥有正的Y方向。 要想将新的car添加给City Traffic(要将所有逻辑应用给已添加的car),那它从3D设计软件导出时就应带有指定的方向向量。
需要指出的是,内容创建者和程序员应就方向向量问题进行协商。
基本运动
向前移动
这部分包含了设置mesh前向移动的不同方式。
在本例中,我们使用了按"p"键向前移动mesh的方法。
// 定义ObjectMeshStatic网格和移动速度
ObjectMeshStatic mesh;
float movement_speed = 5.0f;
// 初始化自定义控制(controls)
void init_controls() {
// 检测按键是否被按下以及更新指定control的状态
// 您可以使用'p',也可以使用ASCII码(112)
engine.controls.setStateKey(CONTROLS_STATE_AUX_0,'p');
}
// 将mesh作为节点添加给Editor
Node add_editor(Node node) {
engine.editor.addNode(node);
return node_remove(node);
}
/* world(世界)脚本的init()功能
*/
int init() {
/* 创建一摄像机并将其添加给虚拟世界
*/
Player player = new PlayerSpectator();
player.setDirection(Vec3(0.755f,-1.0f,0.25f));
engine.game.setPlayer(player);
// 将mesh添加给虚拟世界并设置材质
mesh = add_editor(new ObjectMeshStatic("unigine_project/meshes/statue.mesh"));
mesh.setMaterial("mesh_base", "*");
// 调用init_controls()函数
init_controls();
return 1;
}
/* world(世界)脚本的update()功能
*/
int update() {
// 获取帧时长
float ifps = engine.game.getIFps();
// 检查控制键是否被按下
if(engine.controls.getState(CONTROLS_STATE_AUX_0)) {
// 获取mesh的当前世界变换矩阵
Mat4 transform = mesh.getWorldTransform();
// 获取mesh的方向向量
Vec3 direction = transform.m00m10m20;
// 计算移动的增量
Vec3 delta_movement = direction * movement_speed * ifps;
// 为mesh设置新位置
mesh.setWorldPosition(mesh.getWorldPosition() + delta_movement);
}
return 1;
}
另一种获取方向向量的方法是通过如下命令:
Vec3 direction = Vec3(transform.col0);
这行代码显然更具可读性,不过却需要对Vec3进行附加的强制类型转换。
设置网格位置的其它方法
也可通过setWorldTransform()函数设置新位置。 下面的几个例子都包含了取自world(世界)脚本的update功能代码。 对这一方法而言,控制(controls)的初始化部分都是相同的,不同之处是world(世界)脚本的update()功能内部。
// 检查控制键是否被按下
if(engine.controls.getState(CONTROLS_STATE_AUX_0)) {
// 获取mesh的当前世界变换矩阵
Mat4 transform = mesh.getWorldTransform();
// 获取mesh的方向向量
Vec3 direction = transform.m00m10m20;
// 计算移动的增量
Vec3 delta_movement = direction * movement_speed * ifps;
// 为mesh设置新位置
mesh.setWorldTransform(translate(delta_movement) * transform);
}
或者,您也可更改世界变换矩阵的平移列(具体情况矩阵变换(Matrix Transformations)章节)来移动mesh:
// 检查控制键是否被按下
if(engine.controls.getState(CONTROLS_STATE_AUX_0)) {
// 获取mesh的当前世界变换矩阵
Mat4 transform = mesh.getWorldTransform();
// 获取mesh的方向向量
Vec3 direction = transform.m00m10m20;
// 计算移动的增量
Vec3 delta_movement = direction * movement_speed * ifps;
// 设置新位置
// 此处您也可使用transform.m03m13m23 += delta_movement;
transform.col3 += Vec4(delta_movement,1.0f);
// 为mesh设置新的世界变换矩阵
mesh.setWorldTransform(transform);
}
旋转
这部分包含了mesh旋转的实现。
您可以使用两种方式来旋转mesh,它们是setWorldTransform()函数或setWorldRotation()函数。 下面的例子使用的是setWorldRotation()函数:
// 定义ObjectMeshStatic网格和移动速度
ObjectMeshStatic mesh;
float rotation_speed = 30.0f;
// 初始化自定义控制(controls)
void init_controls() {
// 检测按键是否被按下以及更新指定control的状态
// 您可以使用'o',也可以使用ASCII码(111)
engine.controls.setStateKey(CONTROLS_STATE_AUX_1,'o');
}
// 将mesh作为节点添加给Editor
Node add_editor(Node node) {
engine.editor.addNode(node);
return node_remove(node);
}
/* world(世界)脚本的init()功能
*/
int init() {
/* 创建一摄像机并将其添加给虚拟世界
*/
Player player = new PlayerSpectator();
player.setDirection(Vec3(0.755f,-1.0f,0.25f));
engine.game.setPlayer(player);
// 将mesh添加给虚拟世界并设置材质
mesh = add_editor(new ObjectMeshStatic("unigine_project/meshes/statue.mesh"));
mesh.setMaterial("mesh_base", "*");
// 调用init_controls()函数
init_controls();
return 1;
}
/* world(世界)脚本的update()功能
*/
int update() {
// 获取帧时长
float ifps = engine.game.getIFps();
/* 这块代码用来旋转mesh
*/
// 检查控制键是否被按下
if(engine.controls.getState(CONTROLS_STATE_AUX_1)) {
// 设置沿Z轴的节点旋转
mesh.setWorldRotation(mesh.getWorldRotation() * quat(rotateZ(rotation_speed * ifps)));
}
return 1;
}
在上面的例子中,通过按下键盘按键"o"就可以让节点向左旋转。
要想使用setWorldTransform()函数,须用下行代码替换setWorldRotation()函数:
mesh.setWorldTransform(mesh.getWorldTransform() * rotateZ(rotation_speed * ifps));
组合运动
组合不同的运动控制不比只添加一种运动控制难多少。
下面的例子将一个mesh添加给了虚拟世界,并且您还能控制这个mesh。 您能通过键盘按键"o","["旋转它,能通过键盘按键"p"向前移动它。
// 定义ObjectMeshStatic网格和移动速度
ObjectMeshStatic mesh;
float movement_speed = 5.0f;
float rotation_speed_left = 30.0f;
float rotation_speed_right = -30.0f;
// 初始化自定义控制(controls)
void init_controls() {
// 检测按键是否被按下以及更新指定control的状态
// 您可以使用'p',也可以使用ASCII码(112)
engine.controls.setStateKey(CONTROLS_STATE_AUX_0,'p');
engine.controls.setStateKey(CONTROLS_STATE_AUX_1,'o');
engine.controls.setStateKey(CONTROLS_STATE_AUX_2,'[');
}
// 将mesh作为节点添加给Editor
Node add_editor(Node node) {
engine.editor.addNode(node);
return node_remove(node);
}
/* world(世界)脚本的init()功能
*/
int init() {
/* 创建一摄像机并将其添加给虚拟世界
*/
Player player = new PlayerSpectator();
player.setDirection(Vec3(0.755f,-1.0f,0.25f));
engine.game.setPlayer(player);
// 将mesh添加给虚拟世界并设置材质
mesh = add_editor(new ObjectMeshStatic("unigine_project/meshes/statue.mesh"));
mesh.setMaterial("mesh_base", "*");
// 调用init_controls()函数
init_controls();
return 1;
}
/* world(世界)脚本的update()功能
*/
int update() {
// 获取帧时长
float ifps = engine.game.getIFps();
// 检查用于向前移动的控制键是否被按下
if(engine.controls.getState(CONTROLS_STATE_AUX_0)) {
// 获取mesh的当前世界变换矩阵
Mat4 transform = mesh.getWorldTransform();
// 获取mesh的方向向量
Vec3 direction = transform.m00m10m20;
// 计算移动的增量
Vec3 delta_movement = direction * movement_speed * ifps;
// 为mesh设置新位置
mesh.setWorldPosition(mesh.getWorldPosition() + delta_movement);
}
// 检查用于左旋转的控制键是否被按下
if(engine.controls.getState(CONTROLS_STATE_AUX_1)) {
// 设置节点的左旋转
mesh.setWorldRotation(mesh.getWorldRotation() * quat(rotateZ(rotation_speed_left * ifps)));
}
// 检查用于右旋转的控制键是否被按下
if(engine.controls.getState(CONTROLS_STATE_AUX_2)) {
// 设置节点的右旋转
mesh.setWorldRotation(mesh.getWorldRotation() * quat(rotateZ(rotation_speed_right * ifps)));
}
return 1;
}