Announcements

Between mid-October and November, the content on AREA will be relocated to the Autodesk Community M&E Hub and the Autodesk Community Gallery. Learn more HERE.

animation problem

animation problem

Anonymous
Not applicable
398 Views
5 Replies
Message 1 of 6

animation problem

Anonymous
Not applicable
Hello. I'm new here and fairly new to Maxscript.

I have been working on an importer script to import 3 different files into max: a mesh file, a bone file, and an animation file.

I've successfully completed the first two (I think) but I have run into problems getting the animation right.


f = getOpenFileName caption: "Import Animation" types: "Animation (*.ani)|*.ani"

ReadANI f &Animation

For BoneID = 1 To Animation.BoneData.names.Count Do
(
obj = getnodebyname Animation.BoneData.names
if obj != undefined Then
(
If Animation.BoneTM == undefined Then
(
tm = Animation.BoneTM

For FrameID = 1 To Animation.FrameCount Do
(
rot = Animation.BoneFrame.Rotation
trans = Animation.BoneFrame.Translation


animate on
(
at time FrameID (obj.pos = trans; obj.rotation = rot)
)
)
)
else
(
if tm != undefined Then obj.transform = tm
)
)
)



as you can see the problem lies within the animate on code block. I have a series of positions and rotations for each bone in each frame. Given that the bones have parents or are a child of parents. The model has a skin modifier with the bones added in. I had to do that manually as I am still working on it.

My question is am I doing something wrong with the animation because it gives weird results. I have a picture to illustrate the problem better

0 Likes
399 Views
5 Replies
Replies (5)
Message 2 of 6

Anonymous
Not applicable
I can't tell precisely what is wrong here unless I see how you are storing your rotation and translation, I only see how you are applying it. From what I can tell it may not work out as easily as you have it written. I've found the best way to store animation is capturing each keyframe for position and rotation individually then storing the transforms for all the keys. However, just storing the world transform may not be sufficient. If I know the bone has a parent and will continue to have a parent I will store an offset matrix of that transform in parent space. This will generally get exactly what I want. Additionally, after all the transforms are set you can go back through and remove the specific translation, rotation, scale keys that may have been created, where you don't want them, as a result of setting the transforms. That requires another step but is really only a cleanup.

Pseudo Code:

fn get_bone_animation bone =
(
-- get each translation keyframe
anim_keys = #()
for i in bone.controller.position.controller.keys do append anim_keys i.time

-- get each rotation keyframe
for i in bone.controller.rotation.controller.keys do appendifunique anim_keys i.time

-- store the bone transform for every frame there is a key
anim_transforms = #()
for i in anim_keys do (
at time i (
if bone.parent == undefined then (
-- world space transform
append anim_transforms bone.transform
) else (
-- parent space transform
append anim_transforms (bone.transform * inverse bone.parent.transform)
)
)
)
return anim_transforms
)

fn set_bone_animation bone transforms =
(
for i in transforms do (
with animate on (
-- you will have to capture your time somewhere probably in your structure
at time (
-- apply transforms
if bone.parent == undefined then (
bone.transform = transforms
) else (
bone.transform = (transforms * bone.parent.transform)
)
)
)
)
)
0 Likes
Message 3 of 6

Anonymous
Not applicable
I will try to incorporate what you said into my script. In the meantime here is the functions for reading and storing the animation file. I want to let everyone know that this format is based on the ASE format but with some differences. People familiar with ASE will spot the similarities.


Function ReadCHR FileName &BoneData &Version =
(
If FileName == Undefined Then Return False
BoneData = ClsBoneData()

Local FileHandle = 0
Local I = 0

FileHandle = FOpen FileName "rbS"

Version = ReadLong FileHandle #Unsigned
If Version < 4 Then
MessageBox "Invalid Version, attempting to continue anyway."

BoneData.ID = ReadLong FileHandle #Unsigned
BoneData.BoneCount = ReadLong FileHandle #Unsigned

CreateArray &BoneData.Names BoneData.BoneCount
CreateArray &BoneData.TM BoneData.BoneCount
CreateArray &BoneData.InverseTM BoneData.BoneCount
CreateArray &BoneData.LocalTM BoneData.BoneCount
CreateArray &BoneData.Parents BoneData.BoneCount

For I = 1 To BoneData.BoneCount Do
(
FSeek FileHandle 4 #Seek_Cur --Bone Name Len
BoneData.Names = ReadString FileHandle
BoneData.TM = ReadMatrix FileHandle
BoneData.InverseTM = ReadMatrix FileHandle
BoneData.LocalTM = ReadMatrix FileHandle
BoneData.Parents = (ReadLong FileHandle #Signed) + 1

If (FindString BoneData.Names "L ForeArm") != Undefined Then BoneData.LeftArmIndex = I
Else If (FindString BoneData.Names "R ForeArm") != Undefined Then BoneData.RightArmIndex = I
Else If (FindString BoneData.Names "L Hand") != Undefined Then BoneData.LeftHandIndex = I
Else If (FindString BoneData.Names "R Hand") != Undefined Then BoneData.RightHandIndex = I
)

BoneData.SendVS = ReadLong FileHandle #Unsigned

BoneData.LocalRH = ReadMatrix FileHandle
BoneData.LocalShield = ReadMatrix FileHandle
BoneData.LocalKnuckle = ReadMatrix FileHandle

If Version == 5 Then
(
CreateArray &BoneData.Events 4
CreateArray &BoneData.EventParents 4
For I = 1 To 4 Do BoneData.Events = ReadVector3 FileHandle
For I = 1 To 4 Do BoneData.EventParents = ((ReadLong FileHandle #Signed) + 1)
)
If Version >= 6 Then
(
CreateArray &BoneData.Events 8
CreateArray &BoneData.EventParents 8
For I = 1 To 8 Do BoneData.Events = ReadVector3 FileHandle
For I = 1 To 8 Do BoneData.EventParents = ((ReadLong FileHandle #Signed) + 1)
)
If Version == 7 Then
(
BoneData.LocalLH = ReadMatrix FileHandle
)
FClose FileHandle
)

Function ReadANI FileName &ANI =
(
If FileName == Undefined Then Return False
Ani = ClsAnimationData()

Local FileHandle = 0
Local Version = 0
Local FrameCount = 0
Local BoneCount = 0
Local PathPresent = 0
Local EventCount = 0
Local I = 0

ANI.Name = GetFilenameFile FileName

FileHandle = FOpen FileName "rbS"

Version = ReadLong FileHandle #Unsigned
If Version != 10 Then
MessageBox "Invalid Version, attempting to continue anyway."

ANI.ID = ReadLong FileHandle #Unsigned
ANI.PerSLERP = ReadFloat FileHandle
FSeek FileHandle 32 #Seek_Cur
BoneCount = ReadLong FileHandle #Unsigned
FrameCount = ReadLong FileHandle #Unsigned
ANI.FrameCount = FrameCount
PathPresent = ReadLong FileHandle #Unsigned
If PathPresent != 0 Then FSeek FileHandle (12 * FrameCount) #Seek_Cur
ReadTM FileHandle &ANI BoneCount FrameCount
CreateArray &ANI.Attribs FrameCount
For I = 1 To FrameCount Do
(
ANI.Attribs = ClsAttributes()
ANI.Attribs.Flags = ReadLong FileHandle #Unsigned
ANI.Attribs.SoundID = ReadLong FileHandle #Unsigned
ANI.Attribs.Frame = ReadFloat FileHandle
)
EventCount = ReadLong FileHandle #Unsigned
If EventCount != 0 Then
(
CreateArray &ANI.Events EventCount
For I = 1 To EventCount Do ANI.Events = ReadVector3 FileHandle
)
)

Function ReadTM FileHandle &AnimationData TotalBones TotalFrames =
(
Local NameLength = 0
Local PoolSize = 0
Local AnimationPresent = 0
Local I = 0
Local J = 0

AnimationData.BoneData = ClsBoneData()
AnimationData.FrameCount = TotalFrames
AnimationData.BoneData.BoneCount = TotalBones
CreateArray &AnimationData.BoneData.Names TotalBones
CreateArray &AnimationData.BoneData.TM TotalBones
CreateArray &AnimationData.BoneData.InverseTM TotalBones
CreateArray &AnimationData.BoneData.LocalTM TotalBones
CreateArray &AnimationData.BoneData.Parents TotalBones
For I = 1 To TotalBones Do
(
FSeek FileHandle 4 #Seek_Cur
AnimationData.BoneData.Names = ReadString FileHandle
AnimationData.BoneData.InverseTM = ReadMatrix FileHandle
AnimationData.BoneData.LocalTM = ReadMatrix FileHandle
AnimationData.BoneData.Parents = ((ReadLong FileHandle #Signed) + 1)
--Generate TM matrix to fill out the whole structure
AnimationData.BoneData.TM = Inverse AnimationData.BoneData.InverseTM
)

FSeek FileHandle 4 #Seek_Cur --Skip PoolSize
CreateArray &AnimationData.BoneTM TotalBones
CreateArray &AnimationData.BoneFrame TotalBones
For I = 1 To TotalBones Do
(
AnimationPresent = ReadLong FileHandle #Unsigned
If AnimationPresent != 1 Then
(
AnimationData.BoneTM = ReadMatrix FileHandle
)
Else
(
CreateArray &AnimationData.BoneFrame TotalFrames
For J = 1 To TotalFrames Do
(
AnimationData.BoneFrame = ClsFrame()
AnimationData.BoneFrame.Rotation = ReadQuaternion FileHandle
AnimationData.BoneFrame.Translation = ReadVector3 FileHandle
)
)
)
)

Function ReadTMAni FileHandle &GeometryObject FrameCount =
(
Local FramePresent = ReadLong FileHandle #Unsigned
Local I = 0
If FramePresent != 0 Then
(
CreateArray &GeometryObject.StaticFrames FrameCount
For I = 1 To FrameCount Do
(
GeometryObject.StaticFrames = ClsFrame()
GeometryObject.StaticFrames.Rotation = ReadQuaternion FileHandle
GeometryObject.StaticFrames.Translation = ReadVector3 FileHandle
)
)
)
0 Likes
Message 4 of 6

Anonymous
Not applicable
still no luck getting animation to work. would love to see if anyone has a solution to this problem.
0 Likes
Message 5 of 6

paulneale
Advisor
Advisor
With it all left justified it is very hard to read it. I'm still not 100% clear on what the issues you are see are? You say the rotations are not correct? What space are they being stored and applied in?
Paul Neale

http://paulneale.com


Paul Neale




EESignature

0 Likes
Message 6 of 6

Anonymous
Not applicable
Each bone has 3 matrices: TM, InverseTM, and LocalTM. My guess is they already calculated the Inverse Trans Matrix instead of doing the work by hand.

Each animation frame checks if there is a Bone Transform for each bone. If there isn't one, the it uses the Rotation quat and Translation stored therein.

My problem is that I do not know how to rotate and translate each bone. I don't know if its local space or parent space. I do know that a bone that has a parent bone is rotated in parent space but that really all I know.

I've tried a lot of things and this is pretty close but some bones are behaving wildly.


For BoneID = 1 To Animation.BoneData.names.Count Do (
obj = getnodebyname Animation.BoneData.names
if obj != undefined Then
(
if Animation.BoneTM == undefined Then
(
For FrameID = 1 To Animation.FrameCount Do (
Frame = Animation.BoneFrame
if Frame == undefined Then ( return 0 ) else
(
CurFrame = Frame
--curBoneFrame = Animation.BoneFrame
if (FrameID + 1) >= Animation.FrameCount Then ( nextBoneFrame = Animation.BoneFrame ) else ( nextBoneFrame = Animation.BoneFrame)

-- Get QuatSlerp
quatSlerp = slerp CurFrame.Rotation nextBoneFrame.Rotation Animation.PerSLERP
-- GetVecLerp
vecLerp = lerp CurFrame.Translation nextBoneFrame.Translation 1
-- Make new Rotation Matrix
mQ = quatSlerp as matrix3
-- Make new Translation

local mTemp = mQ
mTemp.row4 = vecLerp

format "Frame:% MatTemp:%\n" FrameID mTemp

if FrameID == Animation.FrameCount Then FrameID = Animation.FrameCount else FrameID += 1

if obj.parent != 0 Then (

with animate on (
at time FrameID
(
in coordsys parent obj.rotation = mQ;
in coordsys parent obj.pos = vecLerp
)
)
) else (
with animate on (
at time FrameID
(
in coordsys local obj.rotation.x_rotation = mQ;
in coordsys local obj.pos = vecLerp
)
)
)
)
)
)
)
)
0 Likes