Animation blueprints with static states

I am applying UE4 as a tool for implementing a Digital Twin in manufacturing, specifically to represent motion of physical equipment.

As a simple example, consider a cabinet that opens and closes.

I have implemented Blueprint, Skeletal Mesh (of the physical cabinet with opposing doors, single armature with one bone per door), and two animations, one that opens the doors, and one that closes them. I have created an animation blueprint attached to the (cabinet) skeletal mesh. In the animation I have implemented OpenDoor and CloseDoor functions that handle booleans and can drive the underlying animation state machine from the Event Graph. In the AnimGraph, I’ve implemented a simple 4 state machine (Entry -> DoorsClosed -> DoorsOpening -> DoorsOpen -> DoorsClosing -> DoorsClosed). When a pawn/character approaches, the blueprint creates a reference to the animation blueprint, and invokes the appropriate method to open or close the door. All that logic is working correctly.

My problem is (for example), when I invoke the OpenDoor function, which activates the OpenDoor animation, it works correctly including state transitions. My problem is, when the DoorsOpening->DoorsOpen transition occurs, I just want the doors to remain open. I have no animation for the state when the doors are actually open (they are just supposed to stay open). Unfortunately, the doors snap shut at the completion of the transition. The state machine has the correct state, but the bones for the doors have returned to the closed state.

How do I represent an AnimGraph state when there is no animation to play but the bones have been moved by a previous animation?

Any animation state with nothing in it will play the rest pose. You need to have a “pose animation”, a one-frame animation which defines a pose, to exist in your state for it to do something.

If you don’t want to actually make one of these, what you can do is take your door opening animation, put it in the “DoorsOpen” node, right-click it, and hit “convert to single-frame animation”. A single-frame animation, rather than playing, takes in a float value which tells it where to be in the course of that animation’s timeline. You just have that float value be set to the final frame of the doors opening animation, and it will “play” that static pose of the doors being all the way open, until you exit the state.

Thank you, RhythmScript. I am building my animations in Blender, and importing via fbx files into UE4. For long term maintenance (I hope to expand the use of this workflow), I’m hoping to keep all animation dev work in one place. I’m not sure if you know Blender, but I’ve tried creating a single frame animation, and it does not seem to import into UE4 along with the multiframe animations. I may need to try it again, but am I going in the right direction?

Addendum: I found my problem. I am now able to export single frame animations from Blender, and have included them in the AnimGraph, and everything is working correctly now. Thank you again for your response.

I do know Blender, and I would have recommended making sure that a keyframe existed in the portion of the animation you were isolating so that it didn’t export nothing…

and don’t be that guy, cpeppler! Nothing is more annoying for someone in the year 2026 who Googled this issue, found this thread, read it with eager anticipation, and got to the end to see “EDIT: Fixed it” with no explanation of how you fixed it! Always include a parenthetical of what you missed/what you did. For posterity!

Correction taken! To be absolutely 100% honest, I think I had failed to select all the animations before I did Export->fbx file. I tried it again, opened the entire tree of armature, meshes, and animations, selected them all, and re-exported from Blender. I reimported the updated fbx into UE4, and there were my single frame animations of open and closed states. I associated them with the quiescent states in the AnimGraph and viola, it worked!

OK, so it was a dumb mistake. Full confession!

I’m sure there is a more efficient way to pass the animations. In fact, I bet there’s a way to do what I wanted with just one animation, accessed differently in UE4 AnimGraph. For example, run the open animation in reverse for close. Specify the first and last frame, and use those frames in the AnimGraph for open and close state. That would be far more elegant and efficient, but efficiency of workflow is for another day (unless you have it off the top of your head :wink:

If I may.

you would probably be better off creating a CabinetDoor actor that’s completely independent.
In the actor, you expose a mesh, a rotation axis, a rotation pivot, and rotation max.
Those are just variabkes you create. Components you add (the mesh).

you can then just use those values in the editor by adding the CabinetDoor actor as a child actor to any blueprint (cabinet frame).

opening/closing is done with simple rotation over a timeline. Like we do for doors (many tutorials you can pull out there).

While at it you can add and expose an interaction montage, so your pawn can play the montage when opening - for instance.

20 to 30min setup from 0 knowledge and endless reusability.

With the added bonus you aren’t messing around with skeletal meshes for things that really do not need them.

if you expect to showcase this as anyrhing more that a reference, Rendering a skeletal mesh well with non dynamic light is near impossible.
Whereas, setting the cabinet frame as static and the door actor as movable will bake almost any light scenario without issues.

won’t require animations, or weight painting… and allow you to swap models in seconds / even at runtime (which on a skeletal mesh with different bones, good luck).

MostHostLA - Thank you for your post. The approach you describe was the first approach I tried to take. I imported the different meshes (developed in a CAD system), including the base cabinet, both doors, with windows, with all dimensions tied to the same origin… I found multiple videos on how to do relative rotation of a single door, and was able to put the single door approach together easily. Interestingly, all the video authors warned about keeping the rotation around the actor origin (see problem below).

My problem came when I tried to rotate two doors, around two different axes using blueprint. Relative to the actor, a single rotation about the actor origin is simple using relative rotation and a timeline. However, I could not figure out for the life of me (after spending days) how to rotate the second door around the second axis. I gave up on the UE4 mesh only actor approach, and went to blender.

In blender, I discovered that using two different axes requires the use of quaternions (offsetting the axes and the rotation around them). After much work, I did get those to work correctly, then tried to reimport the animations using the Animgraph, and state model etc.

If there is a simple way to get rotations with two different axes going within an actor, I would prefer this approach, but I could not figure it out, thus the longer route.

My end goal is to animate pieces of equipment in a factory. Pieces of equipment may have combinations of translations and rotations. Picture animating a SCARA robot arm with a multi joint arm that also moves up and down in the Z axis. I was using the dual door cabinet open/close as a first, simple attempt, and I have been wrestling with how best to represent it in UE. The simplest workflow I can come up with is the best.

If you can help me with the dual axis rotation problem (with rotation limits), I’m all ears.

The problem isn’t the axis or rotation. Is probably how the problem was approached after the initial tutorial.

lets assume a few things you can easily replicate.

  1. create an actor called door.
  2. add a mesh to it.
  3. add a custom event. Call it open.
  4. ads a custom event. Call it close.
  5. create a timeline.
  6. right click type self. get a reference of self variable.
  7. drag from it and type transform. find the one that best suits your needs - you need to set, not get.
  8. split the transform pin.
  9. slept the rotation pin.

Here you just opened up the axis value on which you can affect the rotation you need…

  1. double-click the timeline, and set it up.
    you probably want a total speed of .25 (quarter second) or more. Make sure to set both the duration of the timeline and the timeline values by adding key frames and placing them appropriately.
    Place the last key frame at a value of 360 - for now. A full circle.

  2. drag from the self pin, type transform and find a matching value for the get function. Split its structure pins again.

  3. drag from each axis and create a variable. Call them f_rotationX, f_rotationY, and f_rotarionZ

  4. set these value (connect the exec pin) out of bot Open and Close (each needs its own set so duplicate and connect the set operations).

  5. plug the last set pin exec to the timeline.
    use Play from the open event, and Reverse for close event.

  6. Now connect Update to the set transform. And let’s get ready for some math.

  7. create 3 bools: b_rotateX, b_rotateY, b_rotateZ. Set all except X to false.

  8. drag from any float of the rotation split (set or get, same thing for now) and type select. This should generate a select float. Requiring a Bool to power it.

  9. connect the get of each bool you created to a select float.

  10. connect the GET rotation to the B value of the select (if false, use B, the original rotation).
    also, connect the output to the relevant rotation axis of the set function.

  11. do the math.
    take the initial rotation value, add the timeline output to it.
    plug into A of the relevant select float.

  12. handle direction.
    To handle closing, you need to check the timeline direction (it’s an emum pin that’s part of the timeline).
    when Clsoing, the value needs to be subtracted from the initial rotation.
    when opening (we handled it already) you need to add…

to do this, another select float, and a branch will probably do the trick. Run both add and subtract.
let the select float handle the proper value.
Inelegant, but easy to setup…

That’s basically it. you have a door that turns around whatever it’s pivot point is (set by the scene component) by 360°, and back around when you call the respective functions.

  1. adding variables to limit the swing of the door.
    Take the last result of the select float, drag and type Clamp.
    in the clamp, drag the Min and the Max and create proper floats.
    f_min_rotX, f_max_rotX etc.
    Expose those values like the bools.
    And pin their get to the respective spots.
    perhaps pre-set the max values to 125 or thereabouts.

That’s it.
Now you can make another actor, call it closet, and add a door actor to it - as a child actor.

Place the child actor, position, set its values, and choose how to transmit the open/close calls to it. Blueprint interface is probably great for this.
would need another 10 entries or so to adjust for that though.

At a base level, just make another custom event in the main actor, call it Open, mark it as blueprint callable.
Take the child actor reference in the code, drag from it, cast to the door class, and from the cast success, call the Open event.
Repeat for however many “doors” the object has.

then while the game is playing in PIE, eject, click the actor, and find the button for the BP callable function (event) in its details. Click it, and test out the open /closing of doors.
this is also where you fine-tune the angle on a per-instance basis by altering each child’s rotation options.

Thank you for this incredibly detailed reply. A course in a forum post! I remember when I first tried this I attempted to modify the second door mesh (the one away from the origin) directly using BP functions (without quaternions), and gave up. Your approach uses nested actors which avoids quaternion math, shifting to hierarchical BP relationships and communications. I had been using the CAD system to make sure all components were placed and oriented accurately relative to one another, but I’m guessing that will need to be done when placing child actors within the parent. Much to think about, but thank you again for another perspective from which to approach the problem