public EntityHeadController(IAnimationManager animator, EntityAgent entity, Shape entityShape) { this.entity = entity; this.animManager = animator; HeadElement = entityShape.GetElementByName("head"); NeckElement = entityShape.GetElementByName("neck"); HeadGlobalMatrix = Mat4f.Create(); HeadGlobalMatrixInverted = Mat4f.Create(); HeadLocalMatrix = Mat4f.Create(); // Head List <ShapeElement> elems = HeadElement.GetParentPath(); for (int i = 0; i < elems.Count; i++) { ShapeElement elem = elems[i]; float[] localTransform = elem.GetLocalTransformMatrix(); Mat4f.Mul(HeadGlobalMatrix, HeadGlobalMatrix, localTransform); } Mat4f.Mul(HeadGlobalMatrix, HeadGlobalMatrix, HeadElement.GetLocalTransformMatrix()); Mat4f.Invert(HeadGlobalMatrixInverted, HeadGlobalMatrix); }
/// <summary> /// Takes the transform and inverses it. /// </summary> /// <param name="frameModelTransform"></param> /// <returns></returns> public float[] ApplyInverseTransform(float[] frameModelTransform) { List <ShapeElement> elems = Element.GetParentPath(); float[] modelTransform = Mat4f.Create(); for (int i = 0; i < elems.Count; i++) { ShapeElement elem = elems[i]; float[] localTransform = elem.GetLocalTransformMatrix(); Mat4f.Mul(modelTransform, modelTransform, localTransform); } Mat4f.Mul(modelTransform, modelTransform, Element.GetLocalTransformMatrix()); float[] inverseTransformMatrix = Mat4f.Invert(Mat4f.Create(), modelTransform); return(Mat4f.Mul(frameModelTransform, frameModelTransform, inverseTransformMatrix)); }
/// <summary> /// Resolves all joints and loads them. /// </summary> /// <param name="requireJointsForElements"></param> public void ResolveAndLoadJoints(params string[] requireJointsForElements) { if (Animations == null) { return; } Dictionary <string, ShapeElement> elementsByName = new Dictionary <string, ShapeElement>(); CollectElements(Elements, elementsByName); ShapeElement[] allElements = elementsByName.Values.ToArray(); int jointCount = 0; HashSet <string> AnimatedElements = new HashSet <string>(); for (int i = 0; i < Animations.Length; i++) { Animation anim = Animations[i]; for (int j = 0; j < anim.KeyFrames.Length; j++) { AnimationKeyFrame kf = anim.KeyFrames[j]; AnimatedElements.AddRange(kf.Elements.Keys.ToArray()); kf.Resolve(anim, allElements); } } foreach (ShapeElement elem in elementsByName.Values) { elem.JointId = 0; } int maxDepth = 0; foreach (string code in AnimatedElements) { ShapeElement elem; elementsByName.TryGetValue(code, out elem); if (elem == null) { continue; } AnimationJoint joint = new AnimationJoint() { JointId = ++jointCount, Element = elem }; JointsById[joint.JointId] = joint; maxDepth = Math.Max(maxDepth, elem.GetParentPath().Count); } // Currently used to require a joint for the head for head control, but not really used because // the player head also happens to be using in animations so it has a joint anyway foreach (string elemName in requireJointsForElements) { if (!AnimatedElements.Contains(elemName)) { ShapeElement elem = GetElementByName(elemName); if (elem == null) { continue; } AnimationJoint joint = new AnimationJoint() { JointId = ++jointCount, Element = elem }; JointsById[joint.JointId] = joint; maxDepth = Math.Max(maxDepth, elem.GetParentPath().Count); } } // Iteratively and recursively assigns the lowest depth to highest depth joints to all elements // prevents that we overwrite a child joint id with a parent joint id for (int depth = 0; depth <= maxDepth; depth++) { foreach (AnimationJoint joint in JointsById.Values) { if (joint.Element.GetParentPath().Count != depth) { continue; } joint.Element.SetJointId(joint.JointId); } } }