[Gameplay Camera System] How to implement "Montage-like" Action Cameras?

Hi everyone,

I am currently working with the new Gameplay Camera System and implementing character action cameras (e.g., Climbing, Conveyor Belts).

I am facing difficulties managing the Blend Stack behavior for these actions.

The Issue: Currently, when I push a new “Action Rig” and then try to blend it out (or remove it) before it reaches 100% weight, I run into stability issues.

I attempted to manually remove the active Rig when the action ends. However, because the incoming Rig hadn’t reached 100% weight yet, removing it left the stack without a fully weighted camera provider, causing the camera to snap or behave erroneously (invalid view).

The Desired Behavior (The “Animation Montage” Analogy): I am looking for a workflow similar to Animation Montages:

  1. Base State: The main gameplay camera is running.
  2. Push Action: When an action (e.g., Climbing) starts, I “Push” the Action Rig on top.
  3. Preservation: Crucially, the Base Rig should NOT be removed or blended out completely to the point of destruction. It should remain in the stack (perhaps dormant or paused), just like the base locomotion pose stays underneath a montage.
  4. Pop Action: When the action ends (even if the Action Rig only blended to 30%), I want to simply “Pop” the Action Rig.
  5. Resume: The Base Rig should immediately resume control from its previous state, smoothing out the transition.

The Question: In the current Gameplay Camera System architecture:

  1. How can I ensure the Base Rig remains valid/active in the background while an Action Rig is blending on top, preventing the “no active camera” error during early exits?
  2. Is there a built-in “Overlay” node or a specific BlendStack setting that mimics this Montage Push/Pop behavior without forcing the previous rig to fully exit?

I suspect CameraModifiers could handle this, but I am trying to achieve this purely within the new modular Camera System graph.

Any pointers would be appreciated!

[Attachment Removed]

重现步骤
Switch to new rig before it blend to 100%.

[Attachment Removed]

Hello! Sorry for the delays, and thanks for checking out the GPC (Gameplay Cameras) plugin.

Indeed, the main blend stack implementation doesn’t support that sort of situations. Instead, you usually just keep pushing the next camera rig instance on top of the previous ones, possibly getting into a “sandwiched” situation where you have BaseRig / ActionRig / BaseRig in the stack. This makes it easier to reason about, especially in terms of how the camera director concept works.

On the other hand, the blend stacks used for the base/global/visual layers do support what you say. So for example you can activate a CameraModifier or CameraShake that blend in and may be blended out gracefully, including after being “interrupted” mid-blend-in.

How do you do these pushes and pops? Did you implement some C++ code that his the GPC APIs directly?

[Attachment Removed]

Hi Ludovic,

Thank you so much for the detailed reply! That clarifies a lot about the intended design of the Main Layer blend stack.

To answer your question regarding how I am handling the pushes and pops: I am currently using a combination of StateTree + Chooser. The StateTree handles the high-level logic and state abstraction, and it uses a Chooser to evaluate the context and select the specific Camera Rig to activate.

Regarding the “sandwich” approach (`Old BaseRig -> `ActionRig` -> `New BaseRig`), has the team considered supporting a workflow where the old `BaseRig` is reactivated (un-paused/popped back into focus) instead of pushing a completely new instance?

I ask because pushing a new `BaseRig` creates a specific blending artifact in my project, which is exactly why I was hoping for a montage-like interruption mechanism:

  • I have a skill with a variable duration. When activated, it pushes an `AbilityRig`. When the skill ends, it pushes a new `BaseRig`.
  • If the player activates the skill very briefly and cancels it when the `AbilityRig` has only blended in to 10%, the `AbilityRig` logic seems to freeze, but it does not blend out.
  • Instead, as the new `BaseRig` starts blending in, the system forces the `AbilityRig` to continue its blend up to 100%, and it waits for the new `BaseRig` to also reach 100% before the `AbilityRig` is truly terminated.
  • This results in a visual glitch where the `AbilityRig` continues to incorrectly influence the camera behavior long after the skill has actually ended.

On a separate note (Climbing Cameras): I’m curious about the intended GPC workflow for a climbing camera where the camera needs to temporarily detach from the character’s root movement.

My current workaround is to cache the View Target’s position the moment climbing begins. I then apply the warped climbing camera trajectory to that cached position, timing it so that when the climb animation finishes, the camera is “coincidentally” right back in its expected default position behind the character.

How would you approach this kind of decoupled-then-realigned camera movement natively within the GPC framework?

Thanks again for your time and for the awesome plugin!

[Attachment Removed]

Hi!

Nice, using StateTree with GPC seems to be more popular than I expected. I sadly haven’t tested it much yet since all the projects I’ve been working with so far are either going with the Blueprint director. Of note, the Game Animation Sample Project uses a Chooser table with the Blueprint director. The StateTree director needs some attention and misses a few features… but I have it scheduled for a few improvements for 5.8.

> Regarding the “sandwich” approach (`Old BaseRig -> `ActionRig` -> `New BaseRig`), has the team considered supporting a workflow where the old `BaseRig` is reactivated (un-paused/popped back into focus) instead of pushing a completely new instance?

I haven’t considered it much since the current design was already locked down in my mind from a previous camera system I implemented at a previous company :slight_smile: But the reality is that moving things in the blend stack like this leads to issues. For instance, consider three different camera rigs: A, B, and C. You start with A, then go to B, then quickly to C, and then back to B. With the “new instance” design, the blend stack at that point is [ A1 - B1- C1- B2 ] (that is, an instance of A, an instance of B, an instance of C, and a second instance of B). If you were instead to interrupt B and re-push it on top, you would go from [ A - B - C ] to [ A - C - B ] on that last activation, as you move B from the middle of the stack to the top. And so the order in which the outputs are blended gets suddenly changed: instead of blending A and B, and then blending C on top, you blend A and C, and then B on top. The overall result of the blend stack “pops” in some non-obvious way. I believe there is an old GDC presentation from the Uncharted team at Naughty Dog that briefly explains the problem, and how they also just went to an “always push” model for their blend stacks. Some animation systems do the “interrupt and move” approach, but those tend to be limited to a small number of entries in their blend stacks to avoid the problem I described. I didn’t want to have this limitation since I know some fast-paced games can have more than half a dozen entries in a blend stack when things get intense.

There are a couple things you can do to fix your issue. The first one is to look into whether the AbilityRig could be done instead as a global Camera Modifier. The Base, Global, and Visual blend stacks are different types of stacks compared to the main blend stack. These are called “persistent stacks” in the code because the rigs running in there stay there until explicitly removed. A rig reaching 100% above them doesn’t pop anything. You can also insert and remove rigs freely, although of course you better make sure they blend in and out correctly to prevent bugs. There are Camera Modifier APIs to start and stop things like these. When you stop a Camera Modifier, it blends out before removing itself. If that happens mid-blend-in, it interrupts the blends and reverses it. This is possibly a good solution if your skill ability feature should effectively “take over the camera” for a short time -- since these things run in the Global stack, they are layered on top of whatever happens in the main stack, which may or may not fit your use case.

The second option requires some custom code, but you could implement a custom reversable blend for your AbilityRig, so that when it blends up to 10% and gets interrupted, your blend would go back to 0%. At this point you would have a 0% non-contributing entry in the blend stack, and it would stay there until someone higher up the stack reaches 100% and pops everything below, but it would visually and logically speaking be what you want.

The last option requires custom code *and* is pretty involved, but I designed the system to more-or-less not be dependent on the exact implementation of the main blend stack. If you look at the default root camera node evaluator, that’s the one that knows about these blend stacks. The rest of the system only knows about “activating” and “deactivating” rigs. This is because I know some people may want to customize the heart of the system, possibly running with a different setup than the default one with the 4 blend stacks (1 push-only stack, 3 persistent stacks).

Does this all make sense?

> How would you approach this kind of decoupled-then-realigned camera movement natively within the GPC framework?

The GPC rigs don’t care about what the GPC component is attached to. If you run a rig that is only, say, an offset node [X += 10] (i.e. a rig that just moves the camera 10 units to the side), we don’t want to run this logic from an absolute position, such as the world origin. So by default, the rig evaluation “starts” where whatever “owns” it is. In the case of a rig running from a GPC actor/component, that’s the component’s location. And so if the component is on the character, or on some other actor in the level, the rig runs from there. And then it moves the camera 10 units to the side. But the rig could completely ignore that and move the camera elsewhere. You could place a GPC rig actor in the sky, but run a rig whose first node moves the camera to a specific location, or attaches the camera to the player pawn, or whatever.

So you can have rigs in your character cameras that go and attach to some other actor, or some bone, or whatever else you need. You could have a rig that looks at where the last rig’s result was, and goes there, and then stays there even if the character moves. So while you may need to write a custom node in C++ or Blueprint or something, you can totally “detach” your camera rigs from whatever actor/component they’re being run from. Does that answer the question?

Cheers!

Ludo.

[Attachment Removed]

Hi Ludo,

Thanks again for the incredibly insightful response. The historical context regarding the Uncharted team’s blend stack philosophy makes perfect sense, and I completely understand why the “always push” model is strictly enforced for the main stack to prevent those nasty blending pops.

1. Climbing Camera Resolved First off, your suggestion for the decoupled camera movement was spot on. I implemented a custom node for the climbing rig that ignores the default attached transform and explicitly reads the cached View Target position from when the climb started. It works perfectly!

2. Ability Rig & The API Usability Question Regarding the AbilityRig, I agree that moving transient/interruptible actions to the Global or Visual persistent stacks is definitely the right architectural paradigm.

However, diving into this brought up a workflow and architecture question regarding how external gameplay systems interact with GPC.

I noticed a distinct difference in usability between native Unreal CameraModifiers and GPC’s Global/Visual layers. For instance, triggering a native camera effect (like a shake) is incredibly straightforward—external gameplay code can simply call AddNewCameraModifier() (a “fire-and-forget” approach).

In contrast, driving GPC Rigs as visual modifiers feels much more involved. Many of the core interfaces related to ActivateCameraRig appear to be private or internal to the GPC evaluation loop. It feels like GPC’s design heavily prefers the Camera Director to internally pull/poll external parameters to drive state changes, rather than allowing an external system (like a Gameplay Ability or a Gameplay Cue) to directly push a transient rig or visual effect onto a persistent stack.

My questions on the roadmap:

  • How do you envision the long-term relationship between native CameraModifiers and GPC’s Global/Visual layers? (Since things like Camera Shakes can be evaluated via CameraShakeAsset in GPC but also exist as native Modifiers).
  • Are there any plans to expose cleaner, public-facing APIs to make it easier for external gameplay code to directly trigger and manage GPC Rigs on persistent stacks without having to route everything through complex Director state polling?

Thanks again for taking the time to discuss the architecture. It’s hugely helpful for us early adopters trying to build scalable camera frameworks!

[Attachment Removed]

Hi! Glad to hear one issue got resolved.

For the other issues and questions, lets see…

* The “native/vanilla” UE camera modifiers and camera shakes are still there obviously but I have no plans currently to do anything with them. I’m focused on the GPC modifiers and shakes which are camera node graphs.

* I’ve done some work with the APIs for the upcoming 5.8 already -- I can point you to some Github commits if you’re interested. In addition to the start/stop APIs for base/global/visual camera rigs, I’ve added a bunch of modifier/shake-related APIs too. So there are dedicated APIs for starting global/visual modifiers and shakes, and they return an ID that you can use to stop them or see if they’re still playing. Hopefully that makes it much easier to work with modifiers and shakes -- as long as you have a reference to the GPC component or camera manager, the function should be there.

* Generally speaking yeah I want to make it easy to pass values and trigger things into the camera system from various gameplay systems. It just takes a long time to get everything setup :slight_smile: And to give a bit more context about the roadmap and how slowly it advances: I’m the only engineer working on GPC, and I’m only part-time on it (I’m working on Sequencer the other half of the time).

I hope this helps! Cheers

Ludo

[Attachment Removed]

Hi Ludo,

Wow, I had absolutely no idea you were single-handedly building and maintaining GPC while splitting your time with Sequencer! That is genuinely incredibly impressive. Massive respect to you for putting together such a robust, forward-thinking framework under those constraints.

I would absolutely love to take a look at those GitHub commits for 5.8! That would be immensely helpful.

I also took your advice and watched the GDC presentation from the Naughty Dog / Uncharted team. It was a huge eye-opener and really made the “always push” philosophy for the Main Layer click for me. It gave me a much deeper appreciation for the GPC design patterns.

Because of that, I’ve actually decided to pivot my architecture. I am planning to transition my camera system’s implementation away from StateTree and move towards a Priority Queue or Stack-based approach.

This ties perfectly into the exact feature I am currently trying to build: allowing the skill system (specifically GAS) to directly send a Rig, or even an entirely new Camera Director, to the camera system and request activation.

My plan is to implement a Stack or Priority Queue-based structure to manage all active Camera Directors. When a new ability triggers, the incoming Rig/Director is inserted based on priority (or pushed to the top) to take control. When the ability ends, it gets removed/popped, gracefully falling back to the previous state.

Since this stack-based management of external gameplay pushes sounds conceptually very similar to the philosophy behind your new 5.8 APIs for the Global/Visual layers, studying your commits will be the absolute perfect reference for me to implement this cleanly and natively.

Thanks again for your time, the great advice, and the offer to share the commits. Looking forward to studying the 5.8 changes!

Cheers,

Zarza

[Attachment Removed]

Just writing here as I was following this thread and heard Ludovic has been laid off ( hoped it was a mistake, but seems that’s the case )

What is Epic’s plan to support the Gameplay Cameras, as I think many assumed it was the new and “correct” way to do cameras moving forward.

( Is there a possibility to re-hire Ludovic? )

[Attachment Removed]

Hey there,

I can’t comment on any particular departures or possible hirings, but the state of Gameplay Cameras is in a good spot, and they are most likely ready to move into Beta status. The team is currently discussing exactly what that looks like. Unfortunately, at this time, I don’t have any further information than that.

Dustin

[Attachment Removed]