Quick Start

Last updated: June 20, 2020

Download

There are multiple downloads for the RuntimeMeshComponent, depending on the Unreal Engine version you’re using.

  Download v4.1 for UE 4.23+ (Current)

  Download v4 for UE 4.20+

  Download current examples project for UE4.23+

Installation

Installation from Marketplace

 

Unreal Marketplace Version Out of Date

The current version of the RMC on the marketplace is quite old. This will be updated shortly as v4 is stabilized!

This section coming soon, once it actually makes sense to write it!

Installation from GitHub

  1. You will need to start with a code project. This does mean you’ll need all the build dependencies necessary to create c++ projects in Unreal. However this doesn’t mean you’ll need to use C++ at all, just that the engine needs to be able to build the plugin. To turn a blueprint project into a code project, you can go to “Add New C++ Class” in the editor and it should set everything up for you!

  2. You can download the RMC from one of the links above.

  3. Navigate to your project folder, and assuming the folder doesn’t already exist, create a ‘Plugins’ folder in the root of your project.

  4. Within the plugins folder create a folder called RuntimeMeshComponent and copy the contents of the version you downloaded into this folder, making sure not to nest subfolders, all the files/folders in the directory of the .uplugin file should be in your newly created /Plugins/RuntimeMeshComponent folder.

  5. At this point you should be able to relaunch the project and the editor should detect the new plugin and compile it for you!

  6. You should be able to start using the RMC!

Using RMC From Code

  1. To make the RMC available in your C++ project, you must first install it from either the marketplace or GitHub as described above.

  2. Next, in your projects build file ‘YourProjectName.Build.cs’ you must add this line:

     PublicDependencyModuleNames.Add("RuntimeMeshComponent");
    
  3. Now you should be able to #include the headers like any other plugin and use the RMC from C++!

Using RMC from Blueprint

Using it from Blueprint isn’t recommended as creating meshes relies on lots of small operations, and BP has fixed time cost per operation. This means that, when using it from BP, generating meshes will often hang the engine. We recommend making the provider in C++, then giving it the data it needs through BP if you really want to, so that all of the generation can be both multithreaded and done in C++, while keeping the data logic in BP.

To install, do just like the previous section.

Mesh Basics

How Meshes are Represented

Meshes are represented through a vertex buffer and index buffer. These work in tandem to represent a mesh. The vertex buffer contains a list of all the unique vertices in the mesh, including their position, normal, tangent, color and texture coordinates. The index buffer, in the case of the RMC is in the form of a triangle list. This is laid out as a contiguous list of indices into the vertex buffer 3 at a time representing the 3 points of a triangle.

Mesh Structure Example

Representation of a triangle and it's arrays

Vertex Buffer Layout

The vertex buffer is a list of vertices with all its corresponding data for all the unique vertices in the mesh. There are several options, which can affect the memory consumption, rendering performance, and visual quality of the mesh.

The elements of the vertex buffer are:

  1. Position: This contains the position in local space of the vertex of this mesh. This is a FVector as it contains a (X, Y, Z) position.
  2. Normal/Tangent: This contains the normal and tangent at this vertex and is used for lighting information and materials. Normals can be in either normal or high precision format. High precision correllates to the high precision tangents of the engine, so this option is really only useful when the engine is configured to use high precision tangents. The size of the tangents in memory is either 8 bytes for normal position, or 16 bytes for the high precision. Normals point up from the triangle towards the camera when the triangle is visible, and tangents point towards the increasing U coordinate of the UV. Cotangents can be calculated from that and point towards the increasing V coordinate of the UV. These also determine if you have hard shading (where you can see individual triangles) or soft shading (usually used). For hard shading, each vertex of the tris needs to have the normal of the tris, so that means your vertex buffer is around the same length as the index buffer.
  3. Color: This contains a single color value for this vertex, it is up to the material if and how this is used. It can be for vertex painting, or just passing through extra data to the material for other effects. This is always represented as FColor, which contains a 4 bytes B, G, R, A, value.
  4. Texture Coordinates: Within UE, the mesh can have 1 to 8 channels of texture coordinates, most meshes will only use 1, but you can have all the way up to 8. Beware : most of the time UV 2 is used for lightmaps, so you’ll need to configure that correctly. There’s 2 options here, one is a channel count and the other is a normal/high precision UV’s. The datatype switches between FVector2DHalf and FVector2D for normal vs high precision. This means it uses either 4 or 8 bytes of memory per channel, so the texture coordinates can range in memory from 4 bytes for a single channel normal precision up to 64 bytes for all 8 channels in high precision.

Depending on the configuration above, the total vertex size can range from 28 bytes for a normal precision tangents, normal precision texcoord single channel, to as much as 96 bytes for all high precision components with 8 texture coordinate channels.

Index Buffer Layout

The index buffer is meant to map the vertices into triangles. Within the RMC this takes the form of a triangle list, so indices will be in groups of 3 one after the other to define the 3 points of each triangle, each group of 3 is separate from the others and has no dependence on the others. With that said though order of the vertices within the triangle does matter for culling (See Winding Order below), and order of triangles within the buffer can have performance effects through things like cache coherency, locality, transform cache, and overdraw.

The index buffer can be either a 16 bit integer, or 32 bit integer per element, so it will consume 2 to 4 bytes per element. 16 bit integer is the default as it can handle meshes of up to 2^16 or 65,536 vertices.

Winding Order

Winding order refers to the order the vertices are reference for the triangle, this is important as one of the most common ways of improving performance is through backface culling. This works by looking at the direction the triangle wraps to detect if it’s a front or backface, and if it is found to be a backface then the triangle will get culled in hardware. By default Unreal Engine uses ClockWise Culling, so you should make the order of the vertices when referenced in the index list wrap Counter-ClockWise when viewed from the visible side.

It is possible to disable backface culling in Unreal by using two sided materials. If your mesh appears to render inside out, then you need to reverse the winding order.

Mesh Hierarchy/LOD

Each RuntimeMeshComponent can have 1-8 Levels of Detail or LODs, each of which can have any number of sections. Each LOD is separate from the others, and so can have different numbers of sections and different materials bound to those sections.

Each LOD has a ScreenSize associated to it. This is the percent of the screen the bounding volume has to cover before this LOD is rendered.

Material Slots

Unlike the ProceduralMeshComponent and old RMC, materials are handled similarly to how StaticMesh handles them. URuntimeMesh holds a number of material slots, setup by SetupMaterialSlot, each has a index, name, and material. You can find these slots by index or name. Each mesh section can be assigned to any slot.

The RuntimeMeshComponent, like the StaticMeshComponent, has override materials (which was how RMC and PMC previously handled materials). These materials override the slots by index, and allow different components to bind different materials even when they share the same underlying mesh data.

Collision

Collision in the RMC has a few different parts, including basic settings and two collision types each of which has its own benefits and limitations.

Simple Collision

Simple collision is made up of Boxes, Spheres, Cylinders, and Convex Elements. These are the basis of simple collision, which is required for movable objects that can interact with the environment and perform overlap tests. These are all convex shapes, as concave collision detection is far more complex. You can have none, one, or multiple of each of these 4 shapes, but you must have at least one to have any form of simple collision/physics simulation. Convex means that any line between two points belonging in the volume belongs to the volume.

Convex Elements are a convex mesh object. These can be generated directly by you, or possibly through a process known as convex decomposition where you take a source mesh and generate one or more convex shapes to represent it. This is how UE4 handles arbitrary shapes for collision. Convex elements are slower to compute than other primitives, and are limited to 256 vertices.

Note : Collisions don’t have to be perfect, since the primitives are invisible. Sacrificing accuracy for performance is alright : Avoid using convexes.

Complex collision

Complex collision is made from a triangular mesh. This can be either from your renderable mesh data, or a custom simplified mesh for collision. Usually the latter is better for collision performance, but takes extra effort to generate. No two complex collision shapes can perform collision tests, so complex collision only objects are not allowed to simulate physics. Having a line trace set to complex will return the complex collision mesh’s triangle index on hit.

Settings

The collision settings object is used to set the simple collision shapes, as well as some basic collision cooking settings.

Collision Cooking is required for convex elements and complex mesh. This process builds internal structures for performing high performance collision, but it takes a non-trivial amount of time to perform this collision on complex meshes. With this the RMC supports Async Cooking which can be turned on or off through the flag bUseAsyncCooking.

Complex as simple collision is where you have no simple collision for a shape and let the complex collision be used for things such as line tracing which would normally use the simple collision. This setting is controlled by bUseComplexAsSimple on the collision settings object.

CookingMode can be set to either CollisionPerformance or CookingPerformance. The first prioritizes efficient collision detection at the cost of a little more effort in cooking to build optimal collision structures. The second prioritizes quickly cooking meshes over having optimal collision structures.

Component Structure

The Runtime Mesh Component is made up of several distinct parts, each of which provides a portion of the overal system. Together the combination can be very extensible, or very simple. If you’re familiar with how UStaticMesh and UStaticMeshComponent works, this will be very similar with a couple extra pieces.

URuntimeMeshComponent

URuntimeMeshComponent is the main component that allows you to place a URuntimeMesh in the scene and interact with it exactly like UStaticMeshComponent. It’s possible to have multiple URuntimeMeshComponents all sharing a single URuntimeMesh, this means that a single copy of the gpu buffers can be shared among several individual components that all can act independently while drawing the same mesh. This is not the same as instancing which draws multiple copies of the mesh at different locations/rotations within the same component, but they all function together.

URuntimeMesh

URuntimeMesh is the data carrier component. It is responsible for owning the GPU buffers, and the physics object that can then be used by one or more URuntimeMeshComponent’s. When you update the mesh data of a URuntimeMesh all the linked URuntimeMeshComponents will receive the mesh update together and they will all start rendering the new mesh. The URuntimeMesh DOES NOT store any mesh data in main memory, it simply copies it out to gpu memory (VRAM) and then destroys its cpu side copy. For collision it will pass the data to PhysX/Chaos and once the cooked collision shapes are created then it also removes the copy of the raw mesh data for collision as it’s no longer necessary. It relies on the URuntimeMeshProvider to get any of this data again if it needs it.

URuntimeMeshProvider

URuntimeMeshProvider is the base class for the provider system. The provider system is how a URuntimeMesh gets the configuration, renderable mesh data, and collision settings/data. URuntimeMeshProviders’ are composable so they can be chained together. For example if you create your own provider that only generates the renderable data, then you can use URuntimeMeshProviderCollision with it to generate the collision data from your rendering data. A URuntimeMesh must have a valid URuntimeMeshProvider to function, but that provider can be either a single provider or a chain of providers. This will in the future also allow the RMC to decide when to generate additional LODs instead of having to create them all upfront as you do now.

URuntimeMeshProviderPassthrough

URuntimeMeshProviderPassthrough is a base class for pass through providers. These work by linking one or more providers to them and doing internal logic on the returned results from the linked providers before passing the result on to the URuntimeMesh.

URuntimeMeshModifier

URuntimeMeshModifier is the base class for the modifier systems. Some providers support applying generic modifiers to them that can modify the mesh data as it passes through the provider. These are allowed to do things such as clean mesh data, or generate the extra index buffers, but they’re not allowed to generate mesh data directly, that is up to the provider. These are simply for common functionality that you’d rather not implement yourself. There is a URuntimeMeshProviderModifiers that can be placed between your provider and the URuntimeMesh to apply these, and the URuntimeMeshProviderStatic has a built in modifier support.