Skip to content

Mesh Simplifier API

Mattias Edlund edited this page Aug 18, 2021 · 5 revisions

About

The Mesh Simplifier API is where the actual mesh simplification (or decimation) happens. The algorithm itself is deeply based on Fast Quadric Mesh Simplification, with many modifications. When you want to reduce the triangle count of a mesh, this is the API that you want to use.

API

You will find the API in the MeshSimplifier class of the UnityMeshSimplifier interface. You will have to create an instance of the class before you can use it.

Constructors

Name Summary
MeshSimplifier() Creates a new mesh simplifier.
MeshSimplifier(Mesh mesh) Creates a new mesh simplifier and initializes a mesh directly.

Properties

Type Name Summary Default value
SimplificationOptions SimplificationOptions Gets or sets all of the simplification options as a single block. SimplificationOptions.Default
bool Verbose Gets or sets if verbose information should be printed to the console. false
Vector3[] Vertices Gets or sets the vertex positions. null
int SubMeshCount Gets the count of sub-meshes.
int BlendShapeCount Gets the count of blend shapes.
Vector3[] Normals Gets or sets the vertex normals. null
Vector4[] Tangents Gets or sets the vertex tangents. null
Vector2[] UV1 Gets or sets the vertex 2D UV set 1. null
Vector2[] UV2 Gets or sets the vertex 2D UV set 2. null
Vector2[] UV3 Gets or sets the vertex 2D UV set 3. null
Vector2[] UV4 Gets or sets the vertex 2D UV set 4. null
Vector2[] UV5 Gets or sets the vertex 2D UV set 5. null
Vector2[] UV6 Gets or sets the vertex 2D UV set 6. null
Vector2[] UV7 Gets or sets the vertex 2D UV set 7. null
Vector2[] UV8 Gets or sets the vertex 2D UV set 8. null
Color[] Colors Gets or sets the vertex colors. null
BoneWeight[] BoneWeights Gets or sets the vertex bone weights. null

Methods

Type Name Summary
int[][] GetAllSubMeshTriangles() Returns the triangle indices for all sub-meshes.
int[] GetSubMeshTriangles(int subMeshIndex) Returns the triangle indices for a specific sub-mesh.
void ClearSubMeshes() Clears out all sub-meshes.
void AddSubMeshTriangles(int[] triangles) Adds a sub-mesh triangle indices for a specific sub-mesh.
void AddSubMeshTriangles(int[][] triangles) Adds several sub-meshes at once with their triangle indices for each sub-mesh.
Vector2[] GetUVs2D(int channel) Returns the UVs (2D) from a specific channel.
Vector3[] GetUVs3D(int channel) Returns the UVs (3D) from a specific channel.
Vector4[] GetUVs4D(int channel) Returns the UVs (4D) from a specific channel.
void GetUVs(int channel, List<Vector2> uvs) Returns the UVs (2D) from a specific channel.
void GetUVs(int channel, List<Vector3> uvs) Returns the UVs (3D) from a specific channel.
void GetUVs(int channel, List<Vector4> uvs) Returns the UVs (4D) from a specific channel.
void SetUVs(int channel, IList<Vector2> uvs) Sets the UVs (2D) for a specific channel.
void SetUVs(int channel, IList<Vector3> uvs) Sets the UVs (3D) for a specific channel.
void SetUVs(int channel, IList<Vector4> uvs) Sets the UVs (4D) for a specific channel.
void SetUVs(int channel, IList<Vector4> uvs, int uvComponentCount) Sets the UVs for a specific channel with a specific count of UV components.
void SetUVsAuto(int channel, IList<Vector4> uvs) Sets the UVs for a specific channel and automatically detects the used components.
BlendShape[] GetAllBlendShapes() Returns all blend shapes.
BlendShape GetBlendShape(int blendShapeIndex) Returns a specific blend shape.
void ClearBlendShapes() Clears all blend shapes.
void AddBlendShape(BlendShape blendShape) Adds a blend shape.
void AddBlendShapes(BlendShape[] blendShapes) Adds several blend shapes.
void Initialize(Mesh mesh) Initializes the algorithm with the original mesh.
void SimplifyMesh(float quality) Simplifies the mesh to a desired quality.
void SimplifyMeshLossless() Simplifies the mesh without losing too much quality.
Mesh ToMesh() Returns the resulting mesh.

Structs

SimplificationOptions

Type Name Summary Default value
bool PreserveBorderEdges If the border edges should be preserved. false
bool PreserveUVSeamEdges If the UV seam edges should be preserved. false
bool PreserveUVFoldoverEdges If the UV foldover edges should be preserved. false
bool PreserveSurfaceCurvature If the discrete curvature of the mesh surface be taken into account during simplification. Taking surface curvature into account can result in good quality mesh simplification, but it can slow the simplification process significantly. false
bool EnableSmartLink If a feature for smarter vertex linking should be enabled, reducing artifacts in the decimated result at the cost of a slightly more expensive initialization by treating vertices at the same position as the same vertex while separating the attributes. More info here. true
double VertexLinkDistance The maximum distance between two vertices in order to link them. Note that this value is only used if EnableSmartLink is true. double.Epsilon
int MaxIterationCount The maximum iteration count. Higher number is more expensive but can bring you closer to your target quality. Sometimes a lower maximum count might be desired in order to lower the performance cost. 100
double Agressiveness The agressiveness of the mesh simplification. Higher number equals higher quality, but more expensive to run. 7.0
bool ManualUVComponentCount If a manual UV component count should be used (set by UVComponentCount), instead of the automatic detection. false
int UVComponentCount The UV component count. The same UV component count will be used on all UV channels. 2

BlendShape

Type Name Summary
string ShapeName The name of the blend shape.
BlendShapeFrame[] Frames The blend shape frames.

BlendShapeFrame

Type Name Summary
float FrameWeight The weight of the blend shape frame.
Vector3[] DeltaVertices The delta vertices of the blend shape frame.
Vector3[] DeltaNormals The delta normals of the blend shape frame.
Vector3[] DeltaTangents The delta tangents of the blend shape frame.

Examples

Simplify all MeshFilters on children of a game object at runtime

This example will not work with skinned and animated meshes.

using UnityEngine;

public class SimplifyChildren: MonoBehaviour
{
    [SerializeField, Range(0f, 1f), Tooltip("The desired quality of the simplified mesh.")]
    private float quality = 0.5f;

    private void Start()
    {
        Simplify();
    }

    private void Simplify()
    {
        var meshFilters = GetComponentsInChildren<MeshFilter>();
        foreach (MeshFilter meshFilter in meshFilters)
        {
            SimplifyMeshFilter(meshFilter);
        }
    }

    private void SimplifyMeshFilter(MeshFilter meshFilter)
    {
        Mesh sourceMesh = meshFilter.sharedMesh;
        if (sourceMesh == null) // verify that the mesh filter actually has a mesh
            return;

        // Create our mesh simplifier and setup our entire mesh in it
        var meshSimplifier = new UnityMeshSimplifier.MeshSimplifier();
        meshSimplifier.Initialize(sourceMesh);

        // This is where the magic happens, lets simplify!
        meshSimplifier.SimplifyMesh(quality);

        // Create our final mesh and apply it back to our mesh filter
        meshFilter.sharedMesh = meshSimplifier.ToMesh();
    }
}

Simplify MeshFilter on game object at runtime manually with only vertices and indices

Please note that this example is only to show the possibility of manually providing vertices etc, in most cases in Unity you will want to use the Initialize and ToMesh methods that will take care of most cases automatically, directly through a Mesh.

using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
public class SimplifySimple: MonoBehaviour
{
    [SerializeField, Range(0f, 1f), Tooltip("The desired quality of the simplified mesh.")]
    private float quality = 0.5f;

    private void Start()
    {
        Simplify();
    }

    private void Simplify()
    {
        var meshFilter = GetComponent<MeshFilter>();
        if (meshFilter == null) // verify that there is a mesh filter
            return;

        Mesh sourceMesh = meshFilter.sharedMesh;
        if (sourceMesh == null) // verify that the mesh filter actually has a mesh
            return;

        // Create our mesh simplifier and setup our vertices and indices from all sub meshes in it
        var meshSimplifier = new UnityMeshSimplifier.MeshSimplifier();
        meshSimplifier.Vertices = sourceMesh.vertices;

        for (int i = 0; i < sourceMesh.subMeshCount; i++)
        {
            meshSimplifier.AddSubMeshTriangles(sourceMesh.GetTriangles(i));
        }

        // This is where the magic happens, lets simplify!
        meshSimplifier.SimplifyMesh(quality);

        // Create our new mesh and transfer vertices and indices from all sub meshes
        var newMesh = new Mesh();
        newMesh.subMeshCount = meshSimplifier.SubMeshCount;
        newMesh.vertices = meshSimplifier.Vertices;

        for (int i = 0; i < meshSimplifier.SubMeshCount; i++)
        {
            newMesh.SetTriangles(meshSimplifier.GetSubMeshTriangles(i), 0);
        }

        meshFilter.sharedMesh = newMesh;
    }
}