The way I approached this was to "reverse engineer" the shader graph shader and extracted all the logic to C# for just the code that handles/manipulates vertex positions. I mostly succeeded in the task, except that the results seem to be off only at specific vertices. Notice on the edges, the vertices get that jagget shape and I also noticed some triangles just floating in empty space, detached from the mesh.
Here is the code I am using to bake the VAT position texture in C#
private void GenerateMesh()
{
var mesh = new Mesh();
var vertices = _mesh.vertices;
var uv1 = _mesh.uv2;
var textureWidth = _positions.width;
var textureHeight = _positions.height;
var tMin = _vatData.BoundsMin * 10.0f;
var tMax = _vatData.BoundsMax * -10.0f;
var pixelRatioX = 1.0f - (Mathf.Ceil(tMin.z) - tMin.z);
var pixelRatioY = 1.0f - (tMax.x - Mathf.Floor(tMax.x));
var a = (Mathf.Floor(_vatData.DisplayFrame) - 1f) % _vatData.FrameCount;
var b = a * (1.0f / _vatData.FrameCount) * pixelRatioY;
for (var i = 0; i < vertices.Length; i++)
{
var uv = uv1[i];
var c = b + (1.0f - uv.y) * pixelRatioY;
var sampleX = Mathf.FloorToInt(uv.x * pixelRatioX * textureWidth);
var sampleY = Mathf.CeilToInt(c * textureHeight);
var pixel = _positions.GetPixel(sampleX, sampleY);
var offset = new Vector3(pixel.r, pixel.g, pixel.b);
if (uv.y <= 0.1f)
offset = new Vector3(0, 0, 0);
vertices[i] += offset;
}
mesh.vertices = vertices;
mesh.triangles = _mesh.triangles;
mesh.tangents = _mesh.tangents;
mesh.uv = _mesh.uv;
mesh.uv2 = _mesh.uv2;
mesh.RecalculateNormals();
mesh.RecalculateTangents();
_meshFilter.sharedMesh = mesh;
}
Attached in the post is the image of how the results look like. On the left is the VAT shader from Houdini, on the right is the C# bake.