Translated SkeletalAnimation demo (current)

Roszcz

01-05-2007 14:47:02

Hello.
I'm new to (M)Ogre, and as a part of learing it I've decided to translate the current SkeletalAnimation demo (using jaiqua mesh). It turned out to be rather quick and easy task, and below is the result:

SkeletalNew.cs

using System;
using System.Collections.Generic;
using Mogre;

namespace Mogre.Demo.SkeletalAnimationNew
{
class SkeletalNew : Demo.ExampleApplication.Example
{
const uint NUM_JAIQUAS = 6;

AnimationState[] mAnimState = new AnimationState[NUM_JAIQUAS];
float[] mAnimationSpeed = new float[NUM_JAIQUAS];
Vector3 mSneakStartOffset;
Vector3 mSneakEndOffset;

Quaternion[] mOrientations = new Quaternion[NUM_JAIQUAS];
Vector3[] mBasePositions = new Vector3[NUM_JAIQUAS];
SceneNode[] mSceneNode = new SceneNode[NUM_JAIQUAS];
Degree mAnimationRotation = -60;
const float mAnimChop = 7.96666f;
const float mAnimChopBlend = 0.3f;

public override void CreateFrameListener()
{
base.CreateFrameListener();
Root.Singleton.FrameStarted += FrameStarted;
}

bool FrameStarted(FrameEvent evt)
{
for (int i = 0; i < NUM_JAIQUAS; ++i)
{
float inc = evt.timeSinceLastFrame * mAnimationSpeed[i];
if ((mAnimState[i].TimePosition + inc) >= mAnimChop)
{
// Loop
// Need to reposition the scene node origin since animation includes translation
// Calculate as an offset to the end position, rotated by the
// amount the animation turns the character
Quaternion rot = new Quaternion(mAnimationRotation, Vector3.UNIT_Y);
Vector3 startoffset = mSceneNode[i].Orientation * -mSneakStartOffset;
Vector3 endoffset = mSneakEndOffset;
Vector3 offset = rot * startoffset;
Vector3 currEnd = mSceneNode[i].Orientation * endoffset + mSceneNode[i].Position;
mSceneNode[i].Position = currEnd + offset;
mSceneNode[i].Rotate(rot);

mAnimState[i].TimePosition = (mAnimState[i].TimePosition + inc) - mAnimChop;
}
else
{
mAnimState[i].AddTime(inc);
}
}
return true;
}

// Scene creation
public override void CreateScene()
{
sceneMgr.ShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_MODULATIVE;
sceneMgr.SetShadowTextureSize(512);
sceneMgr.ShadowColour = new ColourValue(0.6f, 0.6f, 0.6f);

// Setup animation default
Animation.DefaultInterpolationMode = Animation.InterpolationMode.IM_LINEAR;
Animation.DefaultRotationInterpolationMode = Animation.RotationInterpolationMode.RIM_LINEAR;

// Set ambient light
sceneMgr.AmbientLight = new ColourValue(0.5f, 0.5f, 0.5f);

// The jaiqua sneak animation doesn't loop properly, so lets hack it so it does
// We want to copy the initial keyframes of all bones, but alter the Spineroot
// to give it an offset of where the animation ends
SkeletonPtr skel = SkeletonManager.Singleton.Load("jaiqua.skeleton", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
Animation anim = skel.GetAnimation("Sneak");
Animation.NodeTrackIterator trackIter = anim.GetNodeTrackIterator();
while (trackIter.MoveNext())
{
NodeAnimationTrack track = trackIter.Current;

TransformKeyFrame oldKf = new TransformKeyFrame(null, 0f);
track.GetInterpolatedKeyFrame(new TimeIndex(mAnimChop), oldKf);

// Drop all keyframes after the chop
while (track.GetKeyFrame((ushort)(track.NumKeyFrames-1)).Time >= mAnimChop - mAnimChopBlend)
track.RemoveKeyFrame((ushort)(track.NumKeyFrames-1));

TransformKeyFrame newKf = track.CreateNodeKeyFrame(mAnimChop);
TransformKeyFrame startKf = track.GetNodeKeyFrame(0);

Bone bone = skel.GetBone(track.Handle);
if (bone.Name == "Spineroot")
{
mSneakStartOffset = startKf.Translate + bone.InitialPosition;
mSneakEndOffset = oldKf.Translate + bone.InitialPosition;
mSneakStartOffset.y = mSneakEndOffset.y;
// Adjust spine root relative to new location
newKf.Rotation = oldKf.Rotation;
newKf.Translate = oldKf.Translate;
newKf.Scale = oldKf.Scale;
}
else
{
newKf.Rotation = startKf.Rotation;
newKf.Translate = startKf.Translate;
newKf.Scale = startKf.Scale;
}
}

Entity ent = null;
float rotInc = Math.TWO_PI / (float)NUM_JAIQUAS;
float rot = 0.0f;

for (int i = 0; i < NUM_JAIQUAS; ++i)
{
Quaternion q = new Quaternion();
q.FromAngleAxis( new Radian(rot), Vector3.UNIT_Y);

mOrientations[i] = q;
mBasePositions[i] = q * new Vector3(0,0,-20);

ent = sceneMgr.CreateEntity("jaiqua" + i.ToString(), "jaiqua.mesh");
// Add entity to the scene node
mSceneNode[i] = sceneMgr.RootSceneNode.CreateChildSceneNode();
mSceneNode[i].AttachObject(ent);
mSceneNode[i].Rotate(q);
mSceneNode[i].Translate(mBasePositions[i]);

mAnimState[i] = ent.GetAnimationState("Sneak");
mAnimState[i].Enabled = true;
mAnimState[i].Loop = false; // manual loop since translation involved
mAnimationSpeed[i] = Math.RangeRandom(0.5f, 1.5f);

rot += rotInc;
}

// Give it a little ambience with lights
Light l = sceneMgr.CreateLight("BlueLight");
l.Type = Light.LightTypes.LT_SPOTLIGHT;
l.SetPosition(-200f,150f,-100f);
l.Direction = -l.Position.NormalisedCopy;
l.SetDiffuseColour(0.5f, 0.5f, 1.0f);

l = sceneMgr.CreateLight("GreenLight");
l.Type = Light.LightTypes.LT_SPOTLIGHT;
l.SetPosition(0f,150f,-100f);
l.Direction = -l.Position.NormalisedCopy;
l.SetDiffuseColour(0.5f, 1.0f, 0.5f);

// Position the camera
camera.SetPosition(100,20,0);
camera.LookAt(0,10,0);

// Report whether hardware skinning is enabled or not
Technique t = ent.GetSubEntity(0).GetMaterial().GetBestTechnique();
Pass p = t.GetPass(0);
if (p.HasVertexProgram && p.GetVertexProgram().IsSkeletalAnimationIncluded)
mDebugText = "Hardware skinning is enabled";
else
mDebugText = "Software skinning is enabled";

Plane plane;
plane.normal = Vector3.UNIT_Y;
plane.d = 100;
MeshManager.Singleton.CreatePlane("Myplane",ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, plane,1500,1500,20,20,true,1,60,60,Vector3.UNIT_Z);
Entity pPlaneEnt = sceneMgr.CreateEntity( "plane", "Myplane" );
pPlaneEnt.SetMaterialName("Examples/Rockwall");
pPlaneEnt.CastShadows = false;
sceneMgr.RootSceneNode.CreateChildSceneNode(new Vector3(0,99,0)).AttachObject(pPlaneEnt);
}

}
}


Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using Mogre;

namespace Mogre.Demo.SkeletalAnimationNew
{
class Program
{
static void Main(string[] args)
{
try
{
SkeletalNew app = new SkeletalNew();
app.Go();
}
catch (System.Runtime.InteropServices.SEHException)
{
// Check if it's an Ogre Exception
if (OgreException.IsThrown)
ExampleApplication.Example.ShowOgreException();
else
throw;
}
}
}
}

Blackbeard

01-05-2007 17:15:07

Cool, as more translations as better.