Announcement

Collapse
No announcement yet.

Custom AnimGraph Node C++ Templates

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

    Custom AnimGraph Node C++ Templates

    Greetings, I've made two templates (UE 4.15) that should serve as an example for Creating Custom AnimGraph Nodes, both inside a regular c++ project and inside a Plugin.

    Project Template: https://github.com/Hethger/UE4_AnimG...oject_Template

    Plugin Template: https://github.com/Hethger/UE4_Custo...lugin_Template

    The AnimGraph Node itself has the minimum code that a node needs to work, so it outputs the same pose that is feeded into it.

    Click image for larger version

Name:	MyAnimGraphNode.JPG
Views:	1
Size:	13.9 KB
ID:	1217116

    I post this as there is no complete guide that goes in depth about creating Custom AnimGraph Nodes. Theres enough information about making the functionality inside the node's source files. But what lacks is an oficial explanation of the structure that has to be built around them to properly work outside the editor.

    Through trial and error, research, and help from the community, I finally elaborated the procedure by which I made this templates and with which I also incorporate Custom AnimGraph Nodes into my own plugin: the Mirror Animation System.

    I can only attest for this packaging and working in windows, as I can't test this in other platforms. Although a strange specific thing is that the plugin needs to have IOS blacklisted to package the Plugin on it's own, but not when Packaging the whole project.

    I have a dream, that maybe with the infinite power of the community, this and other small voids of information about this topic will come to and end, marching to a future were no one will ever have to suffer in agony doing AnimGraph Nodes, ever again.

    #2
    Why didn't you do this last week? :/
    I was in need of this soooo badly last week, I ended up figuring out (after long two hours) how to make them (and customize widget cosmetics) by myself

    This is my final result at the moment:






    Anyways, is always good to have samples, making a wiki page would be cool too!
    | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

    Comment


      #3
      I have a bit of a problem with your template on 4.16. While everything compiles correctly and your node shows up in the context menu just fine, the nodes are actually never saved. They will work in game and everything, but once I reboot the editor, they are just gone.

      When placing the node
      Click image for larger version

Name:	CustomNodeA.jpg
Views:	1
Size:	40.9 KB
ID:	1129717

      On reboot
      Click image for larger version

Name:	CustomNodeB.jpg
Views:	1
Size:	39.6 KB
ID:	1129718

      The message I get on reboot
      Click image for larger version

Name:	CustomNodeErrorMessage.jpg
Views:	1
Size:	94.3 KB
ID:	1129719

      I should note that for testing sake, I simply just moved your plugin into the plugin folder and didn't change anything (primarily to see if my earlier attempts of using your template for my own version weren't botched in some way).

      Edit: I just tested an older backup project with a Unreal Engine 4.15.2, and get the exact same error, leading me to believe that there may be some other settings I may have to change. Would you happen to have any ideas Hethger?

      Edit 2: Got the same result on an new fresh project.
      Last edited by cridia; 06-15-2017, 12:17 AM.

      Comment


        #4
        Originally posted by cridia View Post
        I have a bit of a problem with your template on 4.16. While everything compiles correctly and your node shows up in the context menu just fine, the nodes are actually never saved. They will work in game and everything, but once I reboot the editor, they are just gone.

        When placing the node
        [ATTACH=CONFIG]144999[/ATTACH]

        On reboot
        [ATTACH=CONFIG]145000[/ATTACH]

        The message I get on reboot
        [ATTACH=CONFIG]145001[/ATTACH]

        I should note that for testing sake, I simply just moved your plugin into the plugin folder and didn't change anything (primarily to see if my earlier attempts of using your template for my own version weren't botched in some way).

        Edit: I just tested an older backup project with a Unreal Engine 4.15.2, and get the exact same error, leading me to believe that there may be some other settings I may have to change. Would you happen to have any ideas Hethger?
        This problem seems similar to when you make c++ structs, functions and such available to blueprints, you use them inside a blueprint and eventually you edit the source for this functions or structs (by Changing what the function returns, changing the name of one of the member of the structs, etc.), sudenly those blueprints where you used these functionalities have compile errors, or don't save like in your case.

        To solve this issue what I did was eliminate the AnimGraph Node from every Animation Blueprint, Inside those blueprints I connect a placeholder node to the output so it compiles a pose (like play animation). Then regenerate project files, open the project in visual studio, recompile, compile again, and finally open the project and use the node regularly.

        Tell me whether this worked for you.

        Cheers, Theodor

        Comment


          #5
          No, I am still getting the exact same error, even after following all the steps you described. I should note I have also tried this with a fresh new project, and am getting the exact same errors. Makes me believe there is something somewhere that I haven't properly set yet (maybe something in the settings), though it would be strange because other editor extending plugins I am using don't have any problems whatsoever.

          On another node; if I use your example node, it will all be removed upon reboot anyway so removing them is not necessary. When I use a bit more "intensive" node in terms of functionality, well, then upon reboot it will without fail throw an access violation error and crash before the editor is even started.
          Last edited by cridia; 06-15-2017, 02:44 AM.

          Comment


            #6
            Those errors look very much like what you'd get if the plugin modules were not loaded. Are you able to use the plugin (for example, replace the custom node), immediately after seeing those messages? If so, I wonder if it could be related to module loading order - seems like perhaps somehow the blueprint is being loaded before the plugin modules. I'd maybe try playing around with the LoadingPhase setting of the module references within your uplugin file. See here for reference.

            Comment


              #7
              Originally posted by kamrann View Post
              Those errors look very much like what you'd get if the plugin modules were not loaded. Are you able to use the plugin (for example, replace the custom node), immediately after seeing those messages? If so, I wonder if it could be related to module loading order - seems like perhaps somehow the blueprint is being loaded before the plugin modules. I'd maybe try playing around with the LoadingPhase setting of the module references within your uplugin file. See here for reference.
              It worked! Changing it to predefault stops the violation errors and the nodes from disappearing. Now I can finally continue moving all the nodes I had made before into the plugin. Thanks!

              Comment


                #8
                Originally posted by kamrann View Post
                Those errors look very much like what you'd get if the plugin modules were not loaded. Are you able to use the plugin (for example, replace the custom node), immediately after seeing those messages? If so, I wonder if it could be related to module loading order - seems like perhaps somehow the blueprint is being loaded before the plugin modules. I'd maybe try playing around with the LoadingPhase setting of the module references within your uplugin file. See here for reference.
                This definitely works, but changing the module load order will create a conflict if you're using component visualizers (these require a PostEngineInit load order). Outside of doing something silly like creating separate modules for the visualizers and the graph nodes, what would be the solution to have both?

                Comment


                  #9
                  Nothing silly about creating separate modules for them, they're totally unrelated after all. In fact I have a feeling the graph nodes should really be in a Developer module anyway, and the visualizers in an Editor module. This is definitely the case for blueprint nodes in order for things to work in standalone mode; not 100% sure it's the same for anim nodes but likely is.

                  Comment


                    #10
                    This post is very relevant even till today . I am struggling to get my plugin to package for so many days with horribly low information regarding it . This should hopefully make me understand where i did wrong.

                    Comment


                      #11
                      Hethger, a god among men.

                      The project would not compile unless I made a few changes since the editor has updated somewhat since this was posted. I'd do a pull request, but I'm still learning how to git.
                      I haven't tried a packaged project with these changes, however I had to perform these for the project to even build. I am also using a completely empty project.


                      REQUIRED(?) CHANGES:

                      MyGame.Target.cs
                      Code:
                      using UnrealBuildTool;
                      using System.Collections.Generic;
                      
                      public class MyGameTarget : TargetRules {
                           public MyGameTarget(TargetInfo Target) {
                                Type = TargetType.Game;
                      
                                // SetupBinaries() function is deprecated, we can just do this instead
                                // We also no longer need to check if we are within the editor
                                // Don't know why, possibly 'Type = TargetType.Editor' in 'MyGameEditor.Target.cs' takes care of this
                                ExtraModuleNames.AddRange(new string[] { "MyGame" });
                           }
                      }

                      MyGameEditor.Target.cs
                      Code:
                      using UnrealBuildTool;
                      using System.Collections.Generic;
                      
                      public class MyGameTarget : TargetRules {
                           public MyGameTarget(TargetInfo Target) {
                                Type = TargetType.Editor;
                      
                                // SetupBinaries() function is deprecated, we can just do this instead
                                ExtraModuleNames.AddRange(new string[] { "MyGame"});
                           }
                      }

                      MyGame.cpp
                      Code:
                      #include "MyGame.h"
                      #include "Modules/ModuleManager.h"
                      
                      class FDevProjectModule : public FDefaultGameModuleImpl {
                      #if WITH_EDITOR
                          virtual void StartupModule() override {
                              // Note the addition of AnimGraphRunTime      
                              FModuleManager::Get().LoadModule(TEXT("BlueprintGraph"));
                              FModuleManager::Get().LoadModule(TEXT("AnimGraph"));
                              FModuleManager::Get().LoadModule(TEXT("AnimGraphRunTime"));
                              FModuleManager::Get().LoadModule(TEXT("MyGameEditor"));
                          }
                      #endif
                      };
                      
                      IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, MyGame, "MyGame");

                      MyAnimNode.h
                      Code:
                      #pragma once
                      
                      #include "Animation/AnimNodeBase.h"
                      #include "MyAnimNode.generated.h"
                      
                      USTRUCT(BlueprintType)
                      struct MYGAME_API FMyAnimNode : public FAnimNode_Base {
                          GENERATED_BODY()
                      
                          UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links)
                          FPoseLink BasePose;
                      
                      public:
                          MyAnimNode();
                      
                          // FAnimNode_Base interface
                          virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
                          virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
                          virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
                          virtual void Evaluate_AnyThread(FPoseContext & Output) override;
                          virtual void GatherDebugData(FNodeDebugData& DebugData) override;
                          // End of FAnimNode_Base interface
                      
                      };

                      MyAnimNode.cpp
                      Code:
                      #include "MyAnimNode.h"
                      
                      #include "MyGame.h"
                      #include "Animation/AnimInstanceProxy.h"
                      
                      
                      FMyAnimNode::FMyAnimNode() {
                      
                      }
                      
                      void FMyAnimNode::Initialize_AnyThread(const FAnimationInitializeContext & Context) {
                          Super::Initialize_AnyThread(Context);
                      
                          BasePose.Initialize(Context);
                      }
                      
                      void FMyAnimNode::CacheBones_AnyThread(const FAnimationCacheBonesContext & Context) {
                          BasePose.CacheBones(Context);
                      }
                      
                      void FMyAnimNode::Update_AnyThread(const FAnimationUpdateContext & Context) {
                          EvaluateGraphExposedInputs.Execute(Context);
                          BasePose.Update(Context);
                      }
                      
                      void FMyAnimNode::Evaluate_AnyThread(FPoseContext & Output) {
                          // Evaluate the input
                          BasePose.Evaluate(Output);
                      }
                      
                      void FMyAnimNode::GatherDebugData(FNodeDebugData & DebugData) {
                          FString DebugLine = DebugData.GetNodeName(this);
                      
                      
                          DebugData.AddDebugItem(DebugLine);
                      
                          BasePose.GatherDebugData(DebugData);
                      }

                      To get SkeletonControlBase nodes working I had to also add the 'AnimGraphRuntime' public module in 'MyGame.build.cs', otherwise you'll get drowned by linker errors.
                      Last edited by Lexeon; 04-21-2019, 09:08 PM.

                      Comment

                      Working...
                      X