This page has been translated automatically.
视频教程
界面
要领
高级
实用建议
基础
专业(SIM)
UnigineEditor
界面概述
资源工作流程
Version Control
设置和首选项
项目开发
调整节点参数
Setting Up Materials
设置属性
照明
Sandworm
使用编辑器工具执行特定任务
如何擴展編輯器功能
嵌入式节点类型
Nodes
Objects
Effects
Decals
光源
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
编程
基本原理
搭建开发环境
C++
C#
UnigineScript
统一的Unigine着色器语言 UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
材质和着色器
Rebuilding the Engine Tools
GUI
双精度坐标
应用程序接口
Animations-Related Classes
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
VR-Related Classes
创建内容
内容优化
材质
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Tutorials

Creating a Simple Mechanism Using Various Types of Joints

A Simple Mechanism Using Joints

A Simple Mechanism Using Joints

This example shows how to:

The basic workflow of creating and animating a simple mechanism is as follows:

  1. Create geometry for all parts of the mechanism.
  2. Assign bodies and collision shapes to the parts.
  3. Set up masses for the parts.
    Notice
    It is very important to ensure mass balance – avoid connection of too heavy bodies to light ones, otherwise the joints may become unstable!
  4. Connect all parts of the mechanism using appropriate types of joints. Set up joint parameters.
  5. Animate the mechanism using joint motors.

Creating Geometry and Adding Some Physics#

The first thing we are going to address in this tutorial is the geometry of our mechanism (see the picture above). We are going to create the following parts:

  • Two blue guide bars
  • a red piston
  • a green rod
  • a black wheel
  • Two dummy objects with dummy bodies to attach the parts of our mechanism to.

We are also going to add some physical parameters to the geometry such as mass and collision shapes. So, we need a set of basic functions:

Source code (C++)
// function creating a named dummy body of a specified size at pos
ObjectDummyPtr createBodyDummy(const char* name, const vec3& size, const Mat4& transform)
{
	// creating a dummy object
	ObjectDummyPtr dummy = ObjectDummy::create();

	// setting parameters
	dummy->setWorldTransform(transform);
	dummy->setName(name);

	//assigning a dummy body to the dummy object and adding a box shape	to it
	BodyDummy::create(dummy);
	dummy->getBody()->addShape(ShapeBox::create(size), translate(0.0f, 0.0f, 0.0f));

	return dummy;
}

// function creating a named box having a specified size, color and transformation with a body and a shape
ObjectMeshDynamicPtr createBodyBox(const char* name, const vec3& size, float mass, const vec4& color, const Mat4& transform)
{
	// creating geometry and setting up its parameters (name, material and transformation)
	ObjectMeshDynamicPtr OMD = Primitives::createBox(size);
	OMD->setWorldTransform(transform);
	OMD->setMaterialParameterFloat4("albedo_color", color, 0);
	OMD->setCollision(1, 0);
	OMD->setName(name);

	// adding physics, i.e. a rigid body and a box shape with specified mass
	BodyRigidPtr body = BodyRigid::create(OMD);
	body->addShape(ShapeBox::create(size), translate(vec3(0.0f)));
	OMD->getBody()->getShape(0)->setMass(mass);

	return OMD;
}

// function creating a named cylinder having a specified size, color and transformation with a body and a shape
ObjectMeshDynamicPtr createBodyCylinder(const char* name, float radius, float height, float mass, const vec4& color, const Mat4& transform)
{
	// creating geometry and setting up its parameters (name, material and transformation)
	ObjectMeshDynamicPtr OMD = Primitives::createCylinder(radius, height, 1, 32);
	OMD->setWorldTransform(transform);
	OMD->setMaterialParameterFloat4("albedo_color", color, 0);
	OMD->setCollision(1, 0);
	OMD->setName(name);

	// adding physics, i.e. a rigid body and a cylinder shape with specified mass
	BodyRigidPtr body = BodyRigid::create(OMD);
	body->addShape(ShapeCylinder::create(radius, height), translate(vec3(0.0f)));
	OMD->getBody()->getShape(0)->setMass(mass);

	return OMD;
}

Now using these functions we can create our mechanism. We are going to use MeshDynamic objects for the parts and Dummy objects for mounting points.

Source code (C++)
// creating parts of the mechanism
Mat4 transform = Mat4(translate(0.0f, 0.0f, 10.0f) * rotateY(90.0f));

piston = createBodyBox("piston", vec3(1.0f, 2.0f, 0.5f), 15.0f, vec4(1.0f, 0.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, 3.5f, 0.0f)));
guide_bar1 = createBodyBox("guide_bar1", vec3(1.0f, 9.0f, 0.5f), 15.0f, vec4(0.0f, 0.1f, 0.7f, 1.0f), transform * Mat4(translate(1.0f, 3.0f, 0.0f)));
guide_bar2 = createBodyBox("guide_bar2", vec3(1.0f, 9.0f, 0.5f), 15.0f, vec4(0.0f, 0.1f, 0.7f, 1.0f), transform * Mat4(translate(-1.0f, 3.0f, 0.0f)));
wheel = createBodyCylinder("wheel", 3.0f, 0.25f, 25.0f, vec4(0.1f, 0.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, -15.0f, -0.5f)));
rod = createBodyCylinder("rod", 0.1f, 15.0f, 5.0f, vec4(0.1f, 1.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, -5.0f, 0.0f) * rotateX(90.0f)));

//creating mounting points
dummy1 = createBodyDummy("dummy1", vec3(1.0f, 1.0f, 1.0f), transform * Mat4(translate(0.0f, -15.0f, -1.5f)));
dummy2 = createBodyDummy("dummy2", vec3(1.0f, 1.0f, 0.5f), transform * Mat4(translate(0.0f, 7.0f, 0.0f)));

Adding and Setting Up Joints#

Now that we have created all parts of our mechanism with physical bodies and shapes, let us link them together with joints.

First, we are going to attach the wheel to the first mounting point(dummy1). The wheel is going to rotate around its axis. Let us use a cylindrical joint here. As the center of the wheel is aligned with the center of dummy1, we may use a simple constructor JointCylindrical() and specify only bodies, the anchor point will be placed automatically between their centers of mass.

Then we must set the coordinates (in the world space) of the axis of wheel rotation. In our case it is (1.0f, 0.0f, 0.0f). And finally set other joint parameters.

Source code (C++)
// creating a cylindrical joint
jc = JointCylindrical::create(dummy1->getBody(), wheel->getBody());

// setting rotation axis in world coordinates
jc->setWorldAxis(vec3(1.0f, 0.0f, 0.0f));

// setting common joint constraint parameters
jc->setLinearRestitution(0.4f);
jc->setAngularRestitution(0.4f);
jc->setLinearSoftness(0.4f);
jc->setAngularSoftness(0.4f);

// setting linear and angular damping
jc->setLinearDamping(4.0f);
jc->setAngularDamping(2.0f);

// setting small linear limits as we are not going to use this degree of freedom to the full extent
jc->setLinearLimitFrom(-0.0005f);
jc->setLinearLimitTo(0.0005f);

// setting the number of iterations
jc->setNumIterations(16);

Now let us attach the rod to the wheel and to the piston. This is where we need a hinge joint. For both of these joints we have to specify anchor point and joint axis coordinates in the JointHinge() constructor.

Source code (C++)
// creating hinge joints
jh = JointHinge::create(wheel->getBody(), rod->getBody(), Vec3(0.0f, -12.5f, 10.0f), vec3(1.0f, 0.0f, 0.0f));
jh2 = JointHinge::create(rod->getBody(), piston->getBody(), Vec3(0.0f, 2.5f, 10.0f), vec3(1.0f, 0.0f, 0.0f));

// setting the number of iterations
jh->setNumIterations(8);
jh2->setNumIterations(8);

The next thing we are going to do is to attach two guide bars to the second mounting point(dummy2) using a pair of fixed joints. For both of these joints we will specify anchor point coordinates in the JointFixed() constructor.

Source code (C++)
// creating fixed joints
jf1 = JointFixed::create(dummy2->getBody(), guide_bar1->getBody(), Vec3(0.0f, 7.0f, 9.0f));
jf2 = JointFixed::create(dummy2->getBody(), guide_bar2->getBody(), Vec3(0.0f, 7.0f, 11.0f));

// setting the number of iterations
jf1->setNumIterations(1);
jf2->setNumIterations(1);

And the last joint we are going to use is a prismatic joint to attach the piston to the second mounting point (dummy2). Here we will specify joint axis coordinates, linear limits to determine the range of motion for the piston and linear softness.

Source code (C++)
// creating a prismatic joint
jp = JointPrismatic::create(piston->getBody(), dummy2->getBody());
jp->setWorldAxis(vec3(0.0f, 1.0f, 0.0f));

// setting linear limits [-5.0; 0.0] and softness
jp->setLinearLimitFrom(-5.0f);
jp->setLinearLimitTo(0.0f);
jp->setLinearSoftness(0.5f);

// setting the number of iterations
jp->setNumIterations(8);

Using Joint Motors#

To animate the mechanism we are going to use the motor of our cylindrical joint. In order to make it move we must set angular velocity and torque:

Source code (C++)
// setting up motor parameters for a cylindrical joint to animate the whole mechanism
jc->setAngularVelocity(1000.0f);
jc->setAngularTorque(150.0f);

Putting it All Together#

Let's sum up all described above. The final code for our tutorial will be as follows:

In the AppWorldLogic.h file, define smart pointers for the objects of our scene.

Source code (C++)
/* .. */
#include <UnigineObjects.h>
#include <UniginePlayers.h>

class AppWorldLogic : public Unigine::WorldLogic
{

public:
	/* .. */

Insert the following code into the AppWorldLogic.cpp file.

Notice
Unchanged methods of the AppWorldLogic class are not listed here, so leave them as they are.
Source code (C++)
/* .. */
#include "AppWorldLogic.h"
#include "UnigineGame.h"
#include "UniginePrimitives.h"

using namespace Unigine;
using namespace Math;

// joints of the mechanism
JointCylindricalPtr jc;
JointHingePtr jh;
JointHingePtr jh2;
JointFixedPtr jf1;
JointFixedPtr jf2;
JointPrismaticPtr jp;

// function creating a named dummy body of a specified size at pos
ObjectDummyPtr createBodyDummy(const char* name, const vec3& size, const Mat4& transform)
{
	// creating a dummy object
	ObjectDummyPtr dummy = ObjectDummy::create();

	// setting parameters
	dummy->setWorldTransform(transform);
	dummy->setName(name);

	//assigning a dummy body to the dummy object and adding a box shape	to it
	BodyDummy::create(dummy);
	dummy->getBody()->addShape(ShapeBox::create(size), translate(0.0f, 0.0f, 0.0f));

	return dummy;
}

// function creating a named box having a specified size, color and transformation with a body and a shape
ObjectMeshDynamicPtr createBodyBox(const char* name, const vec3& size, float mass, const vec4& color, const Mat4& transform)
{
	// creating geometry and setting up its parameters (name, material and transformation)
	ObjectMeshDynamicPtr OMD = Primitives::createBox(size);
	OMD->setWorldTransform(transform);
	OMD->setMaterialParameterFloat4("albedo_color", color, 0);
	OMD->setCollision(1, 0);
	OMD->setName(name);

	// adding physics, i.e. a rigid body and a box shape with specified mass
	BodyRigidPtr body = BodyRigid::create(OMD);
	body->addShape(ShapeBox::create(size), translate(vec3(0.0f)));
	OMD->getBody()->getShape(0)->setMass(mass);

	return OMD;
}

// function creating a named cylinder having a specified size, color and transformation with a body and a shape
ObjectMeshDynamicPtr createBodyCylinder(const char* name, float radius, float height, float mass, const vec4& color, const Mat4& transform)
{
	// creating geometry and setting up its parameters (name, material and transformation)
	ObjectMeshDynamicPtr OMD = Primitives::createCylinder(radius, height, 1, 32);
	OMD->setWorldTransform(transform);
	OMD->setMaterialParameterFloat4("albedo_color", color, 0);
	OMD->setCollision(1, 0);
	OMD->setName(name);

	// adding physics, i.e. a rigid body and a cylinder shape with specified mass
	BodyRigidPtr body = BodyRigid::create(OMD);
	body->addShape(ShapeCylinder::create(radius, height), translate(vec3(0.0f)));
	OMD->getBody()->getShape(0)->setMass(mass);

	return OMD;
}

int AppWorldLogic::init()
{
	// setting up physics parameters
	Physics::setGravity(vec3(0.0f, 0.0f, -9.8f * 2.0f));
	Physics::setFrozenLinearVelocity(0.1f);
	Physics::setFrozenAngularVelocity(0.1f);

	// setting up player
	player = PlayerSpectator::create();

	player->setPosition(Vec3(22.0f, -2.0f, 10.0f));
	player->setDirection(vec3(-10.0f, -2.0f, 0.0f), vec3(0.0f, 0.0f, -1.0f));
	Game::setPlayer(player);

	// creating parts of the mechanism
	Mat4 transform = Mat4(translate(0.0f, 0.0f, 10.0f) * rotateY(90.0f));

	piston = createBodyBox("piston", vec3(1.0f, 2.0f, 0.5f), 15.0f, vec4(1.0f, 0.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, 3.5f, 0.0f)));
	guide_bar1 = createBodyBox("guide_bar1", vec3(1.0f, 9.0f, 0.5f), 15.0f, vec4(0.0f, 0.1f, 0.7f, 1.0f), transform * Mat4(translate(1.0f, 3.0f, 0.0f)));
	guide_bar2 = createBodyBox("guide_bar2", vec3(1.0f, 9.0f, 0.5f), 15.0f, vec4(0.0f, 0.1f, 0.7f, 1.0f), transform * Mat4(translate(-1.0f, 3.0f, 0.0f)));
	wheel = createBodyCylinder("wheel", 3.0f, 0.25f, 25.0f, vec4(0.1f, 0.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, -15.0f, -0.5f)));
	rod = createBodyCylinder("rod", 0.1f, 15.0f, 5.0f, vec4(0.1f, 1.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, -5.0f, 0.0f) * rotateX(90.0f)));

	//creating mounting points
	dummy1 = createBodyDummy("dummy1", vec3(1.0f, 1.0f, 1.0f), transform * Mat4(translate(0.0f, -15.0f, -1.5f)));
	dummy2 = createBodyDummy("dummy2", vec3(1.0f, 1.0f, 0.5f), transform * Mat4(translate(0.0f, 7.0f, 0.0f)));
 
	// creating hinge joints
	jh = JointHinge::create(wheel->getBody(), rod->getBody(), Vec3(0.0f, -12.5f, 10.0f), vec3(1.0f, 0.0f, 0.0f));
	jh2 = JointHinge::create(rod->getBody(), piston->getBody(), Vec3(0.0f, 2.5f, 10.0f), vec3(1.0f, 0.0f, 0.0f));

	// setting the number of iterations
	jh->setNumIterations(8);
	jh2->setNumIterations(8);

	// creating fixed joints
	jf1 = JointFixed::create(dummy2->getBody(), guide_bar1->getBody(), Vec3(0.0f, 7.0f, 9.0f));
	jf2 = JointFixed::create(dummy2->getBody(), guide_bar2->getBody(), Vec3(0.0f, 7.0f, 11.0f));

	// setting the number of iterations
	jf1->setNumIterations(1);
	jf2->setNumIterations(1);

	// creating a prismatic joint
	jp = JointPrismatic::create(piston->getBody(), dummy2->getBody());
	jp->setWorldAxis(vec3(0.0f, 1.0f, 0.0f));

	// setting linear limits [-5.0; 0.0] and softness
	jp->setLinearLimitFrom(-5.0f);
	jp->setLinearLimitTo(0.0f);
	jp->setLinearSoftness(0.5f);

	// setting the number of iterations
	jp->setNumIterations(8);

	// creating a cylindrical joint
	jc = JointCylindrical::create(dummy1->getBody(), wheel->getBody());

	// setting rotation axis in world coordinates
	jc->setWorldAxis(vec3(1.0f, 0.0f, 0.0f));

	// setting common joint constraint parameters
	jc->setLinearRestitution(0.4f);
	jc->setAngularRestitution(0.4f);
	jc->setLinearSoftness(0.4f);
	jc->setAngularSoftness(0.4f);

	// setting linear and angular damping
	jc->setLinearDamping(4.0f);
	jc->setAngularDamping(2.0f);

	// setting small linear limits as we are not going to use this degree of freedom to the full extent
	jc->setLinearLimitFrom(-0.0005f);
	jc->setLinearLimitTo(0.0005f);

	// setting the number of iterations
	jc->setNumIterations(16);

	// setting up motor parameters for a cylindrical joint to animate the whole mechanism
	jc->setAngularVelocity(1000.0f);
	jc->setAngularTorque(150.0f);

	return 1;
}

/* .. */

	
	player->setPosition(Vec3(22.0f, -2.0f, 10.0f));
	player->setDirection(vec3(-10.0f, -2.0f, 0.0f), vec3(0.0f, 0.0f, -1.0f));
	Game::setPlayer(player);

	// creating parts of the mechanism
	Mat4 transform = Mat4(translate(0.0f, 0.0f, 10.0f)*rotateY(90.0f));

	piston = createBodyBox("piston", vec3(1.0f, 2.0f, 0.5f), 15.0f, vec4(1.0f, 0.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, 3.5f, 0.0f)));
	guide_bar1 = createBodyBox("guide_bar1", vec3(1.0f, 9.0f, 0.5f), 15.0f, vec4(0.0f, 0.1f, 0.7f, 1.0f), transform* Mat4(translate(1.0f, 3.0f, 0.0f)));
	guide_bar2 = createBodyBox("guide_bar2", vec3(1.0f, 9.0f, 0.5f), 15.0f, vec4(0.0f, 0.1f, 0.7f, 1.0f), transform* Mat4(translate(-1.0f, 3.0f, 0.0f)));
	wheel = createBodyCylinder("wheel", 3.0f, 0.25f, 25.0f, vec4(0.1f, 0.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, -15.0f, -0.5f)));
	rod = createBodyCylinder("rod", 0.1f, 15.0f, 5.0f, vec4(0.1f, 1.1f, 0.1f, 1.0f), transform * Mat4(translate(0.0f, -5.0f, 0.0f) * rotateX(90.0f)));

	//creating mounting points
	dummy1 = createBodyDummy("dummy1", vec3(1.0f, 1.0f, 1.0f), transform * Mat4(translate(0.0f, -15.0f, -1.5f)));
	dummy2 = createBodyDummy("dummy2", vec3(1.0f, 1.0f, 0.5f), transform * Mat4(translate(0.0f, 7.0f, 0.0f)));

	// creating hinge joints
	jh = JointHinge::create(wheel->getBody(), rod->getBody(), Vec3(0.0f, -12.5f, 10.0f), vec3(1.0f, 0.0f, 0.0f));
	jh2 = JointHinge::create(rod->getBody(), piston->getBody(), Vec3(0.0f, 2.5f, 10.0f), vec3(1.0f, 0.0f, 0.0f));

	// setting the number of iterations
	jh->setNumIterations(8);
	jh2->setNumIterations(8);


	// creating fixed joints
	jf1 = JointFixed::create(dummy2->getBody(), guide_bar1->getBody(), Vec3(0.0f, 7.0f, 9.0f));
	jf2 = JointFixed::create(dummy2->getBody(), guide_bar2->getBody(), Vec3(0.0f, 7.0f, 11.0f));

	// setting the number of iterations
	jf1->setNumIterations(1);
	jf2->setNumIterations(1);

	// creating a prismatic joint
	jp = JointPrismatic::create(piston->getBody(), dummy2->getBody());
	jp->setWorldAxis(vec3(0.0f, 1.0f, 0.0f));

	// setting linear limits [-5.0; 0.0] and softness
	jp->setLinearLimitFrom(-5.0f);
	jp->setLinearLimitTo(0.0f);
	jp->setLinearSoftness(0.5f);

	// setting the number of iterations
	jp->setNumIterations(8);


	// creating a cylindrical joint
	jc = JointCylindrical::create(dummy1->getBody(), wheel->getBody());

	// setting rotation axis in world coordinates
	jc->setWorldAxis(vec3(1.0f, 0.0f, 0.0f));

	// setting common joint constraint parameters
	jc->setLinearRestitution(0.4f);
	jc->setAngularRestitution(0.4f);
	jc->setLinearSoftness(0.4f);
	jc->setAngularSoftness(0.4f);

	// setting linear and angular damping
	jc->setLinearDamping(4.0f);
	jc->setAngularDamping(2.0f);

	// setting small linear limits as we are not going to use this degree of freedom to the full extent
	jc->setLinearLimitFrom(-0.0005f);
	jc->setLinearLimitTo(0.0005f);

	// setting the number of iterations
	jc->setNumIterations(16);

	// setting up motor parameters for a cylindrical joint to animate the whole mechanism
	jc->setAngularVelocity(1000.0f);
	jc->setAngularTorque(150.0f);

	return 1;
}

/* .. */
Last update: 2024-04-18
Build: ()