zoukankan      html  css  js  c++  java
  • 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;
        }
    }
  • 相关阅读:
    Begin Example with Override Encoded SOAP XML Serialization
    State Machine Terminology
    How to: Specify an Alternate Element Name for an XML Stream
    How to: Publish Metadata for a WCF Service.(What is the Metadata Exchange Endpoint purpose.)
    Beginning Guide With Controlling XML Serialization Using Attributes(XmlSerializaiton of Array)
    Workflow 4.0 Hosting Extensions
    What can we do in the CacheMetaData Method of Activity
    How and Why to use the System.servicemodel.MessageParameterAttribute in WCF
    How to: Begin Sample with Serialization and Deserialization an Object
    A Test WCF Service without anything of config.
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/11848771.html
Copyright © 2011-2022 走看看