/// <summary> /// Tries to get the local transform and blend weight of the specified bone. /// </summary> public bool TryGetBoneTransform(int bone, out Matrix transform, out float blendWeight) { blendWeight = 1; if (bone >= AnimationClip.Transforms.Length || AnimationClip.Transforms[bone] == null) { transform = Matrix.Identity; return(false); } if (InterpolationEnabled && shouldLerp) { transform = LerpHelper.Slerp( AnimationClip.Transforms[bone][startFrame], AnimationClip.Transforms[bone][endFrame], percentage); } else { transform = AnimationClip.Transforms[bone][startFrame]; } return(true); }
/// <summary> /// Updates the bone transforms. /// </summary> private void UpdateBoneTransforms(float elapsedTime) { // Update default blend float blendLerp = 0; if (BlendEnabled) { blendTimer += elapsedTime; blendLerp = (float)(blendTimer / BlendDuration.TotalSeconds); } // Update controller transforms Array.Clear(weightedBones, 0, weightedBones.Length); for (int controllerIndex = 0; controllerIndex < Controllers.Count; controllerIndex++) { for (int bone = 0; bone < Skeleton.BoneTransforms.Length; bone++) { int index = controllerIndex * numBones + bone; if (Controllers[controllerIndex].Controller.TryGetBoneTransform( bone, out weightedBones[index].Transform, out weightedBones[index].BlendWeight)) { weightedBones[index].BlendWeight *= Controllers[controllerIndex].BlendWeight * ( Controllers[controllerIndex].BoneWeights[bone].Enabled ? Controllers[controllerIndex].BoneWeights[bone].BlendWeight : 0); } else { weightedBones[index].BlendWeight = 0; } } } // Normalize weights for (int bone = 0; bone < Skeleton.BoneTransforms.Length; bone++) { int firstNonZeroChannel = -1; float totalWeight = 0; for (int controllerIndex = 0; controllerIndex < Controllers.Count; controllerIndex++) { int index = controllerIndex * numBones + bone; if (firstNonZeroChannel < 0 && weightedBones[index].BlendWeight > 0) { firstNonZeroChannel = controllerIndex; } totalWeight += weightedBones[index].BlendWeight; } if (totalWeight <= 0) { continue; } Matrix transform = weightedBones[firstNonZeroChannel * numBones + bone].Transform; for (int controllerIndex = firstNonZeroChannel + 1; controllerIndex < Controllers.Count; controllerIndex++) { int index = controllerIndex * numBones + bone; if (weightedBones[index].BlendWeight <= float.Epsilon) { continue; } // This is not mathmatically correct, but produces an acceptable result. transform = LerpHelper.Slerp(transform, weightedBones[index].Transform, weightedBones[index].BlendWeight / totalWeight); } // Perform default blend if (BlendEnabled && blendTarget != null && blendLerp <= 1) { transform = LerpHelper.Slerp(blendTarget[bone], transform, MathHelper.SmoothStep(0, 1, blendLerp)); } Skeleton.BoneTransforms[bone] = transform; } }
private BoneAnimationClip ConvertAnimationClip(AnimationClip animation) { BoneAnimationClip boneAnimation = new BoneAnimationClip(); boneAnimation.FramesPerSecond = FramesPerSecond; boneAnimation.TotalFrames = (int)Math.Round(animation.Duration.TotalSeconds * FramesPerSecond); int maxBones = 0; Dictionary <int, List <Keyframe> > keyframes = new Dictionary <int, List <Keyframe> >(); foreach (Keyframe keyframe in animation.Keyframes) { if (keyframe.Bone > maxBones) { maxBones = keyframe.Bone; } if (!keyframes.ContainsKey(keyframe.Bone)) { keyframes.Add(keyframe.Bone, new List <Keyframe>()); } keyframes[keyframe.Bone].Add(keyframe); } boneAnimation.Transforms = new Matrix[maxBones + 1][]; for (int i = 0; i <= maxBones; ++i) { if (keyframes.ContainsKey(i)) { boneAnimation.Transforms[i] = new Matrix[boneAnimation.TotalFrames]; } } TimeSpan time = TimeSpan.Zero; TimeSpan step = TimeSpan.FromSeconds(1.0 / FramesPerSecond); for (int frame = 0; frame < boneAnimation.TotalFrames; frame++) { foreach (int bone in keyframes.Keys) { List <Keyframe> channel = keyframes[bone]; Matrix transform = Matrix.Identity; if (time <= channel[0].Time) { transform = channel[0].Transform; } else if (time >= channel[channel.Count - 1].Time) { transform = channel[channel.Count - 1].Transform; } else { int k = 0; while (channel[k].Time < time) { k++; } double lerp = (channel[k].Time - time).TotalSeconds / (channel[k].Time - channel[k - 1].Time).TotalSeconds; transform = LerpHelper.Slerp( channel[k].Transform, channel[k - 1].Transform, (float)lerp); } boneAnimation.Transforms[bone][frame] = transform; } time += step; } FigureOutPreferredEnding(boneAnimation); return(boneAnimation); }
private void UpdateBoneTransforms(GameClock gameclock) { // update controller transforms Array.Clear(_weightedBones, 0, _weightedBones.Length); int numBones = _skeleton.BoneTransforms.Length; for (int i = 0; i < _controllers.Count; i++) { for (int b = 0; b < numBones; b++) { int index = i * numBones + b; if (_controllers[i].Controller.TryGetGoneTransforms(b, out _weightedBones[index].Transform, out _weightedBones[index].BlendWeight)) { _weightedBones[index].BlendWeight *= _controllers[i].BlendWeight * (_controllers[i].BoneWeights[b].Enabled ? _controllers[i].BoneWeights[b].BlendWeight : 0); } else { _weightedBones[index].BlendWeight = 0; } } } // Normalize weights for (int bone = 0; bone < numBones; bone++) { int firstNonZeroChannel = -1; float totalWeight = 0; for (int i = 0; i < _controllers.Count; i++) { int index = i * numBones + bone; if (firstNonZeroChannel < 0 && _weightedBones[index].BlendWeight > 0) { firstNonZeroChannel = i; } totalWeight += _weightedBones[i].BlendWeight; } if (totalWeight <= 0) { continue; } // ToDo: Modify to use seperate translation, rotation and scale. Matrix4 transform = _weightedBones[firstNonZeroChannel * numBones + bone].Transform; for (int i = 0; i < _controllers.Count; i++) { int index = i * numBones + bone; if (_weightedBones[index].BlendWeight <= float.Epsilon) { continue; } // this is not matmatically correct, but produces an acceptable result. transform = LerpHelper.Slerp(transform, _weightedBones[index].Transform, _weightedBones[index].BlendWeight / totalWeight); } _skeleton.BoneTransforms[bone] = transform; } }