Experimental bone animations playing from YCD. Windmills, fans, radars, ufos etc

This commit is contained in:
dexy 2019-11-02 18:14:36 +11:00
parent 80b6f3742b
commit 6f0a7d99f9
4 changed files with 131 additions and 8 deletions

View File

@ -697,7 +697,9 @@ namespace CodeWalker.GameFiles
public override float EvaluateFloat(int frame)
{
return Values[frame];
if (frame < Values?.Length) return Values[frame];
if (Values?.Length > 0) return Values[0];
return 0.0f;
}
public override void Read(Sequence blockStream, ref int channelOffset)
@ -769,7 +771,7 @@ namespace CodeWalker.GameFiles
for (int n = 0; n < 4; n++)
{
if ((c + n) >= 4) break;
v[c + n] = sv3c.Value[n];
v[c + n] = ssqc.Value[n];
}
c += 4;
}

View File

@ -550,6 +550,10 @@ namespace CodeWalker.GameFiles
private ResourceSystemStructBlock<ushort> Unknown_40h_DataBlock = null;
public Dictionary<ushort, Bone> BonesMap { get; set; }//for convienience finding bones by tag
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
@ -611,6 +615,16 @@ namespace CodeWalker.GameFiles
}
}
BonesMap = new Dictionary<ushort, Bone>();
if (Bones != null)
{
for (int i = 0; i < Bones.Count; i++)
{
var bone = Bones[i];
BonesMap[bone.Id] = bone;
}
}
}
/// <summary>
@ -784,6 +798,13 @@ namespace CodeWalker.GameFiles
private string_r NameBlock = null;
//used by CW for animating skeletons.
public Quaternion AnimRotation;
public Vector3 AnimTranslation;
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
@ -819,6 +840,10 @@ namespace CodeWalker.GameFiles
this.Name = reader.ReadStringAt(//BlockAt<string_r>(
this.NamePointer // offset
);
AnimRotation = Rotation;
AnimTranslation = Translation;
}
/// <summary>

View File

@ -78,6 +78,7 @@ namespace CodeWalker.Rendering
public ClipMapEntry ClipMapEntryUV0;
public ClipMapEntry ClipMapEntryUV1;
public Dictionary<ushort, RenderableModel> ModelBoneLinks;
public override void Init(DrawableBase drawable)
@ -254,6 +255,17 @@ namespace CodeWalker.Rendering
Matrix trans = (boneidx < modeltransforms.Length) ? modeltransforms[boneidx] : Matrix.Identity;
Bone bone = (hasbones && (boneidx < bones.Count)) ? bones[boneidx] : null;
if (mi < HDModels.Length) //populate bone links map for hd models
{
if (bone != null)
{
if (ModelBoneLinks == null) ModelBoneLinks = new Dictionary<ushort, RenderableModel>();
ModelBoneLinks[bone.Id] = model;
}
}
if ((fragtransforms != null))// && (fragtransformid < fragtransforms.Length))
{
if (fragtransformid < fragtransforms.Length)
@ -364,8 +376,92 @@ namespace CodeWalker.Rendering
var anim = clipanim?.Animation;
if (anim == null)
{ return; }
if (anim.BoneIds?.data_items == null)
{ return; }
if (anim.Sequences?.data_items == null)
{ return; }
bool interpolate = true; //how to know? eg. cs4_14_hickbar_anim shouldn't
bool ignoreLastFrame = true;//if last frame is equivalent to the first one, eg rollercoaster small light "globes" don't
var duration = anim.Duration;
var frames = anim.Frames;
var nframes = (ignoreLastFrame) ? (frames - 1) : frames;
var curPos = ((CurrentAnimTime % duration) / duration) * nframes;
var frame0 = ((ushort)curPos) % frames;
var frame1 = (frame0 + 1) % frames;
var falpha = (float)(curPos - Math.Floor(curPos));
var ialpha = 1.0f - falpha;
var dwbl = this.Key;
var skel = dwbl?.Skeleton;
var bones = skel?.Bones;
if (bones == null)
{ return; }
for (int i = 0; i < anim.BoneIds.data_items.Length; i++)
{
var boneiditem = anim.BoneIds.data_items[i];
var track = boneiditem.Track;
Bone bone = null;
skel?.BonesMap?.TryGetValue(boneiditem.BoneId, out bone);
if (bone == null)
{ continue; }
for (int s = 0; s < anim.Sequences.data_items.Length; s++)
{
var seq = anim.Sequences.data_items[s];
var aseq = seq.Sequences[i];
switch (track)
{
case 0: //bone position
var v0 = aseq.EvaluateVector(frame0);
var v1 = aseq.EvaluateVector(frame1);
var v = interpolate ? (v0 * ialpha) + (v1 * falpha) : v0;
bone.AnimTranslation = v.XYZ();
break;
case 1: //bone orientation
var q0 = new Quaternion(aseq.EvaluateVector(frame0));
var q1 = new Quaternion(aseq.EvaluateVector(frame1));
var q = interpolate ? Quaternion.Slerp(q0, q1, falpha) : q0;
bone.AnimRotation = q;
break;
default:
break;
}
}
}
for (int i = 0; i < bones.Count; i++)
{
var bone = bones[i];
RenderableModel bmodel = null;
ModelBoneLinks?.TryGetValue(bone.Id, out bmodel);
if (bmodel == null)
{ continue; }
//update model's transform from animated bone
var pos = bone.AnimTranslation;
var ori = bone.AnimRotation;
var pbone = bone.Parent;
while (pbone != null)
{
pos = pbone.AnimRotation.Multiply(pos) + pbone.AnimTranslation;
ori = pbone.AnimRotation * ori;
pbone = pbone.Parent;
}
bmodel.Transform = Matrix.AffineTransformation(1.0f, ori, pos);
}
//TODO........
}
private void UpdateAnimUV(ClipMapEntry cme)
{
@ -384,11 +480,11 @@ namespace CodeWalker.Rendering
{ return; }
bool interpolate = true; //how to know? eg. cs4_14_hickbar_anim shouldn't
bool lastFrameSameAsFirst = true;//if last frame is equivalent to the first one, eg rollercoaster small light "globes" don't
bool ignoreLastFrame = true;//if last frame is equivalent to the first one, eg rollercoaster small light "globes" don't
var duration = anim.Duration;
var frames = anim.Frames;
var nframes = (lastFrameSameAsFirst) ? (frames - 1) : frames;
var nframes = (ignoreLastFrame) ? (frames - 1) : frames;
var curPos = ((CurrentAnimTime % duration) / duration) * nframes;
var frame0 = ((ushort)curPos) % frames;

View File

@ -1141,11 +1141,11 @@ namespace CodeWalker.Rendering
//draw line from bone's position to parent position...
Vector3 lbeg = Vector3.Zero;
Vector3 lend = bone.Translation;// bone.Rotation.Multiply();
Vector3 lend = bone.AnimTranslation;// bone.Rotation.Multiply();
while (pbone != null)
{
lbeg = pbone.Rotation.Multiply(lbeg) + pbone.Translation;
lend = pbone.Rotation.Multiply(lend) + pbone.Translation;
lbeg = pbone.AnimRotation.Multiply(lbeg) + pbone.AnimTranslation;
lend = pbone.AnimRotation.Multiply(lend) + pbone.AnimTranslation;
pbone = pbone.Parent;
}