Mostly Harmless

Legacy:Skeletal Mesh

From Unreal Wiki, The Unreal Engine Documentation Site

Jump to: navigation, search
UT2003 :: Actor >> SkeletalMesh

Skeletal Animation was introduced in UT2003 (though some partial support was implemented in the final builds of the Unreal Tournament Generation of engines).

It allows a player to be animated by specifying the movement of their bones, while the 'skin' twists and deforms automatically. This has the advantage of allowing some combination of animations.

Combination of animations is used only sparingly in UT2003. In the behindview you can see that your torso barely moves when you run, but in the animation browser, the animation dictates that the weapon be pointed to the side while running. The idle animation is set to override the running animation on the spine and above. Thus the bones above the spine always play the idle animation even when the lower portions are running. This is an example of animation blending in UT2003. Skeletal animation is also integrated into the Karma Ragdoll system, so is important for that reason. They are defined in actor, and are accessible from any Actor that uses DrawType = DT_Mesh.

[edit] Functions

All these functions are declared in the Actor class:

LinkSkelAnim( MeshAnimation Anim, optional Mesh NewMesh ) (simulated, native, final) 
Sets the skeletal animation settings for this actor. If you supply a mesh argument, the mesh will also be changed.
LinkMesh( Mesh NewMesh, optional bool bKeepAnim ) (simulated, native, final) 
Similar to LinkSkelAnim, this only links the mesh. The optional variable specifies whether the current skeletal animation settings should be retained. If it is true, the skeletal animation settings will remain unchanged. If it is false, the skeletal animation settings will be set to none, or to the defaults included in the mesh, if applicable.
BoneRefresh() (native, final) 
Forces a bone refresh to ensure that bones have been set up and updated.
AnimBlendParams(int Stage, optional float BlendAlpha, optional float InTime, optional float OutTime, optional name BoneName, optional bool bGlobalPose) [native final] 
This sets the parameters for the animation blending. This is the amount that animations will be merged in the event that two conflicting animations play simulataneously on different channels. Stage is the channel that you want to set blending parameters for. InTime is the amount of time for which to interpolate in the blending. Thus, if Blendalpha is 0 and you set it to 1 with this function, using InTime of 1, it will wake 1 second before BlendAlpha is 1. At half a second it will be 0.5, etc. BlendAlpha is the amount to blend the animations. I believe that 0 is fully the channel with a lower number, 1 is fully the channel with the greater number, and 0.5 is half way (each animation applies half the motion to the bone that they would like to. Outtime is not implemented in the current build of the Unreal Engine. Bonename can be used to selectively set blending on certain bones. I do not know what bGlobalPost does.
AnimBlendToAlpha( int Stage, float TargetAlpha, float TimeInterval ) (native, final) 
I believe that this is similar to AnimBlendParams, but with less parameters. It probrably executes faster too.
coords GetBoneCoords( name BoneName ) (native, final) 
Returns the coordinates of a bone - This is the bone's built-in coordinate system. This could probrably be used to find the absolute rotation of a bone, using some vector maths.
rotator GetBoneRotation( name BoneName, optional int Space ) (native, final) 
Returns the rotation of a bone. The optional parameter Space specifices the coordinate system (0 - local [default], 1 - global, 2 - relative to reference pose).
vector GetRootLocation() (native, final) 
Returns the location of the "root" of the skeleton. Likely relative to the world.
rotator GetRootRotation() (native, final) 
Returns the rotation of the "root" of the skeleton. Relative to the world origin.
vector GetRootLocationDelta() (native, final) 
Retrieves the location difference since last time GetRootLocationDelta was called.
rotator GetRootRotationDelta() (native, final) 
Not fully implemented yet - always returns (0,0,0).
bool AttachToBone( Actor Attachment, name BoneName ) (native, final) 
Attaches an actor to the bone specified.
bool DetachFromBone( Actor Attachment ) (native, final) 
Detaches the stated actor from any bone that it may be attached to.
LockRootMotion( int Lock ) (native, final) 
Call with 1 (or larger) to enable, disable by calling with 0.
SetBoneScale( int Slot, optional float BoneScale, optional name BoneName ) (native, final) 
Sets the "drawscale" of the bone, and of the "skin" that is considered attached to that bone. It will affect not only the bone you specified, but also all "child bones" of that bone. Slot is the "slot" that the scalar is stored in. To clear a "slot," you must call this function with just the slot and no parameters. Slots are not per-bone, they are per-actor. This is best illustrated with an example:
// This works.
SetBoneScale (0, 2, 'Spine');
SetBoneScale (1, 2, 'Head');
SetBoneScale (2, 2, 'LFARM');
 
// Even though these are differen't slot/bone combinations, the slots 0, 1, and 2 are
// overridden by the new bone and scalar information.
SetBoneScale (1, 2, 'Spine');
SetBoneScale (2, 2, 'Head');
SetBoneScale (0, 2, 'LFARM');
 
// Clear the scalars by doing this. Calling SetBoneScale(0,0), etcetera would probrably
// also work.
SetBoneScale (0);
SetBoneScale (1);
SetBoneScale (2);
 
// Scalars are cumulative if they are in different slots with the same bone name.
// The spine is 6 times normal size in this example.
SetBoneScale (0, 2, 'Spine');
SetBoneScale (1, 3, 'Spine');
 
// Fractional scalars are also possible. Here we negate slots 0 and 1 with a complementary
// scalar.
SetBoneScale(2, 0.15, 'Spine');
SetBoneDirection( name BoneName, rotator BoneTurn, optional vector BoneTrans, optional float Alpha, optional int Space ) (native, final) 
Sets the rotation of a bone, relative to the world origin. (aka absolute)
SetBoneRotation( name BoneName, optional rotator BoneTurn, optional int Space, optional float Alpha ) (simulated, native, final) 
Sets a bone's rotation. The Space parameter specifies the coordinate system to use (0 = local, i.e. bone [default], 1 = global, i.e. world, 2 = refbone). The Alpha parameter (default is 1.0) blends between default rotation and desired rotation. This can be used for crude interpolation, but such use could incur a slight performance penalty if this function is called frequently.
SetBoneLocation( name BoneName, optional vector BoneTrans, optional float Alpha ) (native, final) 
Sets the Location of a bone. BoneName is the name of the bone to be moved. BoneTrans is the relative offset to move the bone's location to (default is <0,0,0>). The Alpha parameter (default is 1.0) blends between default location and desired location.
GetAnimParams( int Channel, out name OutSeqName, out float OutAnimFrame, out float OutAnimRate ) (native, final) 
Retrieves sequence name, frame and rate of the currently active animation for this mesh.
bool AnimIsInGroup( int Channel, name GroupName ) (native, final) 
Determines if the currently running animation of channel Channel (default is 0) is a member of group Group.
name GetClosestBone( vector loc, vector ray, out float boneDist, optional name BiasBone, optional float BiasDistance ) (native, final) 
Finds the bone closest to the line with the origin loc and the direction ray. boneDist returns the distance to the determined bone. Zero scale bones (including bones that have a parent of zero scale) will be excluded from this calculation. BiasDistance can be used to bias the result (default is 0.0). If the distance to the best bone found is smaller than BiasDistance, then the function will return BiasBone instead.

[edit] Related Topics

[edit] Discussion

Foxpaw: I think that this page is a bit more informative than the previous one - many of the functions may need experimenting with to see what the parameters do, as I generally don't mess around with optional parameters unless I know what they do. :P

DoctorEternal How about a tutorial somewhere that shows how to do the type of blending mentioned at the page top?

SettHere's what learned about animation blending, thanks to MrEvil.

I have a car with openning door ani. The problem was that the left and right door ani. were conflicting with each other. The solution was to use the AnimBlendParams()

AnimBlendParams(0, 1.0,,, 'RdoorBone');
AnimBlendParams(1, 1.0,,, 'LdoorBone');// give each bone it's own channel
...
PlayAnim('RdoorOpen',,, 0);
PlayAnim('LdoorOpen',,, 1);//play the ani. with channel param.

Foxpaw: I noticed something interesting today - it appears to be possible to build sounds into the animations. I'm not sure why you'd want to do it, but it appears possible. Check out ONSWeapons-A.ParasiteMine's "SpiderMineFaceTap" animation. This animation plays sound even when previewed in the editor without any UScript interaction.

Purely for curiosities sake, does anyone know how we can create this kind of sound binding to animations?

Petri: Use udn2:AnimNotifies–more specifically, AnimNotify_Sound. You can look at the ones used in the animation in the "Notify" tab in the Animation_Browser.

SuperApe: This looks like it was made well before UT2003 came out. It needs to look more like the other class pages. Marked up functions defs.

EricBlade: I was just reading a bunch of stuff on UDN last night, and it says that the *Root* functions are for a not-implemented "Root Animation" system, and the functions do nothing. Which is correct?

Raven: As far as I can tell these functions return vectors (or rotators) set to be 0.

DaWrecka: While attempting to code a weapon which selects the starting position based on the position of the tip bones in its first person mesh, I've run into an interesting problem. While firing in first-person, the projectiles will start from precisely the location they're meant to. To get this position, I use GetBoneCoords(FireBones[p]).Origin, where FireBones is a static name array of two elements, and p is a counter. Because of this, I can safely say the behaviour is not due to my invoking GetBoneCoords() with invalid bone names, or invoking it incorrectly. However, if I switch to third-person mode, whatever bone offset was received when last in first-person will be kept. In other words, if I fire in first person, switch to third person, turn 90 degrees left and then fire again, the projectiles will originate from a point 90 degrees to my right. If I turn 180 degrees from my starting position, then the projectiles will originate from behind my pawn, and so on. Short of the hacky workaround of forcing the player view into first-person and then back to third after firing, I can't seem to find a way around this. I'm guessing it has to do with the fact that third-person and first-person render different meshes, but I didn't think third-person would make the first-person mesh effectively disappear. Does anyone know of a less-hacky workaround?

Meowcat: Although this is long after the fact, I thought I might add a code sample about how to successfully use RootMotion physics for moving pawns and their collision cylinders. A note about LockRootMotion is that each call to its appears to set a native RootLocation vector to root bone's current world location (and then all GetRootLocation calls after that will return that vector).

// add this to your pawn class
// Also important to note that you may want to override the ClientSetLocation function in the PlayerController 
// (make a custom subclass) so that server/client resets are not forced while performing the move due to 
// location differences.
var vector RootLocation, RootDelta, RootOffset;
var float MaxRootMotionTime; // safety to bump us out of the anim
 
simulated function AnimMoveSetup(name NewAnim){
    SetPhysics(PHYS_RootMotion);    
    AnimAction=NewAnim;// this will get replicated, and the client will check for this to call this function again
    PlayAnim(NewAnim, 1.0);
    RootDelta = GetRootLocationDelta(); // initiate this so that we don't move based on the previous call to GetRootLocationDelta
    RootLocation = GetRootLocation(); // this is collected only for debug display purposes.
    RootOffset = vect(0,0,0); // this is just informational and can be used for final 'placement' of the pawn
    LockRootMotion(1); // this locks the rendering of the root bone to where it is (even though it will still translate for calculation purposes
    MaxRootMotionTime = 3.0;
}
// this needs to be called from the tick function, on all clients as well while the animation is playing
simulated function TickAnimMove(float DT){
    RootDelta = GetRootLocationDelta();
    if(Physics == PHYS_RootMotion){
       MoveSmooth(RootDelta); // NOTE: If collision with the world turned on, this will simply attempt to move the pawn in the direction of root motion, you may want to consider setting bCollideWorld false while doing the move
       RootOffset += RootDelta;
    }
    MaxRootMotionTime -= DT;
    if(MaxRootMotionTime < 0.0) AnimMoveEnd(); // safety timer
    GetBoneCoords(''); // you may also be able to use bForceSkelUpdate but I have not tried that out
}
 
// call this based on a check in either AnimEnd (to see if the animation has ended) or maybe based on a timer
// You may also want to use some traces and a setlocation call to ensure that the pawn can fit in the final 
// location if world collision was disabled
simulated function AnimMoveEnd(){
    SetPhysics(PHYS_Falling); // this could be something else as well    
    AnimAction='';// this will get replicated, and the client will check for this to call this function again
    PlayAnim(IdleRestAnim, 1.0);
    LockRootMotion(0);// allow the root to move again (this also 'sets' the last root location to its final location here)
}

Category:Legacy Class (UT2003)

Category:Legacy Class (UT2004)

Category:Legacy To Do – Make look more like other class pages. Fix hierarchy path at top, include package name.

Personal tools