Vertex Animation Textures - GhislainGir/BlenderGameToolsDoc GitHub Wiki
Vertex Animation Texture (VAT) is one of the simplest technique for baking skeletal animation(s) (or any animation) into textures by encoding data per vertex, per frame, in pixels. These textures are then sampled in a vertex shader to play the animation on a static mesh.
This can lead to significant performance gains, as rendering skeletal meshes is typically the most expensive way to render animated meshes. By using static meshes, you can leverage instancing and particles to efficiently render crowds, etc. This technique has its own pros and cons, which we'll discuss in this documentation.
Important
This wiki includes a technical art compendium that covers side effects and important considerations when using vertex offsets. These considerations are not specific to VAT, so they are listed on their own dedicated page, which you should probably read after this page for a more complete understanding of VATs.
For each frame and vertex, an XYZ offset is stored in the RGB channels of a unique pixel in a texture. That vertex offset indicates how much the vertex has moved from the rest pose, at that frame.
Note
You can choose to store the vertex's local position instead of an offset from a reference pose. In that case, the local position would likely need to be transformed from local to world space using the mesh's world matrix to set the vertex's position. Working with offsets is typically simpler, especially in Unreal Engine, because the vertex position is computed anyway, so you might as well just offset it.
Offsetting vertices in a vertex shader does not update the normals for various technical reasons. Thus, for each frame and vertex, it's also common to bake the XYZ vertex normal into a second VAT. This can be skipped if the animations are minimal, with little movement, and/or if you don't mind the lighting issues you get from not updating the normals (e.g. for distant props).
Important
Vertex normals are interpolated in the fragment shader and when sampling a normal VAT, it is of utmost importance to prevent this from happening, for reasons that are discussed further below. This essentially boils down to sampling the normal VAT in the vertex shader and interpolating the result in the fragment shader.
Finally, to sample the offset and normal VATs, a special UVMap is created to center each vertex on a unique texel, allowing each vertex to sample its 'dedicated' texel(s) in the VATs using this UVMap.
Playing the animation in the vertex shader thus simply involves manipulating the UV coordinates of that UVMap to sample the texels corresponding to the desired frame. Often, it simply boils down to offsetting the V component with time, assuming a one-frame-per-row packing scheme was used, more on that further below.
VAT is not meant to replace skeletal animations. The reason skeletal meshes are expensive is due to the many features they offer. For example, blending animations isn’t really possible with VAT, at least not without extra texture samples, and even then, the possibilities are very limited.
Skeletal animations allow real-time manipulation of bone data, adding physics, hand/foot IK, retargeting skeletons, complex LOD behavior, and much more. In comparison, VAT rely on a cheap vertex-shader reading baked data and inherit all the constraints that come with any baked workflow. What's baked is baked, period.
VAT can be great for crowd rendering, animating mesh particles, animated environmental props, and VFXs, but they will never replace skeletal animations. Each has its pros and cons, and like with everything else in real-time applications, it’s a matter of understanding when a specific technology shines.
The simplest way to store data in a VAT is using a one-frame-per-row packing scheme. Let's consider baking a skeletal mesh made up of 400 vertices and having 200 frames of animation. The resulting VAT resolution would be 400x200: 200 rows (frames) of 400 pixels (vertices). In other words, the VAT would contain the data of every vertex for every frame, with one frame stacked on top of another. This data could include the vertex offsets for each frame, the normals, or any other vertex attribute.
Important
This method severely limits the number of vertices that can be baked, a topic that is discussed further below.
Note
Rows (frames) can be stacked in either a top-down or bottom-up fashion; it doesn't really matter. The choice likely depends on the targeted application, as UV coordinate systems can be flipped along the V axis, depending on whether the application is OpenGL-oriented or DirectX-oriented.
Note
You could even pack frames in width and vertices in height if you prefer; you'd just need to adapt the way the texture is sampled to read the vertex data. One might wonder which method is most cache-friendly for GPUs, if any at all. For now, we'll stick with the one-frame-per-row method, as it's the most commonly used format.
Playing the animation involves sampling the texture and offsetting the V coordinate by one row/texel at a time.
Since each frame is adjacent in the texture, the pixel interpolation that naturally occurs when sampling a texture on the GPU can be used to get frame linear interpolation for free. UVs between two frames will average them, allowing the V axis to be simply scrolled to get a butter smooth animation.
Note
Most VATs won't make sense visually, as each pixel likely encodes data that well exceeds the [0:1] range, like in this case with an offset in centimeters.
Important
UVs may be stored in 16-bit floats by default in some game engines, including Unreal Engine. Thus, precision issues might arise with larger textures and undesired interpolation might occur between frames but also between vertices as well. That is something that can be partially prevented using Nearest sampling which, however, no longer allows us to leverage pixel interpolation to get frame interpolation for free. This is further discussed in later sections, as well as 32-bit UVs, which, along with Nearest sampling, further help solve precision issues.
Frame interpolation can be troublesome when baking multiple animations and looping a specific one. VATs are often used to render and animate crowds, where some kind of state machine selects and cycles through animations. Playing a specific clip in a VAT containing multiple clips merely involves clamping the V coordinate to a specific clip's range and wrapping it around when needed.
In such a case, pixel interpolation (and thus frame interpolation) can be an issue because, when looping a specific clip, we would need to interpolate between that clip's last and first frames. However, since the VAT describes the whole animation as a simple stack of frames, the last frame will instead interpolate with the first frame of the next clip, and the first frame with the last frame of the previous clip.
This can be fixed by adding extra frames to the VAT, a process we may call padding. For each clip, insert its last frame before its first, and append its first frame after its last.
While padding duplicates frames and thus slightly increases the VAT resolution, the benefits should outweigh the drawbacks. That is, assuming you do use GPU interpolation to get frame interpolation for free, else padding serves no purpose.
Note
You may choose to add padding to the last frames only or the first frames only, but that assumes you know the direction in which the V coordinates need to be scrolled to play the animation forward. This can vary depending on the UV coordinate system of the targeted game engine or graphics API, and animations may only be played in that direction.
Now, this one-frame-per-row packing scheme has its limits and there are a couple of things to note.
Firstly, it often results in non-power-of-two (NPOT) VATs. Vertex & frame count are simply unlikely to be a power of two. NPOT textures are thoroughly discussed here, and while they shouldn't cause much concern in 2025 in the context of VATs, it may still be wise to assume they may not behave like any regular POT texture.
Note
If NPOT textures are an issue, VATs can simply be padded with blank pixels to fit the next POT resolution, and the corresponding vertex-to-texel UVMap can be updated (extra padding decreases the texel size and so vertices UVs have to be re-centered on texels). Again, this is probably not something you need to worry about in 2025, but it had to be mentioned for the sake of completeness in this documentation.
Secondly, when working with VATs, exceeding 4096 pixels is generally not recommended. 8K textures may not be supported on mobile or web apps and you can't downsize a VAT like you would with, say, a troublesome diffuse or roughness texture. Each texel in a VAT holds specific information that can’t be lost or averaged with nearby texels! If you need such a high resolution anyway, one might ask if VAT is the correct method for what you have in mind. There are other baking techniques that may be better suited, like Bone Animation Textures, and newer file formats like Alembic that may be worth considering.
Finally, assuming you don’t want to exceed 4096 pixels, it obviously limits you to baking no more than 4096 frames (which is fine for most cases) and no more than 4096 vertices (which is more restrictive). An alternative packing method exists that alleviates this constraint, though it comes with its own drawbacks.
The workaround is to use multiple rows to store one frame's worth of vertex data.
Sampling the animation then involves offsetting the V coordinates by the appropriate row/texel amount. Note that pixel interpolation can no longer be used for frame interpolation, as it would partially cause interpolation with other vertex data, not the next frame. Additionally, padding becomes irrelevant since interpolation is no longer an option.
At this point, there are plenty of reasons to use Nearest sampling to prevent the GPU from interpolating pixels and instead pick the closest texel. This may be especially relevant if you bake many vertices and/or frames. As the VAT resolution increases to contain more data, the distance between each texel diminishes, potentially causing precision issues, since every vertex is purposely centered on each texel to sample that texel and that texel only.
Precision, when it comes to storing numbers in computers, is an issue as old as computer science. In fact, each vertex UV isn’t exactly centered on a texel. There’s often a slight bit of jitter, and the amount of imprecision can become concerning as the distance between texels becomes too small, or in other words, as the VAT size increases. This is especially true since UVs are typically stored as 16-bit floats by default in most game engines, including Unreal Engine. This is discussed in further detail here.
Sampling a VAT with pixel interpolation may introduce a small amount of 'data corruption', as each vertex might not precisely sample the desired frame or vertex data. Here's a visualization of four texels labeled a, b, c, and d, with a vertex initially centered on texel b. Imprecision from floating-point precision issues causes the UV to deviate slightly, resulting in the four nearest texels slightly contributing to the final sample. This issue becomes more pronounced as the VAT resolution increases, reducing the space between each texel and making the same amount of imprecision result in a greater percentage of deviation, leading to a higher amount of interpolation.
While having data from the next or previous frame participate slightly in the sample for a given frame wouldn't be the end of the world, the data from the vertex to the left or right creeping in is another story. This is really problematic because these vertices aren’t guaranteed to be neighboring vertices in the mesh, or even vertices receiving the same motion. Thus, the values encoded in neighboring texels might drastically vary, and any interpolation—even by a small amount—might result in visible corruption.
This is especially true for tools like Pivot Painter, which rely on bit-packing to encode data in a very specific way within each texel. Any interpolation, even the slightest amount, would scramble the bits and lead to complete data corruption.
Therefore, even though using GPU interpolation to achieve frame interpolation for free sounds great, Nearest sampling is often recommended, if not mandatory. This method picks the nearest texel instead of interpolating between the four nearest ones.
That said, using Nearest sampling might not even totally fix imprecision issues because of 16-bit float UVs. As you approach 4K and higher resolutions, the distance between each texel is so small that the amount of imprecision in the UVs is great enough for the GPU to pick the wrong texel for some vertices.
Here’s an example with a mesh having 4090 vertices, and thus using a 4K-wide single-frame-per-row VAT, configured to use 16-bit UVs. Nearest sampling isn’t able to resolve the interpolation issues because the wrong texels are picked!
In such case, 32-bit float UVs are required (called full precision UVs in Unreal Engine). This obviously makes the mesh use more memory and should only be enabled if you encounter an issue that you're sure is caused by 16-bit float UVs.
Note that using Nearest sampling may therefore no longer be required, thanks to UVs being much more precisely centered on each texel, greatly reducing any interpolation issues. You may thus still leverage pixel interpolation once more and get frame interpolation for free—assuming the vertex count allows you to pack one frame per row! Yay!
Note
Note that it is still possible to get frame linear interpolation despite using Nearest sampling. It simply involves sampling the VAT(s) a second time, one frame ahead and doing the interpolation in the vertex shader manually, something that shouldn't be too expensive for most applications. This could even be toggled off at a distance on LODs etc.
Note
In Unreal Engine, Nearest sampling must be enabled on a per-texture basis. To do this, double-click on a texture asset, open the 'Details' panel, go to the 'Texture' subpanel, and find the 'Filter' option, which is set to 'Default (from Texture Group)' by default.
Note
This whole precision issue might be even more complicated than it seems when you factor in 16.8 fixed point sampling, etc. GPUs are like proprietary black boxes, with the graphics API being the only thing that graphics card manufacturers are supposed to somewhat respect, at least in theory. Navigating the Vulkan, DirectX and Metal APIs to find a common ground is way beyond my expertise, so I won’t go any deeper into the topic. It's not like I'm knowledgeable enough to speak much more on it anyway (and I may actually be wrong here and there, please correct me if so).
To conclude on packing methods, there are, of course, other approaches. Here’s one more, which could be called continuous, and that best utilizes the empty pixels that you may either get with the one-frame-per-row packing scheme if requiring POT VATs, or with the multiple-rows-per-frame packing scheme.
A significant number of texels might go unused if you're not careful, especially with the multiple-rows-per-frame packing scheme. A single vertex overflow could result in an extra row of pixels with just one texel used.
The continuous packing method simply stores one frame after the other and leaves no empty pixel. Here's an example in the case of underflow.
And in the case of overflow.
This requires a more complex algorithm to generate the UVs for sampling the VATs, and is considered experimental as it still needs thorough testing to ensure it doesn’t encounter precision issues with a high frame count. On paper, this continuous packing method promises to make the most of the VAT's resolution and allows data to be tightly packed in POT textures, ensuring wide hardware support.
Sampling a continuously packed VAT involves shifting both the U and V components independently for each frame.
- The ratio of the frame size to the texture width must be computed. For example, if there are 400 vertices to bake and the VAT is 512 pixels wide (resulting in underflow), the frame width would be 400/512, or 0.78125.
- The U component is offset by
$(0.78125 * frame_i)$ . - The V component is offset by the integer part of the offset U component.
- Get rid of the integer part of the U component to get the UVs needed to sample the desired frame.
Here's a visualization of the steps described above in the case of underflow (when the vertex count is lower than the VAT width). The image shows three frames continuously stacked in the VAT, with the vertex UVs centered on each texel of the first frame, along with the necessary steps to offset the UVs to sample the second frame.
And here's a visualization in the case of overflow (when the vertex count is greater than the VAT width).
Nearest sampling is required, as the large texel offset along the U axis causes too much imprecision, and the packing scheme itself prevents frame interpolation with pixel interpolation. Again, this is an experimental packing technique, but I was able to use it with a 4K vertex mesh and around 120 frames. Use at your own risk; it's recommended to stick with the default 'stack of rows' method instead.
Note
If you're overwhelmed by the amount of information, it's best to start with the safest methods: use NPOT VATs with a one-frame-per-row packing scheme, or the multiple-rows-per-frame packing scheme if baking too many vertices; use 32-bit float UVs; use Nearest sampling if you see any glitches and linearly interpolate frames by hand if desired.
There’s one major issue to keep in mind. While sampling the offset VAT to modify the vertex position is done in the vertex shader without much complication, sampling the normal VAT to modify the vertex normal may prove to be troublesome because done in the fragment shader, also called pixel shader.
The fragment shader is responsible for computing the base color of each screen pixel by interpolating vertex attributes, including normals, UVs, and vertex colors, using barycentric coordinates to perform computation at the pixel level.
Interpolating vertex attributes works well in most cases and is not only useful but necessary to achieve smooth renders. For example, UVs are interpolated to find the correct texture coordinates for a given screen pixel, as well as normals for per-pixel lighting calculations. The following figure shows a screen made up of pixels, with a triangle drawn on it. The highlighted pixel will output a UV for texture sampling in the pixel shader, which is an interpolation of the triangle vertices' UVs using barycentric coordinates.
The normal VAT stores an XYZ normal in the RGB channels for each vertex and frame. However, while vertices may be 'assigned' to a single texel in the VAT and centered on it, they are still connected to form triangles!
Thus, when sampling the normal VAT to correct normals in the fragment shader, the sampling coordinates are computed per pixel based on the interpolated vertex UVs, resulting in UVs being positioned very arbitrarily between texels in the VAT.
This causes the pixel shader to interpolate values between texels, leading to angular discontinuities at the pixel level, as you are sampling normals tied to discrete texels instead of smooth values that can be interpolated. In other words, a mess! This is especially noticeable when using Nearest sampling, which does not interpolate between texels but instead snap to the closest texel, causing banding in the final rendered output.
The solution is to sample the normal VAT in the vertex shader, just like with the offset VAT. The sampled normal is to be stored in vertex attributes, typically as extra UVs, so the pixel shader can interpolate the normal stored in the vertex attributes, rather than interpolating the UVs in order to sample the normal VAT.
This may sound complex, but, in many game engines, it can be as simple as using custom UVs to store the normal VAT sample, or even easier in Unreal Engine by using a vertex interpolator node. Same but different. Afaik, Unity seems to offer a similar feature called 'Custom Interpolators'.
Voilà! The normal VAT is sampled in the vertex shader, and the normal is stored in the UVs for the pixel shader to interpolate.
The VAT tool lets you bake vertex animation textures using two different modes. Before we dive into those, let's quickly go over the common options and panels.
A panel called 'Mesh' lets you customize several options related to generating & exporting the baked mesh.
- Scale: Scale factor for the baked offsets/positions. This compensates for Blender's default unit (1 meter) and aligns with the target application's unit system. A default factor of 100 is used to convert from meters to centimeters, Unreal's default unit
- Invert X/Y/Z: Invert the world X/Y/Z axis (Y set to True for Unreal Engine compatibility)
- Name: Name of the baked object
-
Property: Custom property name for the retargeting feature (to bake a high-res animated mesh to a low-res mesh)
- UV|Name: Name of the UVMap to be created or used for baking mesh UVs
- UV|Invert V: Invert the V axis of the UVMap and flip the VAT texture(s) upside down. Typically True for exporting to Unreal Engine or DirectX apps, False for Unity or OpenGL apps
-
Export: Enable to export the generated mesh to an FBX file upon bake completion
- Export|Name: Name for the exported FBX file (without the .fbx extension). is a placeholder tag that can be used to be replaced with the object's name
- Export|Path: File path for the exported FBX, excluding the file name. The path is relative to the Blender file if saved, or absolute otherwise
- Export|Advanced|Override: Enable to override any existing .fbx file
A panel called 'Textures' lets you customize several options related to generating and exporting the offset and/or normal VATs.
- Max Width: Maximum allowed texture width. Exceeding this may cancel the bake due to an excess of vertices or frames
- Max Height: Maximum allowed texture height. Exceeding this may cancel the bake due to an excess of vertices or frames
- Power of Two: Force textures to be power-of-two sizes. Not recommended, as non-power-of-two textures ensure tight packing and are widely supported. May lead to overflow issues when vertices exceed the image width, resulting in multiple rows per frame. Extra space handling can be controlled with the 'Stack Mode' option
- Square: Force texture width and height to be equal if 'Power of Two' is enabled. Typically unnecessary, but provided as an option for specific use cases. Extra space handling can be controlled with the 'Stack Mode' option
- Stack Mode: Control how frames are arranged in the texture when there’s extra space (underflow) or not enough space (overflow). Underflow occurs when the number of vertices per frame is less than the image width, causing gaps at the end of the line ('Power of Two' might cause this). Overflow happens when there are too many vertices for a single line, and the data is spread across multiple lines, possibly leaving gaps. This setting determines how to handle these empty spaces
-
Offsets: Enable to bake the vertex offset texture
- Offsets|Tex Mode: Select the positional data to store in the texture: offset (recommended) or local position
- Offsets|Filename: Name for the vertex offset texture file (without the .exr extension)
- Offsets|Remap: Enable to remap the offsets within a [0:1] range. This requires a multiplier and bias to remap the offsets in your shader or game engine. It is NOT recommended unless you intend to experiment with storing positions/offsets in 8-bit RGBA textures, as this will likely result in significant precision loss and visible deformation. Proceed at your own risk
-
Normals: Enable to bake the vertex normal texture
- Normals|Filename: Name for the vertex normal texture file (without the .exr extension)
- Normals|Remap: Enable to remap the normals within a [0:1] range. This requires a constant bias to remap the normals in your shader or game engine. It is likely safe to do so, as normal VAT may be stored in an 8-bit RGBA texture without noticeable precision loss
-
Export: Enable to export the generated textures to an EXR file upon bake completion
-
Export|Path: Texture file path, excluding the file name. The path is relative to the Blender file if saved, or absolute otherwise
- Export|Advanced|Override: Enable to override any existing .exr file
-
Export|Path: Texture file path, excluding the file name. The path is relative to the Blender file if saved, or absolute otherwise
A panel called 'XML' lets you customize the export options for the XML file.
-
Export: Enable to export an XML file containing information about the bake process (recommended)
-
Export|Mode: Select how the XML file name and path are generated
- Mesh Path: Use the same FBX file name and path for the XML file. Defaults to 'Custom' if mesh is not exported
- Custom Path: Specify a custom XML file name and path
- Export|Filename: Name for the exported XML file (without the .xml extension)
- Export|Path: Path for the exported XML file, excluding the file name. The path is relative to the Blender file if saved, or absolute otherwise
- Export|Override: Enable to override any existing .xml file
-
Export|Mode: Select how the XML file name and path are generated
As the name implies, the 'Mesh Sequence' bake mode assumes that the vertex animation will be derived from a list of meshes, with the frame count determined by the number of meshes.
Important
These meshes must be exact duplicates, with the same topology—meaning the same vertex count and vertex order. As long as this single constraint is met, the meshes can be deformed using any technique you choose.
This technique only supports the baking of a single mesh, as selecting multiple objects will be used to construct the mesh sequence. Object names will be used to alphabetically sort the meshes and order the frame list.
The second bake mode, called 'Animation,' allows you to bake vertex animation textures from animation data. Whether the mesh is keyframed, animated using an armature modifier, or deformed by shape keys, it doesn't matter. You simply need to specify a start and end frame—or let the tool automatically decide, if possible—and the bake should perfectly capture the movement of the vertices you see when scrubbing the timeline within that range.
Baking multiple objects at once is supported and will result in a single unified mesh.
Selecting this mode will reveal an additional panel called 'Frames', where you can customize how the frame range and reference frame are set.
- The NLA mode allows the tool to automatically derive the animation range based on the NLA tracks of the selected objects.
- The Scene mode uses the scene’s current frame settings: start, end, and step.
- The Custom mode lets you specify a custom animation range and step.
Not much needs to be said about the Scene and Custom modes, but the NLA mode offers additional features and comes with extra constraints.
When using the NLA mode, objects must meet certain constraints to be included in the bake. They must either:
- Have an NLA track
- Be parented to an object with an NLA track
- Have an armature modifier that points to an armature with an NLA track
Needless to say, the NLA track must contain NLA strips.
The NLA mode also allows you to add padding in between clips. It also allows you to specify a list of NLA clips to exclude when determining the frame range. This can be useful when using the retargeting feature (more on that further below) and needing to provide a single-frame T-Pose clip as the reference pose, a clip that would otherwise need to be excluded from the bake.
Also, when using the NLA mode, the step setting may be applied differently:
- Global: Bakes every nth frame across the entire animation
- NLA Clip: Bakes every nth frame, starting from the start frame of each clip. This can lead to unexpected results if the objects don’t all have the same NLA track
Important
Clips that are looping should likely be clipped to remove the duplicated start and end frames. It’s also recommended to separate each clip by one frame; otherwise, the end frame of one clip will be replaced by the start frame of the next.
Warning
When baking multiple objects, it’s highly recommended to ensure all objects share the same animation. While using different NLA strips in different orders on different objects is partially supported, it may cause issues with all the features listed above (stepping, padding, clip exclusion. The resulting VAT will also likely be unusable with state machines, as you won’t be able to select a specific clip for a particular object: the animation will be baked, and multiple clips will play at once, probably making the VAT less versatile.
Note
NLA tracks will be scanned regardless of the mode used in order to extract animation information that may be useful when baking a VAT for use in a state machine. It may be important to know when each NLA clip starts and ends, etc. Note that their start/end range will be clamped to the specified start/end. This has no impact on the bake whatsoever and is purely informative.
Important
You may adjust Blender's scene frame rate settings and scale your animations to baking smoother animations (at the cost of baking more frames, resulting in heavier VATs).
This feature, exposed when baking an ‘Animation’, allows the animation of a single high-res mesh to be baked into a vertex animation based on a low-res mesh. While this may result in approximations or undesired outcomes, it can be very useful for generating LODs, simplifying a mesh, etc.
Multiple high-res objects can target multiple low-res objects, but each pair must be unique. A low-res object cannot be targeted by multiple high-res objects.
This must be enabled on a per-object basis. Simply add a custom object property called 'BakeTarget' to the high-res object and make it point to the desired low-res object. The 'BakeTarget' custom property name can be changed in the Vertex Animation panel, Mesh > Property.
Important
If you need multiple high-res objects to target the same low-res object (e.g. a single low-res character originally made of multiple high-res meshes), you will need to merge the high-res meshes into a single mesh. This may require some manipulation with modifiers etc., but there is no workaround.
The retargeting feature relies on a mapping process that aims to associate each vertex of the low poly mesh with the nearest surface point on the high-res mesh. To achieve the most efficient mapping, you'll want to choose a frame with the fewest intersections, such as a T-Pose. This can be done by setting the reference frame mode to Custom and specifying a custom frame.
Note
This reference frame will be used for the mapping process and will also affect the generated static mesh, which will be posed as seen in that frame. This is unlikely to be an issue.
Of course, most animations you want to bake into a VAT won’t include a T-Pose. However, you can add a single-frame T-Pose NLA clip outside the bake range. That said, when using the NLA mode, the range is automatically derived from the NLA clips, so the T-Pose clip will be included. It can, however, be excluded using an exclusion list as shown below.
Retargeting successful!
Baking simulated cloth and similar effects is completely possible. In fact, if the mesh moves while you're scrubbing through the animation timeline, the bake should accurately capture the visible motion. However, in this case, you won’t be working with NLA clips, so you’ll need to set a frame range—either manually or based on the scene’s settings—then select the desired object(s) and press Bake. Voilà!
The bake should produce a new mesh object and at least one VAT image saved within the Blender file.
It’s a good idea to check the generated mesh’s vertex-to-texel UVMap to ensure you have the correct context to work with. Are the frames stacked in a single row or multiple rows? Was that the expected result? etc.
Important
This feature is disabled for now, as handling all possible bake options is really painful to implement and very time consuming.
The generated mesh includes a GeoNode modifier to automatically preview the baked offsets and normals directly in Blender. Just scrub the timeline within the baked frame range.
Note
The node graph for sampling a continuously-packed VAT is different from the one used to sample a VAT with frames stacked per row. Let the tool handle the GeoNode modifier.
Important
Adding padding will naturally desync the baked animation from the viewport's animation.
Simply import the .fbx into your game engine. In Unreal Engine, you may want to check the following import options.
Note
If it wasn’t automatically exported, you’ll need to manually export the generated mesh to .fbx. Blender’s default export settings should work fine.
You'll also probably want to tweak the mesh's bounds using the info stated in the 'report' panel and/or XML file.
Important
Special care must be taken when reading the offset value. In this case, the Blender scene was incorrectly set to use centimeters as the default unit, while the scale factor was still set to 100, assuming a meter-to-centimeter conversion. This means all values must be divided by 100 in this case.
Simply import the .exr offset and normal VATs into your game engine.
The offset .exr may be encoded in:
- uncompressed RGBA8: extremely unlikely, unless you want to experiment with it (will require remapping and bias).
- uncompressed 16-bit HDR: could result in slightly approximated offsets (probably good enough).
- uncompressed 32-bit HDR: safest choice, though it comes with a higher memory footprint.
The normal .exr may be encoded in:
- uncompressed RGBA8: could lead to slightly approximated normals.
- uncompressed 16-bit HDR: safe option (higher memory footprint).
- uncompressed 32-bit HDR: safest option but probably overkill to store normals (highest memory footprint).
Note
If the textures weren’t automatically exported, you’ll need to manually export them as .exr using the following settings.
The filter options will likely need to be set to Nearest, except in a few cases where pixel interpolation can be used without artifacts to achieve frame interpolation for free, as thoroughly discussed in this article.
Once a bake is attempted, a report panel will appear in the Vertex Animation panel, providing valuable insights into the baked information.
- Export: Exports the report to an XML file following the XML export settings.
- Clear: Clears the report. This may be useful as the report holds pointers to the baked object(s), which will make them persist in the Blender file even though they are later deleted.
This panel provides global information about the bake that won’t be covered in detail in this documentation to avoid unnecessary clutter, as most of the information should be self-explanatory. However, there are a few things worth mentioning.
The 'Textures' subpanel provides valuable information about whether the offset and/or normal VATs were remapped, along with the remapping multiplier (which is not displayed for the normal VAT because it defaults to 1.0 for normals).
The 'Mesh' subpanel provides information about the UV map used and whether the V axis is inverted (to match DirectX orientation). It also gives important details about the maximum VAT offset that can be used to offset the mesh bounds and avoid occlusion issues. Be cautious about unit conversion here, as this depends on the specified bake scale factor and the Blender scene unit system configuration.
The 'Anims' subpanel summarizes the animations that were baked. This is only relevant when baking an 'Animation' (as opposed to a mesh sequence) IF 'NLA' mode was used, OR IF any NLA animation strips were found within the specified frame range. Since the same NLA animation strip may be used on multiple objects, each animation also lists the associated object(s) and whether those objects used the 'retargeting' feature. This list may be useful for a state machine, etc.
The 'Frames' subpanel provides a summary of various frame settings, packing mode (!), padding, frame width (for continuous packing), frame height (for row packing), etc.
Finally, the 'Unit' subpanel summarizes the world-space coordinate system used for the bake, which is crucial when using the VATs in the targeted application. If something goes wrong, there's a high probability that a wrong unit is the cause!
Important
The report keeps track of generated images and meshes, which means these resources will always have at least one user. As a result, they won’t be removed from the scene, even if they’ve actually been deleted. This might lead to a new baked mesh being prefixed with '.001'. To fix this, clear the report and purge unused data.
The report can be exported to XML, which may potentially be used to automate the import process in a game engine through a custom importer that parses this file.
Many things can go south with VATs. Here are some things to look out for.
- Double-check that the differences between Blender’s coordinate systems and those of your target application have been properly accounted for:
- Blender’s world axes are +X+Y+Z, while Unreal Engine’s world axes are +X-Y+Z.
- Blender uses OpenGL, meaning UV(0.0) is at the bottom-left corner, whereas Unreal Engine uses DirectX, where UV(0,0) is at the top-left corner.
- Blender’s default unit is 1 meter (though it can be adjusted), while Unreal Engine’s default unit is 1 centimeter, so a scale factor may need to be applied.
- Try 32-bit UVs in your targeted application if you think the issue you experience is related to 16-bit UVs imprecision.
- Double check the texture compression settings in your targeted application. Try uncompressed 32-bit HDR textures first, then see if 16-bit HDR textures lead to no visible differences. RGBA8 may be an option if you know what you're doing.
- Double check the texture sampling settings in your targeted application. Nearest sampling is almost always recommended if not mandatory. Use linear pixel interpolation at your own risk.
- Double check the generated mesh VAT UVs are laid out as expected and that you do sample the VAT texture according to the packing mode. Single-row-per-frame or Multiple-row-per-frame. Continuous packing mode is considered experimental, use at your own risk.
- Ensure VAT UVs are not overriden in your targeted application by lightmap UVs or any other process automated during mesh import.
- Disable any geometry-related optimization features in your game engine initially. This includes virtualized geometry systems like UE's Nanite, which may need to be deactivated both project-wide and on a per-asset basis.
- Triangulation during export may unexpectedly recompute vertex normals, something to always keep in mind. It’s usually best to triangulate the mesh beforehand, before starting any baking processes.
The VAT tool's configuration and settings can be saved as a preset, which can be easily applied with a single click at any time. Presets can be added or removed using the button located to the right of the VAT tool header.
This feature uses Blender's internal preset system, which creates Python files to store all the necessary data. These files are stored in the following directories:
- Windows: C:\Users\<your username>\AppData\Roaming\Blender Foundation\Blender\<version number>\scripts\presets\operator\databaker_vat\
- MAC: Library\Application Support\Blender\<version number>\scripts\presets\operator\databaker_vat\
- Linux: ~/.config/blender/<version number>/scripts/presets/operator/databaker_vat/
Warning
Preset .py files can be copied, pasted, and shared across different computers. However, only install presets from trusted sources, as these files can execute malicious Python code on your machine.