Take an animation that changes the vertices of a mesh and export it as a vertex animation texture file for use in the vertex shaders found in game engines like Godot and Unreal.
The script runs in 2 stages for LDR VAT image creation.
First run determines the largest motion in the vertex animations to determine the minimum points and range of motion that will be scaled to fit into the color representation of the movements.
The second run reads the vertex positions and fits them into the previously calculated range.
After the second stage is complete the position and normals animation textures are saved and a new mesh will exist in the scene setup to preview the animation and ready for export.
HDR image generation runs in 1 stage because scale and offsets are not needed.
Controls
Relative Motion - animation will be defined relative to individual vertex minimum XYZ values and maximum change in XYZ for all vertices.
It works by creating an altered version of the mesh that maximizes the use of the color values to give higher resolution motions.
When unchecked the mesh is not altered and the animation will be based on the bounding box minimum and maximum values.
The RGB values are limited to 256 values each, so small motions can be clunky as they jump between the limited number of values.
Relative Reference Pose - creates difference texture data based on the original shape of the mesh.
This option creates textures in a format where animations can be combined together in the shader.
It creates 2 textures for LDR images. One for positive and one for negative value changes.
For HDR image a single image with positive and negative values is created.
HDR Image Generation - when enabled the position texture will be saved as a float value exr image.
When unchecked the position texture will be a saved as a png format file.
'Metadata' Rename - the VAT Data node will be renamed to "Metadata" so the information from the node will be included in an fbx export of the mesh.
Texture Base name - this name is used in the naming of the position and normals animation textures.
Below shows naming samples assuming a base name of "AnimTexture"
VAT_Delta_AnimTexture_P.png - "Delta" means Relative Motion and "P" means positions
VAT_AnimTexture_N.png - "N" at the end means normals, the normals are calculated the same for both types of motion. So there is no BBox or Delta signifiers.
VAT_BBox_AnimTexture_P.png - "BBox" means use the extents of the bounding box over the course of the animation.
Relative Motion is unchecked.
VAT_BBox_AnimTexture_P.exr - hdr image is generated. EXR export does not use BBox despite the naming. The normals animation texture is always generated as a png file.
Run - execute the script. The anticipated result of the run will show in the information section below the run button.
First Frame Ref. Pose - the first animation frame vertex positions will be included in the bounding box limits of the animation
The actual animation will start on the next frame.
Relative Reference Pose is the most flexible option for VAT exports. Non-HDR will be limited to the 256 values of one direction positive or negative.
So if the mesh is centered in the animation the range of values would be close to 512. Texture file will have "Ref_" as part of the name.
Relative Motion gives best results inside of trueSpace. This is especially true for small motions.
Relative Motion will add "Delta" to the texture file name. Unchecked will add "BBox" to the name.
This option will be disabled if Relative Reference Pose or HDR options are used.
The thinking behind the First Frame Ref Pose is that the mesh can be exported with it's original shape.
and any other animations exported will work with that shape. Relative Motion can only be used with the shape generated by the Relative Motion process.
The First Frame Ref Pose option does not always work with the Relative Motion option.
This option, First Frame Ref Pose, may be deprecated with the creation of the Relative Reference Pose.
HDR will export an exr image and create an 8 bit image internally for tS visualization.
Usage:
Be sure the object uses compound d3d materials and they are not scene instanced. material converter refers to compound materials as "D3D" materials
Name the materials for a better import result later and to avoid other material issues.
Animate the object using vertex morphs, skeleton or deformations.
note: cyclic animation repeat the first keyframe at the end before conversion
If the First Frame Ref. Pose is used, create a keyframe 1 frame before the first frame of animation to define it.
Set the interpolation to linear to prevent overshoot in the animation.
Select the object and set the play range of the animation in the Anim view.
Open the Vertex Animation Texture Tool and set a base name for the textures
Press Run and choose the folder for the files.
The texture files will be generated and saved and a new mesh object will be setup to use the textures.
The new object will have a VAT Data or Metadata node inside that shows the scale and offset values needed for the vertex animation shader.
The new object will have UV set 2 setup for the animation.
Export the new mesh to a format the desired game engine can read
Use the values for scale, num frames, and offsets in the custom vertex shader
note the folder dialog will remember the last selected location, but may not scroll to it when opened.
TODO
Godot, only 2 uvs allowed so no lighting?
"combined" VAT shader for UE and Godot - combine vat anims from code
"multiple" VAT shader for UE and Godot - 1 vat many anims
add comments to unreal and godot materials
test webxr with exr format image vat
Cloth Conversion utility can be used to export a cloth animation as a vertex color animation.
Relative Reference Pose - GodotPositionCode_RelRefLDR.txt. Note: 2 position VATs used
(HDR)Not Relative, Not Relative Reference Pose - GodotPositionCode_BBoxHDR.txt
Not Relative, Not Relative Reference Pose - GodotPositionCode_BBoxLDR.txt
Import GLTF to Godot
create a new folder inside the godot project filesystem to receive the imports
import textures
import gltf and glb together
double click the imported gltf
upper left Actions... > Extract Materials. place materials in the folder
Actions... > Set Mesh Save Paths
Reimport and a new xxx_mesh.res file will be created in the folder
right click gltf > new inherited scene
select the mesh in the scene
Cleanup any vertex colors in the materials/Surfaces, disable vertex colors
Special DeusEx mask materials - Albedo > remove texture and set alpha color as transparent, Transparency > Alpha Scissor
Add VAT to the Godot Material
import the vat image textures
setup and reimport vat images
Compress > Mode=Lossless
Mipmaps > Generate=Off
Detect 3D > Compress To=Disabled
select the mesh in the scene and open the mesh property in the inspector
open the Surface#, click the down arrow on the Material and choose "Convert to Shader Material"
click the area next to down arrow
click on "Shader" and the shader editor opens
replace the vertex function with the entire contents of the desired shader file
save the tres file with a unique name, do not save over the original tres file
reselect the mesh in the scene and navigate back to the material
open the Shader Parameters
drag the position VAT onto the Position input
time scale = 30, set Num Frames
set scale and offset values if needed
above steps repeat for each surface material on the object
The Normals VAT is not used. It looks like Godot is doing some on the fly normals calculations?
Save the scene or material changes will be lost.
Other stuff? - still learning godot
add environment to scene from vertical 3 dot menu
add spotlight - shadow on
toggle preview sunlight off - in 3d view icon bar
exr works with Mobile and probably webgl/webxr?
Future changes?
work with physics - maybe modify cloth scripts
Theory
First the script makes a special uv layout in uv2 with the uv coordinates centered on the bitmap first row of pixels representing the first frame of the animation.
Then the script finds the mesh vertex with the most amount of motion and uses that value as the maximum value of the bitmap for scaling the arbitrary xyz values into all positive rgb color values between 0 and 1.
Then it runs through the animation to read the positions of all the vertices at each frame, saving the difference between the original position and the current xyz values.
The scaled and offset difference is stored rgb values in the texture with 1 row for each animation frame and column size equal to the number of vertices in the mesh.
The mesh with the custom uv2 and textures are imported to software that supports vertex animations based on textures.
A custom shader is created that moves the uv2 coordinate values through the texture, 1 row of pixels(1 frame) at a time reading the rgb values and converting them back into xyz values and adding them to the original xyz position in the vertex shader.
Notes:
GLTF file, drag both gltf and bin file into Godot
Combining VATs from morphs can be simulated by feeding 1 morphed mesh into another.
Combined VATs are limited. Small motions like eyes and lips can be added to a head movement which in turn can be added to a body motion.
Can only go from small to large.
The HDR option does not have bounding box or relative motion limits.
The vertex position values are saved as is into the bitmap without any scaling or offsets.
tested in Godot 4.3 and UE5
Relative Motion gives better results when not using the HDR option
Relative Reference Pose(LDR) is a better option when usage requires combination with other VATs.
Results are similar but it uses 2 textures instead of 1.
uv1 for color, uv2 created for vertex animation
tS can generate a signed floating point format texture and save it to exr format via the plugin
UE4 wont import hdr as texture, only as cube texture, it will import the exr format.
tS can load 16bit png but will not write 16bit png
tS does not have tex2Dlod shader function used to read texture samples for vertex shaders, so it cannot use animated vertex textures internally
tS weird mesh order requirements - uv2 points before uv2 triangles, but reversed in other cases
also weird had to use MeshModifiers.OptimizeTriangulation on copied actor mesh before it would properly update
could see issue in 3d view by setting the mesh normals to mooth and seeing a crazy result or edit the mesh and it would jump when moving vertices.
tS shader node VectorTo and FromComponents definetely weird, W value has an effect on XYZ values - made custom versions to get around the issue.
used custom renaming script to get around tS safe rename with [comma][space][number]
bilinear filtering may work to smooth out motions - no luck so far, idea was double width image to avoid filtering 2 values from 1 time frame
side note: IRdUVSelection may be only way to work with UV values, via pe mode, correction can set uv selection as well, maybe more rsx work in the future...
https://forums.unrealengine.com/t/vertex-animation-script-for-blender-3d-users/85580
found this for 3dsmax vertex anim tools
https://dev.epicgames.com/documentation/en-us/unreal-engine/vertex-animation-tool---timeline-meshes-in-unreal-engine?application_version=5.4
found this for blender
https://github.com/JoshRBogart/unreal_tools?files=1
animation range is scaled and offset to fit within 0-255(0-1)
animation range bounding box bbox min and max values
animation range delta min individual XYZ values for each vertex, maximum change in XYZ values for all vertices,
so small motion will expand to fit the full 0-255 range giving smoother result. bbox may be better for large motions
num vertices limited by texture size maximums - 4096? 8192?
HDR format saved from tS is not high quality, it has steps like an 8 bit image.
Sample includes 2 Unreal 5 uasset files, one relative and one absolute
Sample includes 2 Godot 4 tres files, one relative and one absolute
These shaders need more work and refinement. They work but can be better.
Godot result does not cast shadows. Does receive shadows from other items.
Unreal 5 object will cast shadow and self shadow.
Godot import - texture import detect 3D > Compress To > Disabled
Godot, time scale about 60,
numframes = height of images, no scale of values needed, gltf seems to work well, drag both gltf and bin files in
Unreal 5, texture group = 8 bit data and set data on sampler nodes,
this also set compression settings to vectordisplacementmap(rgba8), scale * 100, offset * -100,
save fbx scale = 100 and Metadata option works well
GLTF file, drag both gltf and bin file into Godot, then rclick New inherited scene and override the materials by dragging the tres files into place.
copy tres file vertex_animation_vshader_relative_xxx.tres into the Godot FileSystem tab. select mesh in scene and Surface Material Override
drag tres into slots
December 14, 2024
new Relative Reference Pose option can combine resulting VATs in the shader.
add check for non-instanced materials
Relative Motion shows "disabled" if HDR or Relative Reference Pose
First Frame Ref Pose deprecated? and moved to back panel
new results info on the panel
November 13, 2024
finished renaming all from VTA to VAT
add EXR float image export
October 17, 2024
fix major bug that limited the motion - bad math had negative value assumption, exportable colors only positive
has installer
replaces corresponding uu scripts and updates the uu button
automatic: includes the manual steps needed with the old bare script
works with actor and deformation animations - uses command node loops to update scene changes for reading
"absolute", non-relative, mode works
separate scale controls for X,Y and Z
naming change VTA to VAT and make naming less confusing
new system to drive the preview animations inside tS - no longer requires stack view