Announcement

Collapse
No announcement yet.

Animation Techniques used in Paragon and January Game Jam Theme Announcement - Live From Epic HQ

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    #31
    ncn2cc - that seems to be the case. Binary search would find the correct value in 4-5 steps at most...

    Comment


      #32
      I read the key frames directly. Since we assume linear interpolation in between keys, we can easily derive intermediate positions in between keys.

      Look at FRichCurve::GetCopyOfKeys() or FRichCurve::GetConstRefOfKeys()
      Laurent "SenorZorro" Delayen
      Senior Gameplay Programmer
      Epic Games

      Comment


        #33
        Originally posted by nan2cc View Post
        Hi @LDelayen,

        Thanks again for sharing those with us !

        Help me to clarify things a little bit please.

        So, You loop from 0 to animation-time-length and using float Value = FRichCurve::Eval(float Time) to evaluate the curve and get the value. When Value is equal to your current capsule rotation (for example, assuming that we are doing this for the turn animation) then you finish the search and evaluate the anim sequence using that Time.

        This is the idea ? and you do this inside the Tick ? is not a problem in term of consuming CPU or the binary search algorithm is enough to find very quickly the value ?

        Please, help me to clarify this.

        PD: Sorry for my english

        Thanks so mush !!
        >> So, You loop from 0 to animation-time-length and using float Value = FRichCurve::Eval(float Time) to evaluate the curve and get the value.

        no, I do a binary search on the keys directly. Evaluating the curve is slow, and we assume linear interpolation in between keys. So I just need to find the bounding keys, and do a lerp.
        We don't have that many keys in these animations, so the binary search is pretty fast. It hasn't shown up on our profiles as something significant.

        The basic idea is my distance to the marker is 12 units, I want to find the position in the animation where the distance curve is 12.
        I do a binary search for the bounding keys around that value. Let's say I find Key3 (9) and Key4(13). I then do a lerp to find the correct time in the animation,

        Here's the code for that function, it's fairly straight forward:

        float FindPositionFromDistanceCurve(const FFloatCurve& DistanceCurve, const float& Distance, UAnimSequenceBase* InAnimSequence)
        {
        const TArray<FRichCurveKey>& Keys = DistanceCurve.FloatCurve.GetConstRefOfKeys();

        const int32 NumKeys = Keys.Num();
        if (NumKeys < 2)
        {
        return 0.f;
        }

        // Some assumptions:
        // - keys have unique values, so for a given value, it maps to a single position on the timeline of the animation.
        // - key values are sorted in increasing order.

        #if ENABLE_ANIM_DEBUG
        if (bDebugLocomotion)
        {
        // verify assumptions in DEBUG
        bool bIsSortedInIncreasingOrder = true;
        bool bHasUniqueValues = true;
        TMap<float, float> UniquenessMap;
        UniquenessMap.Add(Keys[0].Value, Keys[0].Time);
        for (int32 KeyIndex=1; KeyIndex < Keys.Num(); KeyIndex++)
        {
        if (UniquenessMap.Find(Keys[KeyIndex].Value) != nullptr)
        {
        bHasUniqueValues = false;
        }

        UniquenessMap.Add(Keys[KeyIndex].Value, Keys[KeyIndex].Time);

        if (Keys[KeyIndex].Value < Keys[KeyIndex - 1].Value)
        {
        bIsSortedInIncreasingOrder = false;
        }
        }

        if (!bIsSortedInIncreasingOrder || !bHasUniqueValues)
        {
        PrintDebugString(FString::Printf(TEXT("ERROR: BAD DISTANCE CURVE: %s, bIsSortedInIncreasingOrder: %d, bHasUniqueValues: %d"),
        *GetNameSafe(InAnimSequence), bIsSortedInIncreasingOrder, bHasUniqueValues));
        }
        }
        #endif

        int32 first = 1;
        int32 last = NumKeys - 1;
        int32 count = last - first;

        while (count > 0)
        {
        int32 step = count / 2;
        int32 middle = first + step;

        if (Distance > Keys[middle].Value)
        {
        first = middle + 1;
        count -= step + 1;
        }
        else
        {
        count = step;
        }
        }

        const FRichCurveKey& KeyA = Keys[first - 1];
        const FRichCurveKey& KeyB = Keys[first];
        const float Diff = KeyB.Value - KeyA.Value;
        const float Alpha = !FMath::IsNearlyZero(Diff) ? ((Distance - KeyA.Value) / Diff) : 0.f;
        return FMath::Lerp(KeyA.Time, KeyB.Time, Alpha);
        }
        Laurent "SenorZorro" Delayen
        Senior Gameplay Programmer
        Epic Games

        Comment


          #34
          This is invaluable! Thank you so much!

          Comment


            #35
            Hi @LDelayen,

            Again, thanks you so so sooo much for sharing this !! as @DamirH said, this is invaluable !!

            Thanks you so much !!

            Comment


              #36
              Cheers for the talk and the help @LDelayen some really great stuff you doing for Paragon.

              I was wondering if you had multiple out transition animations based on what foot you leave the loop locomotion animation or does the blend between the two animations cover any problems?

              Thanks

              Comment


                #37
                Originally posted by [EPIC] Laurent Delayen View Post
                ...
                Hi Laurent Delayen,

                Today I joined to the Early Access because I could not wait to "touch and feel" Paragon, mainly the animations part. And, first of all: Great work guys !!

                One thing that blows my mind and I can't figure out how do it, is the attack animation when you are walking.

                For example, Steel has a Melee Attack Animation in place. If you are in Idle, and you press the attack button, the animation is played in place, I think that basically is a montage played on all the full body, isn't ?

                But ... the awesome part is when you start moving and attack, I'm completely sure that is not a simple Layered blend per bone . I think that you do some Addictive because you can see a kind of blend between attack animation and walk animation on the legs and the full attack animation on the upper body, against man, it look AWESOME !!

                Can you explain a little bit how you implement that part, please ??

                I was watching again and again the "Animation Techniques used in Paragon" video, trying to find where you do it, but I can't see it, I think that probably is where you "Take out legs" with some UpperBodyMeshSpaceAdditive StateMachine plus Layered Blend per bone plus more Additive and a bunch of other stuffs XD ... Please, I will appreciate so much if you can explain us a little bit deeper how you get that wonderfull blend when you attack and walk.

                Sorry for my english.

                Thanks so much

                Best regards.
                Last edited by nan2cc; 03-19-2016, 12:48 AM.

                Comment


                  #38
                  ok Epic. Please for the humankind love, show me how did you do those turn animations logic!!! PLEASE!!!!!
                  Email: tessaro.unrealdeveloper@hotmail.com
                  BP/C++ Programmer.
                  WIP Portfolio: https://filipetessaro.wixsite.com/portfolio
                  UE Marketplace: https://unrealengine.com/marketplace...ions-rts-style

                  Comment


                    #39
                    This is amazing techniques, want to see some tools for operations like this in engine!

                    Comment


                      #40
                      HI!
                      I wonder if there is some detailed resource to follow in order to make real use of this techniques.
                      The concepts are awesome, but is really hard to implement.

                      Comment


                        #41
                        After a long time I've actually finally gotten back to the curve lookup and marker stuff.

                        The function above has proven extremely valuable, I ran into a different issue - how the hell do I get the animation curve out of my montage / animation?

                        This ended up working but I am not quite sure if it's the right approach. Any confirmation from Epic would be grand.

                        Code:
                        float FindPositionFromDistanceCurve_BP(const FName AnimationCurveName, const float& Distance) const
                        {
                        	for (FFloatCurve& FC : CurrentAttackMontage->RawCurveData.FloatCurves)
                        	{
                        		if (FC.Name.DisplayName == AnimationCurveName)
                        		{
                                                //This is the function from above.
                        			return FindPositionFromDistanceCurve(FC, Distance);
                        		}
                        	}
                        
                        	return 0.f;
                        }

                        Comment


                          #42
                          Hey [MENTION=398]LDelayen[/MENTION]

                          Not sure if you are still reading it.
                          I recently implemented bare bones (pun not intended), version of animation switching from Paragon.
                          As of now my implementation consis of bnuch of if's with carefuly handrafted conditions, to decide where character is currently going (forwards, back, left, right) and while it somewhat working is nowhere near as smooth as it is in Paragon. There are occasional hitches due the inability to decided which direction character is going.

                          My question. Could you show us, how do you select current direction for animation ?
                          https://github.com/iniside/ActionRPGGame - Action RPG Starter kit. Work in Progress. You can use it in whatever way you wish.

                          Comment


                            #43
                            Originally posted by iniside View Post
                            Hey [MENTION=398]LDelayen[/MENTION]

                            Not sure if you are still reading it.
                            I recently implemented bare bones (pun not intended), version of animation switching from Paragon.
                            As of now my implementation consis of bnuch of if's with carefuly handrafted conditions, to decide where character is currently going (forwards, back, left, right) and while it somewhat working is nowhere near as smooth as it is in Paragon. There are occasional hitches due the inability to decided which direction character is going.

                            My question. Could you show us, how do you select current direction for animation ?
                            when you mention current direction for animation, you meant, what is the condition for select certain animation in the animgrah/event based in the character direction ?
                            using C++ is quite simple, you just need to extract the current player controller rotation normalized. if you want to get the absolute control rotation vectorized data:

                            Code:
                            float JoyRight, JoyUp;
                            FVector X(FVector::ZeroVector);
                            FVector Y(FVector::ZeroVector);
                            FVector Z(FVector::ZeroVector);
                            
                            const FRotationMatrix R(Controller->GetControlRotation());
                            R.GetUnitAxes(X, Y, Z);
                            
                            //or...
                            //X = R.GetScaledAxis(EAxis::X);
                            //Y = R.GetScaledAxis(EAxis::Y);
                            //Z = R.GetScaledAxis(EAxis::Z);
                            
                            PCOwner->GetInputAnalogStickState(EControllerAnalogStick::CAS_LeftStick, JoyRight, JoyUp);
                            
                            //current controller direction
                            FVector Direction = ((JoyRight* X) + (JoyUp* Y)).Normalize();
                            ...if you use BP, the animinstance offers a const direction function with a float output. based on that they use a custom blendspace for the direction animations.
                            Last edited by huatson; 04-20-2017, 04:11 AM.

                            Comment


                              #44
                              [MENTION=21348]huatson[/MENTION]

                              Hey thanks.
                              What I mean, Is what to know in which direction character is moving (Left, right, forward, backward, left forward, etc). I have it somewhat workin. Calculating the exact direction is not that much of an issue, as so knowing when to exactly switch direction (ie, from forward to left). Right now I do it something like this:

                              Code:
                              if(Direction > 0.2 && Direction < 0.5)
                              {
                                //switch to left
                              }
                              And there is bunch of those ifs. I wonder if there better way to do it.


                              I will try, what are you suggesting.
                              From what I see, it will not work on non-player characters ?
                              https://github.com/iniside/ActionRPGGame - Action RPG Starter kit. Work in Progress. You can use it in whatever way you wish.

                              Comment


                                #45
                                [MENTION=398]LDelayen[/MENTION] Are you using a special animation graph node to do the evaluation of the distance curves or are you evaluating it in the animInstance class?

                                Comment

                                Working...
                                X