Blend animation layer with script bone transform


photo

Recommended Posts

Hello, I use ObjectMeshSkinned object, that is always watch on player.

Part of code of that I use from one of unigine examples:

 

ObjectMeshSkinned meshSkinned;

void update()
{
float time = engine.game.getTime();

int indexBoneHip = meshSkinned.findBone("hip");
int indexBoneChest = meshSkinned.findBone("chest");
int indexBoneHead = meshSkinned.findBone("head");

vec3 nodePosition = node.getWorldPosition();
vec3 targetPosition = target.getWorldPosition();

float x = nodePosition.x - targetPosition.x;
float y = nodePosition.y - targetPosition.y;

float angle = atan2(y, x) * RAD2DEG;

mat4 boneChestTransform = meshSkinned.getFrameBoneTransform(indexBoneChest);
vec3 boneChestPivot = boneChestTransform.m03m13m23;

boneChestTransform = translate(boneChestPivot) * rotateX(angle);

meshSkinned.setFrameBoneTransform( indexBoneChest, boneChestTransform );
}

 

This is work good, but if I add an idle animation:

meshSkinned.setAnimation("source/animation/robot_idle.smesh");
meshSkinned.setLoop(true);
meshSkinned.play();

My object play only this animation.

How may I blend an animation with script bone transformation?

Thanks.

Link to post

Based on documentation for ObjectMeshSkinned I would guess that you have to use 2 animation layers, one for the idle animation and one for your procedural bone animation. Most probably you also have to use setBoneTransform() instead of setFrameBoneTransform() as documenation states

 

void setFrameBoneTransform(int bone,mat4 transform)

 

Description

 

Sets a transformation matrix for a given bone. The difference from setBoneTransform() is that this method takes into account only the transformation in the current animation layer (no blending is done).

Link to post

I see. I load animation to layer 0 and add layer 1:

meshSkinned.setLayer(0);
meshSkinned.setWeight(0.5);
meshSkinned.setAnimation("source/animation/robot_idle.smesh");
meshSkinned.setLoop(true);
meshSkinned.play();

meshSkinned.addLayer();

meshSkinned.setLayer(1);
meshSkinned.setWeight(0.5);

 

In fact animation don't play and nothing change. If I add line

meshSkinned.setLayer(0);

then idle animation is playing. But my script works only if I comment line

meshSkinned.play();

Link to post

#ifndef REVOLVABLE_H_
#define REVOLVABLE_H_

namespace Source
{
class Revolvable
{
	private:
		Node node;
		Node target;

		float rotation = 0;

		//vec3 targetPosition;
	public:
		ObjectMeshSkinned meshSkinned;

		int active = 0;

		Revolvable(Node node)
		{
			this.node = node;

			meshSkinned = class_cast(node.getTypeName(), node);

			meshSkinned.setLayer(0);
			meshSkinned.setWeight(0.5);
			meshSkinned.setAnimation("source/animation/robot_idle.smesh");
			meshSkinned.setLoop(true);
			//meshSkinned.play();

			meshSkinned.addLayer();

			meshSkinned.setLayer(1);
			meshSkinned.setWeight(0.5);
			//meshSkinned.setLayer(0);
		}

		void update()
		{
			// active and target I set outer from this class
			if (active == 1 && target != NULL)
			{
				float time = engine.game.getTime();

				int indexBoneHip = meshSkinned.findBone("hip");
				int indexBoneChest = meshSkinned.findBone("chest");
				int indexBoneHead = meshSkinned.findBone("head");

				vec3 nodePosition = node.getWorldPosition();
				vec3 targetPosition = target.getWorldPosition();

				float x = nodePosition.x - targetPosition.x;
				float y = nodePosition.y - targetPosition.y;

				float angle = atan2(y, x) * RAD2DEG;

				//mat4 transform = mesh.getWorldBoneTransform(indexBone) * rotateY(90.0);
				mat4 boneChestTransform = meshSkinned.getBoneTransform(indexBoneChest);
				vec3 boneChestPivot = boneChestTransform.m03m13m23;

				boneChestTransform = translate(boneChestPivot) * rotateX(angle);

				meshSkinned.setBoneTransform( indexBoneChest, boneChestTransform );
			}
		}
};
};

#endif

 

In main class I do next:

Node nodeWoman = engine.editor.getNodeByName("robot");	
robot = new Revolvable(nodeWoman);

 

In this way script transform is apply, if I uncomment play() then nothing doing. If I call setLayer(0) when idle animation is play, but script transformation not apply.

Link to post

In manual ObjectMeshSkinned Class include next:

post-151-0-32605800-1292515530_thumb.jpg

What a methods includes to this groups? Thanks.

Link to post

Oops, my bad.

 

2. Methods that set a flag indicating that the update of animation data is required. These methods should be called before the methods from the 3rd group.

  • addLayer()
  • removeLayer()
  • setNumLayers()
  • setBuffer() in case bone transformations are applied to one specific layer
  • setFrame()
  • setFrameBoneTransform()

 

3. Methods that call for update. Animation data will be recalculated during the update only if the corresponding flag was previously set by a function from the 2nd group.

  • getBuffer() in case bone transformations are grabbed from one specific layer
  • setBoneTransform()
  • setBoneChildsTransform()
  • getBoneTransform()

Link to post
  • 1 month later...

In manual addlayer() description is:

 

ObjectMeshSkinned::addLayer

void addLayer()

Description

Adds an animation layer.

 

But in animation_tree.h is:

AnimationTree(ObjectMeshSkinned mesh_) {

mesh = mesh_;
layer = mesh.addLayer;

mesh.setLayer(0);
mesh.setWeight(0.0f);

parameters = new ParameterManager();
}

 

So addLayer() return an index of newest layer?

Link to post

In case of complex animation schemes (layers or buffers) you shouldn't use play() function. play() function calls setFrame() every frame for active layer.

Link to post

For active layer? So I must use, for example

void update()
{
meshSkinned.setFrame(time, 0, 20);
}

 

and it blend all layers, or I need use something like next:

void update()
{
meshSkinned.setLayer(0);
meshSkinned.setFrame(time, 0, 20);

meshSkinned.setLayer(1);

int indexBoneChest = meshSkinned.findBone("chest");

mat4 boneChestTransform = meshSkinned.getBoneTransform(indexBoneChest);

vec3 boneChestPosition = Math::decomposePositionXYZ(boneChestTransform);
vec3 boneChestRotation = Unigine::decomposeRotationYZX(boneChestTransform);
boneChestRotation.x += 0.5;

boneChestTransform = translate(boneChestPosition) * Unigine::composeRotationYZX(boneChestRotation);

meshSkinned.setBoneChildsTransform( indexBoneChest, boneChestTransform );

meshSkinned.setFrame(time, 0, 20);
}

 

This code have no effect... If I use only layer with animation (meshSkinned.setAnimation("source/animation/robot_idle.sanim"):) and use meshSkinned.setFrame(time, 0, 20); in update function this is work (instead of play()), but with bone transform this is not work.

Link to post

I think setFrame() function rewrites bone transformation from previous setBoneChildsTransform():

 

meshSkinned.setBoneChildsTransform( indexBoneChest, boneChestTransform );
meshSkinned.setFrame(time, 0, 20);

 

MeshSkinned has single final array of bone transformation.

Each layer has own bone transformation array and weight of whole layer.

Final bone transformation array is updated on several functions like:

* getBuffer()

* setBoneTransform()

* setBoneChildsTransform()

* getBoneTransform()

 

This behaviour is described in this documentation section: code/scripting/library/objects/class.objectmeshskinned

 

If you should only change transformation of single bone you shouldn't use layers:

 

void update() {
 mesh.setFrame(time);
 mat4 transform = mesh.getBoneTransform(bone);
 // update transformation
 mesh.setBoneChildsTransform(bone,transform);
}

Link to post
  • 7 months later...

I was blended two or more animation.

 

i want to help to your problem solved.

 

this is my animation blending sample script.

 

 

--- script -------------------------------------------------------------------------------------------------

ObjectMeshSkinned meshSkinned;

meshSkinned.setLayer(0); // set layer

meshSkinned.setAnimation("animation0.sanim");

meshSkinned.setFrame(1); // set animation0 frame

meshSkinned.getBuffer(bufferindex0, 0); // capture current layer animation to bufferindex0

 

meshSkinned.setAnimation("animation1.sanim");

meshSkinned.setFrame(1); // set animation1 frame

meshSkinned.getBuffer(bufferindex1, 0); // capture current layer animation to bufferindex1

 

meshSkinned.setAnimation("animation2.sanim");

meshSkinned.setFrame(1); // set animation2 frame

meshSkinned.getBuffer(bufferindex2, 0); // capture current layer animation to bufferindex2

 

meshSkinned.lerpBuffer(bufferindex0, bufferindex0, bufferindex1, 0.5);

meshSkinned.lerpBuffer(bufferindex0, bufferindex0, bufferindex2, 0.5);

meshSkinned.lerpBuffer(bufferindex0, bufferindex0, bufferindex3, 0.5);

 

meshSkinned.setBuffer(bufferindex0, 0); // lerped buffer data to rendering layer.

Link to post