DEV Community

Max Pixel
Max Pixel

Posted on • Updated on

UE5 Anti-Practice: Collision Components Under a Mesh Component

UE5 screenshot

This is a common (anti-)pattern that I come across in other people's Unreal Engine projects: A mesh with one or more collision components attached to it. This will work, but it's not optimal, and is probably a sign that the developer is used to Unity.

Unity vs Unreal Engine: Composition of Components vs Composition within Components


Standard Transform Hierarchy

An important architectural difference between Unity and Unreal Engine is the relationship between components and the standard transform hierarchy. By "standard transform hierarchy", I mean the interface through which built-in components and user code share access to a common set of transform (location, rotation, scale) and hierarchy (parent/child-reference) values. In any modern game engine, there is always a single1 central transform hierarchy implementation that serves as an accessible and predictable backbone for all things 3D. It's this native hierarchy that enables features like the editor's drag-to-move feature, overlap detection, and render culling, all without requiring the game developer to explicitly read & write transform values between editor-events, the physics subsystem, and the rendering subsystem.


UML diagram

In Unity, the Transform Component is the exclusive owner of standard transform hierarchy values, and is a sealed class; each Game Object has exactly one Transform Component, and vice versa; Transform-dependent components (e.g. a mesh which needs to know where to render) use the transform of their Game Object's one Transform Component.


UML diagram

In Unreal Engine, Scene Component is the designated owner of standard transform hierarchy values; Transform-dependent components are subclasses of Scene Component. It can appear as if Actors also have standard transform values, but this is only true in that every Actor has at least one Scene Component (conversely, Scene Components are perfectly capable of existing without any owning Actor).

Basically, the difference comes down to this: Both engines have "entity" classes which are composed of "component" classes. In Unity, the "entity" class has a transform; in Unreal Engine, the "component" class can have a transform. The difference may seem subtle, but has significant architectural implications, and indicates a broader pattern in each engine.


Patterns Extrapolated: Composition vs Inheritance?

Unity screenshot

Mesh Renderer in Unity does not have a transform value because it uses the Transform of its Game Object. Similarly, it doesn't actually own any reference to the mesh that it's supposed to render, either: Instead, it borrows that value from its neighboring Mesh Filter. If the Game Object also has a Mesh Collider, a different type of functionality that also relies on the use of a triangle mesh, that will use the same Mesh Filter as its neighboring Mesh Renderer. Mesh Filter, like Transform, is restricted to only one per Game Object.


UE5 screenshot

In Unreal Engine, Static Mesh Component needs a transform value, so it extends Scene Component. Spline Mesh Component needs to do the same things that Static Mesh Component does, but with additional nuance, so it extends Static Mesh Component. Instead of breaking "mesh rendering" and "mesh collision" into separate components, Unreal Engine's Static Mesh Component implements both rendering and collision (each of which is optionally activated or deactivated).


This certainly seems like a matter of composition versus inheritance. Considering the mantra, "composition over inheritance", you might conclude that Unity has chosen the better and more flexible approach. On the contrary, Unity's approach just moves coupling to a less convenient level of abstraction: Game Object ends up defined as "a group of Components that have the same transform, mesh asset reference, physical properties..." etc.

Unity screenshot

This limits Game Object's usefulness as an "entity" mechanism. A group of Components that logically compose one entity (a player) might have different locations and meshes (right hand, left hand, camera). In this situation, Unity requires you to break that entity up into a soup of loosely formed partial-entities, because, as an engine, it has coupled "entity" with "location" and "mesh" and many other concepts.

Unreal Engine's Actor, on the other hand, can be defined more simply as "a place to put logic that composes together one or more Components as a single representative entity".

UE5 screenshot

Unreal Engine’s decoupled approach allows you to more clearly represent and enforce your game’s primary logical encapsulations through the engine’s tools. As you can see in the screenshots above and graph below, this results in a more streamlined object model that makes editing the game easier for the developer, and makes running the game easier for the CPU.

UML Diagram


Unreal Engine's components do exhibit a sometimes extreme depth of inheritance, but as soon as you look "under the hood" you will find composition galore. FPrimitiveSceneProxy is the object type that is actually parsed by the rendering subsystem. FBodyInstance is the object type that is actually parsed by the collision subsystem. UStaticMeshComponent is composed of FPrimitiveSceneProxy and FBodyInstance, wrapping them up in a way that coordinates them to represent one thing, which you can easily define in the editor and via high-level scripting.

In Unity, Components are the only way to compose together the physical and visual aspects of a single thing, because Components are the only access that we developers are given to those subsystems. In Unreal Engine, we simply have more layers of composition, with unmanaged (non-reflected) C++ classes being the lowest-level.

So, while it's possible to use Components for composing together a thing's visual and physical aspects, it's not necessary nor ideal - the engine has already composed those things together at a lower level, and allows us to tweak the nuances of their composition via Static Mesh Component's properties.


UE4 screenshot

I've mentioned several ways in which Unreal Engine's approach can be more manageable, but it's not entirely without disadvantages. There is technically some wasteful memory overhead from having collision-related information attached to every Static Mesh Component, including those that don't actually need to collide (although this is probably outmatched by the memory overhead of the additional Component and Game Object instances that Unity would require in the same scenario). Most significantly, the presence of unused Collision properties causes visual clutter in the editor that can be a chore to parse through. There's something wonderfully minimalist about the typical properties-panel in Unity, making it easier to hone in on relevant properties while working in the editor.


Don't Do This

With all of that having been cleared up, let's revisit the power-up mesh from the beginning of this article. You now know that Static Mesh Component already composes together both the rendering and collision subsystems, so the additional components aren't necessary. Unnecessary doesn't always equate to "bad", but in this case it certainly equates to "worse".

The downsides to having 3 components instead of 1, all else equal, include

  • Memory fragmentation.
  • Additional memory used.
  • 3x as many properties for you to define and maintain in the editor.
    • If you expect them to all behave the same, you have to maintain that by hand.
    • Alternatively, you can configure the components to weld their physics bodies together, which forces all of them to have the same per-body settings...
      • But then you have settings in the details panel that don't actually have any effect, which can be confusing later on.
      • The engine will end up performing even more Transform re-calculations every time the parent is moved.
  • If the components are configured to produce overlap events, then the Update Overlaps function will run 3 times instead of just once. Update Overlaps is notoriously bad for performance.

For a single instance, this probably wouldn't ever amount to a noticeable difference. However applied to several actors, each of which having several instances, across your entire game, you could end up with a difference of hundreds or thousands of components, which could add up to a difference of many hours tweaking properties in the editor, and of several milliseconds per frame on a low-end mobile device.


Do This Instead

I'll walk through the proper implementation step-by-step.

If the goal is simply to give the mesh collision, it could be as simple as enabling the desired collision settings (the same exact ones found on the collision components) on the mesh component itself. However, if anybody is adding collision components under a static mesh, chances are it's because they want the collision to comprise a particular arrangement of shapes, whether for functional purposes or simply for optimization.

That's certainly true for this example. Simply slapping on a physics profile to the static mesh component is enough to make it collide with things, but it would do so using triangle-mesh collision. It would be computationally cheaper to use a single capsule and a single box, and perhaps you also have a need to differentiate between collision with the handles vs the main body of the item.

wireframe


I've been talking about the Static Mesh Component, and have mentioned that it hosts both rendering-related and physics-related properties. This is also true of the Static Mesh asset, which is where you can find the properties most relevant to this particular task.

UE5 screenshot

The relevant Static Mesh asset can be located in the Content Browser using the "Browse To" (🔍) icon in the Static Mesh Component's Details. From there, it can be opened and edited just like any other asset.


In Unreal Engine, as in Unity, Static Mesh assets implicitly supply triangle-mesh collision. In Unreal Engine, Static Mesh assets can additionally contain "Simple Collision". This is the feature that you can use to achieve that particular arrangement of shapes, without having to use additional Components.

UE5 screenshot

After opening the Static Mesh asset, the first thing to do is to make sure that "Simple Collision" visualization is turned on.

UE5 screenshot

When opening a Static Mesh and viewing its simple collision, you may find that some form of simple collision is already defined (it may have been imported, or generated upon import). In this specific case, there is a convex hull already, but a capsule + box setup would be cheaper performance-wise and result in higher-fidelity collision behavior.


UE5 screenshot

The Collision menu, found in the top toolbar of the Static Mesh asset editor, is where we can find both the ability to delete the existing unwanted collision, as well as the ability to add new shapes.


UE5 screenshot

Once added, shapes can be modified using the 3D widgets, and/or the Details Panel.


UE5 screenshot

These changes take effect immediately for all instances of the Static Mesh (excluding those configured to ignore Simple Collision and always use Complex Collision, of course). You can confirm this by turning on "Show Collision" (alt + C) in the level editor.


What if I want to use the same mesh in two places, but with different collision shapes?

You have a few options:

  1. Copy the mesh asset.
    • Pros: Fewer Components = better performance.
  2. Use additional components instead of using the Static Mesh Component's own collision.
    • Pros: Only one copy of mesh asset = smaller build size.
  3. Define all shapes on the same, single, mesh asset. Activate/deactivate them selectively at runtime.
    • Pros: Better performance and smaller build size.
    • Cons: Effort.

Option 1 might use more memory than option 2 if the mesh is complex. Option 2 might use more memory than option 1 if the mesh is simple.


What if I want to use different shapes for overlap detection vs physical collision?

UE5 collision

This can be controlled per-shape within the asset.


What if I need to know which of the shapes was hit?

UE5 screenshot

Each Shape can be given a name.

UE4 screenshot

The name of the relevant shape is provided via the Sweep Result struct.


What about Skeletal Meshes?

The same is true for Skeletal Meshes: It’s possible to add collision by attaching collision components to the Skeletal Mesh Component, but it’s better to add collision in the asset editor so that it manifests directly from the single Skeletal Mesh Component. The concept is the same, but the steps are a bit different, considering that skeletal mesh collision needs to account for movement and other additional factors.


Any differences in UE4 vs UE5?

UE5 looks a lot different on the surface, but in regards to everything discussed in this article, the only difference is that UE4's editor has one or two menus in slightly different locations.


In Summary

When authoring collision in Unreal Engine, prefer defining your collision on the mesh asset itself. Being more idiomatic to Unreal Engine’s architecture, it will facilitate better performance, and will certainly be easier to maintain if that collision is needed in more than one place.


Footnotes:

1: Transforms also exist within PhysX and other 3rd party libraries, as well as in user code, but these are not (intended to be) directly accessible by game-module code (the engine manages them such that they mimic the engine’s standard transform hierarchy).

Top comments (0)