• UE4 Animation]IK Related


    转自:https://dawnarc.com/2018/05/ue4animationik-related/

    Examples

    工程1

    在油管上看到一个UE4 IK动画的demo工程示例

    该示例作者的主页:https://www.patreon.com/unrealcg

    演示视频:Advanced foot IK for Unreal Engine 4 - (100% Free)
    https://www.youtube.com/watch?v=XetC9ivIXFc

    demo工程下载地址(4.19):
    https://pan.baidu.com/s/1mlcM0cseKWpprnISVM0P5Q

    工程2

    该工程除了IK,还包括动画融合、物理等功能

    演示视频:UE4 - Advanced Locomotion System V3 - Features
    https://www.youtube.com/watch?v=yTniZCOCY7o

    下载地址:Unreal商城,60刀
    Advanced Locomotion System V3
    https://www.unrealengine.com/marketplace/advanced-locomotion-system-v1

    IK AnimNode

    FABRIK (Forward And Backward Reaching Inverse Kinematics)

    FABRIK
    https://docs.unrealengine.com/en-us/Engine/Animation/NodeReference/Fabrik

    Adding of a rifle and fabrik node to fix left hand
    https://www.youtube.com/watch?v=49MJWjlSHcw

    Look At

    Look At
    https://docs.unrealengine.com/en-us/Engine/Animation/NodeReference/SkeletalControls/LookAt

    CCDIK (Cyclic Coordinate Descent Inverse Kinematics)

    CCDIK
    https://docs.unrealengine.com/en-us/Engine/Animation/NodeReference/SkeletalControls/CCDIK

    Hand IK Retargeting

    Hand IK Retargeting
    https://docs.unrealengine.com/en-us/Engine/Animation/NodeReference/SkeletalControls/HandIKRetargeting

    Two Bone IK

    Two Bone IK
    https://docs.unrealengine.com/en-us/Engine/Animation/NodeReference/SkeletalControls/TwoBoneIK

    Spline IK

    Spline IK
    https://docs.unrealengine.com/en-us/Engine/Animation/NodeReference/SkeletalControls/SplineIK

    IK Engine Source

    CCDIK

    Path:
    EngineSourceRuntimeAnimGraphRuntimePrivateBoneControllersAnimNode_CCDIK.cpp

    void FAnimNode_CCDIK::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
    {
        const FBoneContainer& BoneContainer = Output.Pose.GetPose().GetBoneContainer();
    
        // Update EffectorLocation if it is based off a bone position
        FTransform CSEffectorTransform = GetTargetTransform(Output.AnimInstanceProxy->GetComponentTransform(), Output.Pose, EffectorTarget, EffectorLocationSpace, EffectorLocation);
        FVector const CSEffectorLocation = CSEffectorTransform.GetLocation();
    
        // Gather all bone indices between root and tip.
        TArray<FCompactPoseBoneIndex> BoneIndices;
    
        {
            const FCompactPoseBoneIndex RootIndex = RootBone.GetCompactPoseIndex(BoneContainer);
            FCompactPoseBoneIndex BoneIndex = TipBone.GetCompactPoseIndex(BoneContainer);
            do
            {
                BoneIndices.Insert(BoneIndex, 0);
                BoneIndex = Output.Pose.GetPose().GetParentBoneIndex(BoneIndex);
            } while (BoneIndex != RootIndex);
            BoneIndices.Insert(BoneIndex, 0);
        }
    
        // Gather transforms
        int32 const NumTransforms = BoneIndices.Num();
        OutBoneTransforms.AddUninitialized(NumTransforms);
    
        // Gather chain links. These are non zero length bones.
        TArray<CCDIKChainLink> Chain;
        Chain.Reserve(NumTransforms);
        // Start with Root Bone
        {
            const FCompactPoseBoneIndex& RootBoneIndex = BoneIndices[0];
            const FTransform& LocalTransform = Output.Pose.GetLocalSpaceTransform(RootBoneIndex);
            const FTransform& BoneCSTransform = Output.Pose.GetComponentSpaceTransform(RootBoneIndex);
    
            OutBoneTransforms[0] = FBoneTransform(RootBoneIndex, BoneCSTransform);
            Chain.Add(CCDIKChainLink(BoneCSTransform, LocalTransform, 0));
        }
    
        // Go through remaining transforms
        for (int32 TransformIndex = 1; TransformIndex < NumTransforms; TransformIndex++)
        {
            const FCompactPoseBoneIndex& BoneIndex = BoneIndices[TransformIndex];
    
            const FTransform& LocalTransform = Output.Pose.GetLocalSpaceTransform(BoneIndex);
            const FTransform& BoneCSTransform = Output.Pose.GetComponentSpaceTransform(BoneIndex);
            FVector const BoneCSPosition = BoneCSTransform.GetLocation();
    
            OutBoneTransforms[TransformIndex] = FBoneTransform(BoneIndex, BoneCSTransform);
    
            // Calculate the combined length of this segment of skeleton
            float const BoneLength = FVector::Dist(BoneCSPosition, OutBoneTransforms[TransformIndex - 1].Transform.GetLocation());
    
            if (!FMath::IsNearlyZero(BoneLength))
            {
                Chain.Add(CCDIKChainLink(BoneCSTransform, LocalTransform, TransformIndex));
            }
            else
            {
                // Mark this transform as a zero length child of the last link.
                // It will inherit position and delta rotation from parent link.
                CCDIKChainLink & ParentLink = Chain[Chain.Num() - 1];
                ParentLink.ChildZeroLengthTransformIndices.Add(TransformIndex);
            }
        }
    
        // solve
        bool bBoneLocationUpdated = AnimationCore::SolveCCDIK(Chain, CSEffectorLocation, Precision, MaxIterations, bStartFromTail, bEnableRotationLimit, RotationLimitPerJoints);
    
        // If we moved some bones, update bone transforms.
        if (bBoneLocationUpdated)
        {
            int32 NumChainLinks = Chain.Num();
    
            // First step: update bone transform positions from chain links.
            for (int32 LinkIndex = 0; LinkIndex < NumChainLinks; LinkIndex++)
            {
                CCDIKChainLink const & ChainLink = Chain[LinkIndex];
                OutBoneTransforms[ChainLink.TransformIndex].Transform = ChainLink.Transform;
    
                // If there are any zero length children, update position of those
                int32 const NumChildren = ChainLink.ChildZeroLengthTransformIndices.Num();
                for (int32 ChildIndex = 0; ChildIndex < NumChildren; ChildIndex++)
                {
                    OutBoneTransforms[ChainLink.ChildZeroLengthTransformIndices[ChildIndex]].Transform = ChainLink.Transform;
                }
            }
    
    #if WITH_EDITOR
            DebugLines.Reset(OutBoneTransforms.Num());
            DebugLines.AddUninitialized(OutBoneTransforms.Num());
            for (int32 Index = 0; Index < OutBoneTransforms.Num(); ++Index)
            {
                DebugLines[Index] = OutBoneTransforms[Index].Transform.GetLocation();
            }
    #endif // WITH_EDITOR
    
        }
    }

    Path:
    EngineSourceRuntimeAnimationCorePrivateCCDIK.cpp

    namespace AnimationCore
    {
    
        bool SolveCCDIK(TArray<CCDIKChainLink>& InOutChain, const FVector& TargetPosition, float Precision, int32 MaxIteration, bool bStartFromTail, bool bEnableRotationLimit, const TArray<float>& RotationLimitPerJoints)
        {
            struct Local
            {
                static bool UpdateChainLink(TArray<CCDIKChainLink>& Chain, int32 LinkIndex, const FVector& TargetPos, bool bInEnableRotationLimit, const TArray<float>& InRotationLimitPerJoints)
                {
                    int32 const TipBoneLinkIndex = Chain.Num() - 1;
    
                    ensure(Chain.IsValidIndex(TipBoneLinkIndex));
                    CCDIKChainLink& CurrentLink = Chain[LinkIndex];
    
                    // update new tip pos
                    FVector TipPos = Chain[TipBoneLinkIndex].Transform.GetLocation();
    
                    FTransform& CurrentLinkTransform = CurrentLink.Transform;
                    FVector ToEnd = TipPos - CurrentLinkTransform.GetLocation();
                    FVector ToTarget = TargetPos - CurrentLinkTransform.GetLocation();
    
                    ToEnd.Normalize();
                    ToTarget.Normalize();
    
                    float RotationLimitPerJointInRadian = FMath::DegreesToRadians(InRotationLimitPerJoints[LinkIndex]);
                    float Angle = FMath::ClampAngle(FMath::Acos(FVector::DotProduct(ToEnd, ToTarget)), -RotationLimitPerJointInRadian, RotationLimitPerJointInRadian);
                    bool bCanRotate = (FMath::Abs(Angle) > KINDA_SMALL_NUMBER) && (!bInEnableRotationLimit || RotationLimitPerJointInRadian > CurrentLink.CurrentAngleDelta);
                    if (bCanRotate)
                    {
                        // check rotation limit first, if fails, just abort
                        if (bInEnableRotationLimit)
                        {
                            if (RotationLimitPerJointInRadian < CurrentLink.CurrentAngleDelta + Angle)
                            {
                                Angle = RotationLimitPerJointInRadian - CurrentLink.CurrentAngleDelta;
                                if (Angle <= KINDA_SMALL_NUMBER)
                                {
                                    return false;
                                }
                            }
    
                            CurrentLink.CurrentAngleDelta += Angle;
                        }
    
                        // continue with rotating toward to target
                        FVector RotationAxis = FVector::CrossProduct(ToEnd, ToTarget);
                        if (RotationAxis.SizeSquared() > 0.f)
                        {
                            RotationAxis.Normalize();
                            // Delta Rotation is the rotation to target
                            FQuat DeltaRotation(RotationAxis, Angle);
    
                            FQuat NewRotation = DeltaRotation * CurrentLinkTransform.GetRotation();
                            NewRotation.Normalize();
                            CurrentLinkTransform.SetRotation(NewRotation);
    
                            // if I have parent, make sure to refresh local transform since my current transform has changed
                            if (LinkIndex > 0)
                            {
                                CCDIKChainLink const & Parent = Chain[LinkIndex - 1];
                                CurrentLink.LocalTransform = CurrentLinkTransform.GetRelativeTransform(Parent.Transform);
                                CurrentLink.LocalTransform.NormalizeRotation();
                            }
    
                            // now update all my children to have proper transform
                            FTransform CurrentParentTransform = CurrentLinkTransform;
    
                            // now update all chain
                            for (int32 ChildLinkIndex = LinkIndex + 1; ChildLinkIndex <= TipBoneLinkIndex; ++ChildLinkIndex)
                            {
                                CCDIKChainLink& ChildIterLink = Chain[ChildLinkIndex];
                                const FTransform LocalTransform = ChildIterLink.LocalTransform;
                                ChildIterLink.Transform = LocalTransform * CurrentParentTransform;
                                ChildIterLink.Transform.NormalizeRotation();
                                CurrentParentTransform = ChildIterLink.Transform;
                            }
    
                            return true;
                        }
                    }
    
                    return false;
                }
            };
    
            bool bBoneLocationUpdated = false;
            int32 const NumChainLinks = InOutChain.Num();
    
            // iterate
            {
                int32 const TipBoneLinkIndex = NumChainLinks - 1;
    
                // @todo optimize locally if no update, stop?
                bool bLocalUpdated = false;
                // check how far
                const FVector TargetPos = TargetPosition;
                FVector TipPos = InOutChain[TipBoneLinkIndex].Transform.GetLocation();
                float Distance = FVector::Dist(TargetPos, TipPos);
                int32 IterationCount = 0;
                while ((Distance > Precision) && (IterationCount++ < MaxIteration))
                {
                    // iterate from tip to root
                    if (bStartFromTail)
                    {
                        for (int32 LinkIndex = TipBoneLinkIndex - 1; LinkIndex > 0; --LinkIndex)
                        {
                            bLocalUpdated |= Local::UpdateChainLink(InOutChain, LinkIndex, TargetPos, bEnableRotationLimit, RotationLimitPerJoints);
                        }
                    }
                    else
                    {
                        for (int32 LinkIndex = 1; LinkIndex < TipBoneLinkIndex; ++LinkIndex)
                        {
                            bLocalUpdated |= Local::UpdateChainLink(InOutChain, LinkIndex, TargetPos, bEnableRotationLimit, RotationLimitPerJoints);
                        }
                    }
    
                    Distance = FVector::Dist(InOutChain[TipBoneLinkIndex].Transform.GetLocation(), TargetPosition);
    
                    bBoneLocationUpdated |= bLocalUpdated;
    
                    // no more update in this iteration
                    if (!bLocalUpdated)
                    {
                        break;
                    }
                }
            }
    
            return bBoneLocationUpdated;
        }
    }
  • 相关阅读:
    三:oracle练习
    二:SQL 函数
    一:SQL基本语法
    生产者与消费者模式(理解) 进程间通信之消息队列编程
    C语言
    前端面试:基础javascript篇(二)
    Koa入门和源码分析
    前端面试:基础javascript篇(一)
    前端面试题(二)
    C复习
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/11848771.html
Copyright © 2020-2023  润新知