![]() |
![]() |



Author: LostSoul
Date Submitted: 2004-07-29 17:13:06
/*
==========================
r_GenerateBlendedPose
Creates a single pose from a blended skeletal animation
==========================
*/
int r_GenerateBlendedPose(skinmodel_t* skinmodel, iteminfo_t* item, anim_t* anim, int numblends)
{
float lerp;
int from, to, numbones;
int i, n, s, b0, b1, bRef;
skeleton_t* skel;
bone_t bone, blendedbone, selectiveBlendBone;
float totalweight;
int *selectiveBlends, numOfSelectiveBlends = 0, blendnum;
// If there is no skeletal animation data, do nothing
skel = skinmodel->skeleton;
if (!skel)
return GEOM_STATIC;
// if there are no bones, treat as a static model
if (skel->numbones==0)
return GEOM_STATIC;
// Check one of the blends is valid
if (!r_ValidateAnimBlends(anim, numblends, skel))
return GEOM_STATIC;
// Allocate space in the pose list for the final blended pose of our model
numbones = skel->numbonesperframe;
r_GrowPoseList(numbones);
// Change item->from to point at the pose, as this is how the skinner finds out
item->from = r_model.pose_count;
item->to = 0;
item->lerp = 0;
// allocate enough space to hold indices of selective blends (max = numblends)
selectiveBlends = (int *) ri.com_Malloc(sizeof(int) * numblends);
// walk over all the bones, blend and convert them to mat4's
for (i=0; i<numbones; i++)
{
// Starting a new bone, so reset the weighting
totalweight = 0;
// for all the blends being applied, add them up
for (n=0; n<numblends; n++)
{
// check for selective blend and save blend num for later (only on first bone pass)
if (i == 0)
{
if (anim[n].type==ANIMTYPE_SELECTIVE_BLEND)
{
selectiveBlends[numOfSelectiveBlends] = n;
numOfSelectiveBlends++;
}
}
// skip blends of the wrong type (we are only processing ANIMTYPE_BLEND here
if (anim[n].type!=ANIMTYPE_BLEND )
continue;
// skip items that have a weight of zero
if (anim[n].blend.weight <= 0)
continue;
// I guess this is a good one, so work out the bone for this part
from = anim[n].blend.from;
to = anim[n].blend.to;
lerp = anim[n].blend.lerp;
// Find the "from" and "to" versions of the bone
b0 = skel->boneindex[numbones*from + i];
b1 = skel->boneindex[numbones*to + i];
// blend the two bones and build a matrix for it
r_LerpBone(&skel->bonepool[b0], &skel->bonepool[b1], lerp, &bone);
// mix this bone into the final result
if (totalweight==0)
{
// This is the first one, so just copy it over
blendedbone = bone;
totalweight = anim[n].blend.weight;
}
else
{
// blend this one using the weight provided
totalweight += anim[n].blend.weight;
lerp = anim[n].blend.weight / totalweight;
r_LerpBone(&blendedbone, &bone, lerp, &blendedbone);
}
}
// if there was no blend parts, copy the reference frame over
if (totalweight == 0)
{
b0 = skel->boneindex[i];
blendedbone = skel->bonepool[b0];
}
// reset the weighting
totalweight = 0;
// now handle all Selective Blends
for (s=0; s<numOfSelectiveBlends; s++)
{
blendnum = selectiveBlends[s];
// work out the bone for this part
from = anim[blendnum].blend.from;
to = anim[blendnum].blend.to;
lerp = anim[blendnum].blend.lerp;
// Find the "from" and "to" versions of the bone
b0 = skel->boneindex[numbones*from + i];
b1 = skel->boneindex[numbones*to + i];
// Find reference bone index
bRef = skel->boneindex[i];
// compare positions of from, to and ref bone(no from yet). Skip if all the same
if (skel->bonepool[b1].translate[0] == skel->bonepool[bRef].translate[0] &&
skel->bonepool[b1].translate[1] == skel->bonepool[bRef].translate[1] &&
skel->bonepool[b1].translate[2] == skel->bonepool[bRef].translate[2])
{
continue;
}
// blend the two bones and build a matrix for it
r_LerpBone(&skel->bonepool[b0], &skel->bonepool[b1], lerp, &bone);
// mix this bone into the final result
if (totalweight==0)
{
// This is the first one, so just copy it over
selectiveBlendBone = bone;
totalweight = anim[blendnum].blend.weight;
}
else
{
// blend this one using the weight provided
totalweight += anim[blendnum].blend.weight;
lerp = anim[blendnum].blend.weight / totalweight;
r_LerpBone(&selectiveBlendBone, &bone, lerp, &selectiveBlendBone);
}
}
// If there was no selective blend parts, just use blendedbone for pose
if (totalweight==0)
{
r_BoneToMat4(&blendedbone, r_model.pose_list[r_model.pose_count++]);
}
else
{
if (totalweight > 1)
totalweight = 1;
// combine the selective and blended bones using the total selective weighting
lerp = totalweight;
r_LerpBone(&blendedbone, &selectiveBlendBone, lerp, &selectiveBlendBone);
// Convert the final bone to a matrix
r_BoneToMat4(&selectiveBlendBone, r_model.pose_list[r_model.pose_count++]);
}
}
// Now apply all the bone overrides
for (n=0; n<numblends; n++)
{
// skip blends of the wrong type
if (anim[n].type!=ANIMTYPE_FORCE)
continue;
// This is a good one, so replace the blended bone with the one provided
b0 = anim[n].force.boneid;
mat4_Copy(anim[n].force.transform, r_model.pose_list[b0]);
}
// Free up selectiveBlends array
ri.com_Free(selectiveBlends);
// Use skinning please
return GEOM_SKINFRAME;
}This code will allow you to blend skeletal animation in a specific area of the model. It comes in handy when you have a running cycle and you want the model to move an arm while still running. You can add as many selective animations as you want.
[bold]File Changes:[/bold]
In file r_types.c?
extend the "animation blending constants" by adding ANIMTYPE_SELECTIVE_BLEND to the enum.
Line 69 should look like?
enum
{
ANIMTYPE_NONE,
ANIMTYPE_BLEND,
ANIMTYPE_SELECTIVE_BLEND,
ANIMTYPE_FORCE
};
if (anim[i].type==ANIMTYPE_BLEND)
if (anim[i].type==ANIMTYPE_BLEND || anim[i].type==ANIMTYPE_SELECTIVE_BLEND)
[Recent Contributions] [Recent Source Code]
User Contributed Comments
// compare positions of from, to and ref bone(no from yet). Skip if all the same
if (skel->bonepool[b1].translate[0] == skel->bonepool[bRef].translate[0] &&
skel->bonepool[b1].translate[1] == skel->bonepool[bRef].translate[1] &&
skel->bonepool[b1].translate[2] == skel->bonepool[bRef].translate[2])
{
// compare positions of from, to and ref bone(no from yet). Skip if all the same
if (skel->bonepool[b1].translate[0] == skel->bonepool[bRef].translate[0] &&
skel->bonepool[b1].translate[1] == skel->bonepool[bRef].translate[1] &&
skel->bonepool[b1].translate[2] == skel->bonepool[bRef].translate[2] &&
skel->bonepool[b1].rotate[0] == skel->bonepool[bRef].rotate[0] &&
skel->bonepool[b1].rotate[1] == skel->bonepool[bRef].rotate[1] &&
skel->bonepool[b1].rotate[2] == skel->bonepool[bRef].rotate[2] &&
skel->bonepool[b1].scale[0] == skel->bonepool[bRef].scale[0] &&
skel->bonepool[b1].scale[1] == skel->bonepool[bRef].scale[1] &&
skel->bonepool[b1].scale[2] == skel->bonepool[bRef].scale[2] )
{