Hello,
I would like to share an interesting use case of SampleMesh and it’s probably a good opportunity to explain how the point cache tool is implemented behind the curtain.
You may have already tried to spawn uniformly particles over a mesh or skinned mesh in the Visual Effect Graph. The naïve approach consists in a random selection of the triangle index, then, picking two other floats to spawn particles over the chosen triangle. This is also the internal behavior of the block Set Position (Mesh) with the spawn mode Random.
The problem with this solution is that since we don’t consider the triangle area, it’s highly probable to choose one of the small triangles in the first selection phase. This leads to an uneven repartition of spawned particles.

There are more triangles on the head than the rest of the body. The problem and the reason become more obvious looking at the wireframe of this scene.

We can avoid this issue by having a mesh with all triangles of the same size, but this isn’t an easy or reasonable constraint to respect during mesh modelling.
With the point cache bake tool, you can eventually bake a list of positions uniformly distributed on a static mesh, but this won’t be appropriate if you are using a sampling of a skinned mesh directly in Visual Effect Graph.
Actually, we can use the same trick as the point cache bake tool but applicable to a skinned mesh.
First thing first, let me describe how the point cache bake tool is able to generate a uniform set on vertices on any uneven mesh surface:
-
Extract vertices and indices from a mesh
-
Compute area of all triangles
-
Compute the accumulated prefix sum array of the area of all triangles (the first element of this array will be the area of the first triangle, the following one will be the accumulated area of the first and second triangle, the last element will be the total area of the surface of the mesh)
-
For every sample to generate:
-
Pick a random number between 0 and total area
-
Find the corresponding triangle index in accumulated sum array (using a dichotomy)
-
Pick two random floats to generate an uniform barycentric coordinate
-
Interpolate corresponding triangle vertices using previously computed barycentric coordinates, append this result.
Back on our issue, this kind of process can’t be easily done in real time but we can store the result of the computed barycentric coordinate and triangle index in a GraphicsBuffer and use this indirection to interpolate skinned vertices. In other words, we can apply the same algorithm but replace step 4.4. by a simple storage of triangle index and barycentric coordinate in a list to build a buffer later.
Instead of using random triangle index selection, we will use this indirection to sample the skinned mesh.

Some details about this sample:
- The VFXMeshSamplingHelper has been widely inspired by the PointCacheBakeTool.Mesh implementation
- The VFXMeshSamplingHelper static class provides three public functions ComputeDataCache, GetNextSampling & GetInterpolatedVertex
- The basic usage of this class is :
var meshData = VFXMeshSamplingHelper.ComputeDataCache(mesh);
var rand = new System.Random(1234);
var bakedSampling = new TriangleSampling[SampleCount];
for (int i = 0; i < 1000; ++i)
{
bakedSampling[i] = VFXMeshSamplingHelper.GetNextSampling(meshData, rand);
}
- A custom monobehaviour called UniformBaker stores the list of baked positions in scene to build a GraphicsBuffer on the fly in runtime and assign it to the VFX. The baking process is only applied in editor.
This solution isn’t perfect because it assumes the skinning doesn’t change too much the area of the triangles. Furthermore, I choose to store the computed barycentric coordinate, but there is a reason for this: during the baking of barycentric coordinates, we can also interpolate the vertices and do special sorting of the baked coordinates, which is the purpose of the function GetInterpolatedVertex.

Here, I arbitrarily choose to order the baked positions based on the distance of the first channel of texture coordinates with the center of the main texture (See UniformBakerCustomOrder)
bakedSampling = bakedSampling.OrderBy(o =>
{
var vertex = VFXMeshSamplingHelper.GetInterpolatedVertex(meshData, o);
var texCoord = vertex.uvs[0];
return (texCoord - new Vector4(0.5f, 0.5f, 0.5f, 0.5f)).sqrMagnitude;
}).ToArray();
In closing, we are aware this kind of approach can be generalized, for instance, the point cache bake tool can optionally output triangle indices and barycentric coordinates instead of interpolated vertices. Meanwhile, feel free to take inspiration from this use case and implement your own custom solution.
I hope this kind of trick can inspire you for a more advanced effect, we are always glad to see your creativity.
You can find all sources and assets used in this sample on this git repository (you can clone it or download a zip), it can be opened with Unity 2021.2.0b16 or greater.
Feel free to share your impressions and don’t hesitate if you have any additional questions or if something isn’t clear.
