Bones - Skeletal and Pose animations for jPCT

Started by raft, January 06, 2010, 11:45:01 PM

Previous topic - Next topic

Babu

hi raft,

I am back  ;).  I could load the cylinder model with the pose animations in my Android app and I could have all the pose animations working fine.  I see that the skin-animation, "wave" is also working fine. 

But I am facing a problem when I try to have both skin and pose animations working together :(.  I am able see only that animation which I apply last in the code i.e. if I call animatePose() last then I see only pose animation and if I call animateSkin() last then I see only skin animation.  I am not sure if I am doing some wrong  ???.  Below is the code for onDrawFrame().  I am using Ninja Demo as the base for my app.


                public void onDrawFrame(GL10 gl)
{
if (frameBuffer == null) return;

long now = System.currentTimeMillis();
aggregatedTime += (now - frameTime);
frameTime = now;

if (aggregatedTime > 1000)
{
aggregatedTime = 0;
}

while (aggregatedTime > GRANULARITY)
{
aggregatedTime -= GRANULARITY;
skinAnimateSeconds += GRANULARITY * 0.001f * speed;
poseAnimateSeconds += GRANULARITY * 0.001f * speed;
placeCamera();
}

if (poseAnimation > 0 && rockyCylinder.getPoseClipSequence().getSize() >= poseAnimation)
{
float clipTime = rockyCylinder.getPoseClipSequence().getClip(poseAnimation-1).getTime();
if (poseAnimateSeconds > clipTime)
{
poseAnimateSeconds = 0;
}
float index = poseAnimateSeconds / clipTime;

rockyCylinder.animatePose(index, poseAnimation);
}
else
{
poseAnimateSeconds = 0f;
}

////////////////////////// START BLOCK /////////////////////////////////////////
/////// If I move this block above pose animation then "wave" doesn't happen//////////
if (skinAnimation > 0 && rockyCylinder.getSkinClipSequence().getSize() >= skinAnimation)
{
float clipTime = rockyCylinder.getSkinClipSequence().getClip(skinAnimation-1).getTime();
if (skinAnimateSeconds > clipTime)
{
skinAnimateSeconds = 0;
}
float index = skinAnimateSeconds / clipTime;

rockyCylinder.animateSkin(index, skinAnimation);
}
else
{
skinAnimateSeconds = 0f;
}
////////////////////////// END BLOCK /////////////////////////////////////////

rockyCylinder.applyAnimation();

frameBuffer.clear();
world.renderScene(frameBuffer);
world.draw(frameBuffer);

frameBuffer.display();
}


raft

that's because autoApplyAnimation is enabled by default. call AnimatedGroup.setAutoApplyAnimation(false) once after loading group.

first apply pose animations, then skin animation. finally call AnimatedGroup.applyAnimation().

Babu


panthenol

#243
usefull piece of info here also !  thanks guys for sharing this  :D

frag-a

Hi raft, first of all thanks for this great lib. I'm playing around with some 3D game dev stuff, but I don't have much experience...yet :)
It was relatively easy to get into jpct and bones but I suck at math, so I wonder if you could help me here with this attempt to do some IK.
The goal is to have some character to grab or to point to some other object. The below code works fine if the rotation starts from the bind pose.
But if it's not from the bind pose, it just get crazy! Could you please help me figure out whats missing? Thanks in advance.


private static final void targetJoint(final SimpleVector targetTranslation, final SkeletonPose pose, int handleIndex, int parentIndex) {
final Skeleton skeleton = pose.getSkeleton();
final Joint handleJoint = skeleton.getJoint(handleIndex);
final Joint parentJoint = skeleton.getJoint(parentIndex);
final Matrix parentInverseBindPose = parentJoint.getInverseBindPose();
final Matrix parentBindPose = parentInverseBindPose.invert();

final SimpleVector handleTranslation = pose.getGlobal(handleIndex).getTranslation();
final SimpleVector parentTranslation = pose.getGlobal(parentIndex).getTranslation();

float distance = handleTranslation.distance(targetTranslation);
if (distance > 0.1) {
SimpleVector parentHandleVector = handleTranslation.calcSub(parentTranslation);
parentHandleVector = parentHandleVector.normalize();
parentHandleVector.rotate(parentInverseBindPose);

SimpleVector parentTargetVector = targetTranslation.calcSub(parentTranslation);
parentTargetVector = parentTargetVector.normalize();
parentTargetVector.rotate(parentInverseBindPose);

float angle = parentHandleVector.calcAngle(parentTargetVector);
if (Math.abs(angle) > 0.1f) {
Quaternion quat = new Quaternion().fromVectorToVector(parentHandleVector, parentTargetVector);
final Matrix rotation = quat.getRotationMatrix();
rotation.matMul(parentBindPose);
rotation.matMul(pose.getSkeleton().getJoint(parentJoint.getParentIndex()).getInverseBindPose());
pose.getLocal(parentIndex).setTo(rotation);
}
}
}


raft

i'm no expert at these calculations either, most of the time they drives me crazy too :-\

but, it's not surprising that it goes crazy if you apply a transform based on bind pose to a pose not in bind pose. the thing you should remember is that each joint's transform is in its parent's space. all calculations depend on this.

although not strictly sure, IMHO you should do something like this:
* store your initial pose somewhere
* on each frame calculate desired world space transform of joints (ProceduralAnimationSample does this)
* then, starting from first joint, remove parent transform (multiply with parent's inverse transform). joints are ordered such that parent always come before child, so it's guaranteed that parents are updated before childs
* set local transform of joint to result of this

ProceduralAnimationSample does this but since it starts from bind pose, it uses bind pose transforms instead of another pose transforms

also have a look at this tutorial, it's one of the best texts i have found describing the subject:
http://www.okino.com/conv/skinning.htm

frag-a

Thanks, I'll take a look at your suggestions and do some more tries.
I'll put the code here if I can make it work.

frag-a

#247
Hi raft, After some head banging I got it working ;D
Solution is to transform all vectors to joint's local space and do the rotation from the bind pose.
Here is the code, maybe it's useful to someone else.


private static final void targetJoint(final SimpleVector targetTranslation, final SkeletonPose pose, int handleIndex, int parentIndex) {
final Skeleton skeleton = pose.getSkeleton();
final Joint handleJoint = skeleton.getJoint(handleIndex);
final Joint parentJoint = skeleton.getJoint(parentIndex);
final Matrix parentInverseBindPose = parentJoint.getInverseBindPose();
final Matrix parentBindPose = parentInverseBindPose.invert();

final SimpleVector parentVector = pose.getLocal(parentIndex).getTranslation();
final SimpleVector handleVector = pose.getLocal(handleIndex).getTranslation();
float distance = handleVector.distance(targetTranslation);
if (distance > 0.1) {
final SimpleVector targetVector = new SimpleVector(targetTranslation);
targetVector.matMul(parentInverseBindPose);
float angle = handleVector.calcAngle(targetVector);
if (Math.abs(angle) > 0.1f) {
final SimpleVector bindPoseVector = handleJoint.getBindPose().getTranslation();
bindPoseVector.matMul(parentInverseBindPose);

final Matrix rotation = new Quaternion().fromVectorToVector(bindPoseVector, targetVector).getRotationMatrix();
rotation.matMul(parentBindPose);
rotation.matMul(pose.getSkeleton().getJoint(parentJoint.getParentIndex()).getInverseBindPose());
pose.getLocal(parentIndex).setTo(rotation);
}
}
}


Corrected some bugs.

Babu

hi raft,

I am planning to use a mesh (that sits on the same skeleton as the body) for shirt.  Is it possible to use the same mesh for full-sleeve and half-sleeve shirts.  If that is possible, how do we assign the texture coordinates?

Thanks,
Babu

raft


Alexey

Hi!
I tried export mesh + animation from blender (2.57). When i exporting collada and load dae in bones sample, only one animation present. I make 2 animation actions in blender but only one loads. I should make animation actions in some specific way in blender? And another question - i setup http://code.google.com/p/blender2ogre/ blender-ogre exporter and try load exported someMesh.mesh.xml, but then java.nio.BufferOverflowException throw & the same when try convert by .bat . Result .mesh.xml file, i suspicious, is too big 3.2 mb (.dae only ~600kb).  I need another exporter or ?

raft

i never used blender. in theory collada files support multiple animations but i never saw such a real file with. play with exporter options, maybe that helps. othwerise you can merge many files with single animation into one. the provided collada import scripts allows many input files for this purpose. for that to work, meshes and skeletons should be identical. you can also programatically do the merge via AnimatedGroup.mergeAnimations(..) method.

for ogre, i dont think it's because of file size. possibly an issue with either exporter or jME's importer. please post the stack trace for more information.

raft