void FAnimationRuntime::BlendPosesTogetherPerBone(const TArray<FCompactPose>& SourcePoses, const TArray<FBlendedCurve>& SourceCurves, const UBlendSpaceBase* BlendSpace, const TArray<FBlendSampleData>& BlendSampleDataCache, /*out*/ FCompactPose& ResultPose, /*out*/ FBlendedCurve& ResultCurve) { check(SourcePoses.Num() > 0); const TArray<FBoneIndexType> & RequiredBoneIndices = ResultPose.GetBoneContainer().GetBoneIndicesArray(); TArray<int32> PerBoneIndices; PerBoneIndices.AddUninitialized(ResultPose.GetNumBones()); for (int32 BoneIndex = 0; BoneIndex < PerBoneIndices.Num(); ++BoneIndex) { PerBoneIndices[BoneIndex] = BlendSpace->GetPerBoneInterpolationIndex(RequiredBoneIndices[BoneIndex], ResultPose.GetBoneContainer()); } BlendPosePerBone<ETransformBlendMode::Overwrite>(PerBoneIndices, BlendSampleDataCache[0], ResultPose, SourcePoses[0]); for (int32 i = 1; i < SourcePoses.Num(); ++i) { BlendPosePerBone<ETransformBlendMode::Accumulate>(PerBoneIndices, BlendSampleDataCache[i], ResultPose, SourcePoses[i]); } // Ensure that all of the resulting rotations are normalized ResultPose.NormalizeRotations(); if (SourceCurves.Num() > 0) { TArray<float> SourceWeights; SourceWeights.AddUninitialized(BlendSampleDataCache.Num()); for (int32 CacheIndex=0; CacheIndex<BlendSampleDataCache.Num(); ++CacheIndex) { SourceWeights[CacheIndex] = BlendSampleDataCache[CacheIndex].TotalWeight; } BlendCurves(SourceCurves, SourceWeights, ResultCurve); } }
void FAnimationRuntime::ConvertMeshRotationPoseToLocalSpace(FCompactPose& Pose) { // Convert all rotations to mesh space // only the root bone doesn't have a parent. So skip it to save a branch in the iteration. for (FCompactPoseBoneIndex BoneIndex(Pose.GetNumBones()-1); BoneIndex > 0; --BoneIndex) { const FCompactPoseBoneIndex ParentIndex = Pose.GetParentBoneIndex(BoneIndex); FQuat LocalSpaceRotation = Pose[ParentIndex].GetRotation().Inverse() * Pose[BoneIndex].GetRotation(); Pose[BoneIndex].SetRotation(LocalSpaceRotation); } }
void FAnimationRuntime::ConvertPoseToMeshRotation(FCompactPose& LocalPose) { // Convert all rotations to mesh space // only the root bone doesn't have a parent. So skip it to save a branch in the iteration. for (FCompactPoseBoneIndex BoneIndex(1); BoneIndex < LocalPose.GetNumBones(); ++BoneIndex) { const FCompactPoseBoneIndex ParentIndex = LocalPose.GetParentBoneIndex(BoneIndex); const FQuat MeshSpaceRotation = LocalPose[ParentIndex].GetRotation() * LocalPose[BoneIndex].GetRotation(); LocalPose[BoneIndex].SetRotation(MeshSpaceRotation); } }
void FAnimationRuntime::BlendLocalPosesPerBoneWeights( FCompactPose& BasePose, const TArray<FCompactPose>& BlendPoses, struct FBlendedCurve& BaseCurve, const TArray<struct FBlendedCurve>& BlendedCurves, const TArray<FPerBoneBlendWeight> & BoneBlendWeights, ECurveBlendOption::Type CurveBlendOption, /*out*/ FCompactPose& OutPose, /*out*/ struct FBlendedCurve& OutCurve) { check(BasePose.GetNumBones() == BoneBlendWeights.Num()); int32 PoseNum = BlendPoses.Num(); TArray<float> MaxPoseWeights; MaxPoseWeights.AddZeroed(PoseNum); for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) { const int32 PoseIndex = BoneBlendWeights[BoneIndex.GetInt()].SourceIndex; const FTransform& BaseAtom = BasePose[BoneIndex]; const float BlendWeight = FMath::Clamp(BoneBlendWeights[BoneIndex.GetInt()].BlendWeight, 0.f, 1.f); MaxPoseWeights[PoseIndex] = FMath::Max(MaxPoseWeights[PoseIndex], BlendWeight); if (BlendWeight < ZERO_ANIMWEIGHT_THRESH) { OutPose[BoneIndex] = BaseAtom; } else if ((1.0 - BlendWeight) < ZERO_ANIMWEIGHT_THRESH) { OutPose[BoneIndex] = BlendPoses[PoseIndex][BoneIndex]; } else // we want blend here { FTransform BlendAtom = BaseAtom; const FTransform& TargetAtom = BlendPoses[PoseIndex][BoneIndex]; BlendAtom.BlendWith(TargetAtom, BlendWeight); OutPose[BoneIndex] = BlendAtom; } } // time to blend curves // the way we blend curve per bone // is to find out max weight per that pose, and then apply that weight to the curve { TArray<const FBlendedCurve*> SourceCurves; TArray<float> SourceWegihts; SourceCurves.SetNumUninitialized(PoseNum+1); SourceWegihts.SetNumUninitialized(PoseNum+1); SourceCurves[0] = &BaseCurve; SourceWegihts[0] = 1.f; for (int32 Idx=0; Idx<PoseNum; ++Idx) { SourceCurves[Idx+1] = &BlendedCurves[Idx]; SourceWegihts[Idx+1] = MaxPoseWeights[Idx]; } BlendCurves(SourceCurves, SourceWegihts, OutCurve, CurveBlendOption); } }