UDN
Search public documentation:

MotionBlurSkinning
日本語訳
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 Home > Post Process Effects > MotionBlur Skinning Post Process Feature
UE3 Home > Cinematic Artist > MotionBlur Skinning Post Process Feature

MotionBlur Skinning Post Process Feature


3small.png
Body parts moving in different directions show different motion blur direction and strength.

Overview


Recommended read: MotionBlur

Before implementing the motion blur skinning we only supported rigid motion blur based on camera and object motion (translation, rotation, scale). Skinned meshes derived the object motion from the root of the object which can be a good approximation for simple objects but not for characters. There different parts of the body move in different directions and that requires a more sophisticated method.

PerBoneMotionBlur.jpg
Left: feature off
Middle: feature on
Right: Per pixel velocity shown as color.

Skinned motion blur requires some extra CPU and GPU performance and has some extra memory cost. Because of that is should be used only where needed. For all other objects rigid skinned motion blur is still available.

Activate the feature


If supported by the platform (see later section about this topic) it can be activated by the ini setting "MotionBlurSkinning" that can be found in "BaseEngine.ini" or later at runtime with the "MotionBlurSkinning" console command.

The number specified in the ini setting is the same that is used by the console command. It not only allows to switch the feature on (1) or off (0) but also to override the per object flag to force it for all objects (2). The current state and some help can be seen when using the console command without extra parameters:

ConsoleMotionBlurSkinning.jpg
Response when using the MotionBlurSkinning console command.

Setting the SkeletalMesh flag


The flag is called bPerBoneMotionBlur and can be set by code (e.g. UnrealScript) or when placing an object in the level.

editorflag.jpg

Implementation


Skinned motion blur is outputting the per pixel motion vector into the velocity texture (currently black for the camera motion, color for object motion, more details: MotionBlur). After rendering all velocities the following steps don't see any difference between rigid motion blur or skinned motion blur.

We store all the bone data for all objects used in the frame in a texture for use in the next frame. This means we always need two textures as we read from one (GPU) and write to one (CPU) at the same frame. This minimizes the texture lock count. Changing the engine to use triple buffering someone might have to add another buffer to this chain.

It would have been possible to implement the feature with vertex shader constants but because there is a limit of those constants we have a challenge to get the data into the shader. The GPU skinning is already using almost all constants and for skinned motion blur we require the double amount (we need both the current bone matrix and the former one). Packing the data might be an option (e.g. quaternion + scale + position) but not without further complications. Splitting the draw calls into chunks of half the bone count would be another way of solving the problem but that is likely to slow down render performance for other passes and adds more complications to the content preparation (cooking / importing).

We decided to implemented the skinned motion blur by using "vertex texture fetch". This GPU feature is not support on all hardware, in particular earlier ShaderModel 3.0 hardware (AMD/ATI) doesn't support that.

We update the textures with the bone data from the CPU. For good texture cache performance we use a 1D texture.

We split the mesh into chunks to respect the limited bone count (limited vertex shader constants) and to split the mesh by materials.

Bones can appear duplicated as we use the per chunk index and that indexes into a subset of the bones.

Limited bone count

As we use a 1D texture to store the bone data there are limits on the bone count. We currently use a 4096 wide texture and need to store 3 texels per bone. Use the stat SceneUpdate command to see if this limit affects you. We do motion blur only for nearby objects and with the bone count we use we haven't seen this being an issue. Note that motion blur for facial animation often doesn't require the MotionBlurSkinning feature.

Shader permutation

We tried to avoid the shader permutation for having skinned motion blur and not having it. This was mostly to keep code complexity low but also to have less shaders in general. We decided to use static branching (compare on bool shader constant) as this solves the problem and is optimized out by the driver.

On Xbox360 we use static branching to avoid a shader permutation. We verified, this is as fast as compiled out. Other platforms don't make use of this yet (see Optimizations section).

Performance


CPU data update

The CPU cost of skinned motion blur is not high as the data from former frames is stored and reused for the following frame. The texture lock operation should not stall as we only double buffer but to make sure we have a stat on this. By using the console command stat SceneUpdate you can look at this number.

StatSceneUpdate.jpg
The statistics show the CPU time for the lock and the amount of bones that have been updated.

More draw calls

Motion blurred object need to be rendered in the velocity rendering pass (to store the per pixel motion vector). For non skinned motion blur we only need to do this if there is object motion. To test if a skinned object has no motion we would need to check much more data. We don't do this optimization yet. It can be done but it won't help the worst case of many moving object.

That means when enabling the skinned motion blur for an object that was not moving (e.g. bot not moving) it now needs to be rendered and that adds more draw calls.

Vertex texture fetch GPU cost

The current method requires 12 vertex texture fetches into a very big vertex format (4 floats for one bone 4x3 matrix, 4 bones for skinning). This means the more vertices need to be rendered this way the slower it renders. Only nearby objects get rendered this way (velocity rendering pass) so the render cost might peak up with a lot of nearby action.

When profiling the velocity rendering pass on Xbox360 (dense triangle meshes with morph) we noticed the rendering being 60% slower than with rigid motion blur (all objects moved and therefore rendering cannot be skipped).

Memory


The memory occupied by the feature is constant as the two textures that store the data have a fixed size. This avoids reallocations performance loss and memory fragmentation. In order to see how much memory is occupied we track this memory. You can look at the data by using the stat memory console command:

StatMemory.jpg

Support on different platforms


Our implementation is based on the vertex texture fetch which is not available on all GPUs. We currently support skinned motion blur on Direct3D 9 (if hardware supports it) and on Xbox360. Adding support for Playstation 3 should be simple but is expected to be too slow (assuming texture fetch implementation and high vertex count). Future DirectX version will be supported at a later stage. Support for mobile hardware is currently not planned (performance reasons).

If not supported the engine automatically utilizes rigid skinned motion blur instead.

Optimizations:


  • On Xbox360 the "vfetch" feature can be used instead of the vertex texture fetch.
  • We could do less than 4 bone lookups per vertex (degrades quality but might be acceptable).
  • We could check the bPerBoneMotionBlur at runtime to allow game code to disable when it knows the objects is not moving (Simple but requires effort on game code to be useful).
  • Utilize static branching on PC and Playstation 3. We have an engine bug that prevents us from using that. As a workaround we check the state of a float to disable the feature (means even non skinned objects pay the cost of the heavy shader in the velocity rendering pass).
  • We currently lock the whole texture even if only part of it is used.
  • Test if velocity rendering is needed by comparing all bones against the former ones.

Useful console commands


MotionBlurSkinning
as described above