Version: Unity 6.5 Alpha (6000.5)
LanguageEnglish
  • C#

Mesh.SetVertexBufferData

Suggest a change

Success!

Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable.

Close

Submission failed

For some reason your suggested change could not be submitted. Please <a>try again</a> in a few minutes. And thank you for taking the time to help us improve the quality of Unity Documentation.

Close

Cancel

Switch to Manual

Declaration

public void SetVertexBufferData(NativeArray<T> data, int dataStart, int meshBufferStart, int count, int stream, MeshUpdateFlags flags);

Declaration

public void SetVertexBufferData(T[] data, int dataStart, int meshBufferStart, int count, int stream, MeshUpdateFlags flags);

Declaration

public void SetVertexBufferData(List<T> data, int dataStart, int meshBufferStart, int count, int stream, MeshUpdateFlags flags);

Parameters

Parameter Description
data The source data container from which the vertex data is copied.
dataStart The first element in the source data to copy from.
meshBufferStart The first element in mesh vertex buffer to receive the data.
count The number of elements of type T to copy from the data container into the Mesh buffer.
stream The vertex buffer stream to set data for. The default is 0. The value must be within the range 0 to 3.
flags The optional MeshUpdateFlags flags that control the update behavior of the mesh.

Description

Sets the data within a specific vertex buffer stream of the mesh's vertex buffer directly copied from data source.

You can use SetVertexBufferData to set vertex data directly, without using format conversions for each vertex attribute. Elements are copied from the source container to the destination range within the mesh's vertex buffer.

This method does not update vertex attributes or vertex layout of the Mesh. You must configure the vertex buffer structure via SetVertexBufferParams before calling this method, defining the vertex count, layout, and which vertex streams to use.

This is a high-performance, low-level method for populating mesh vertex data. It provides direct access to the underlying vertex buffer with minimal validation or data conversion overhead, making it suitable for performance-critical scenarios where you need maximum control over mesh data.

For simpler ways to set vertex data that handle vertex attribute configuration automatically, use SetVertices, SetNormals, SetUVs, or other attribute-specific methods instead.

// Generates a procedural triangle mesh with custom vertex format.
// Attach this script to a GameObject and enter Play mode.
// Tip: Use the Rendering Debugger window to inspect vertex attributes in the Scene view.

using System.Runtime.InteropServices;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;

// A 2-component vector storing 32-bit floats as 16-bit floats.
public readonly struct Float16x2
{
    readonly ushort m_X, m_Y;

    public Float16x2(float x, float y)
    {
        m_X = Mathf.FloatToHalf(x);
        m_Y = Mathf.FloatToHalf(y);
    }
}

// A 4-component vector storing normalized floats [-1, 1] as 16-bit signed normalized values (SNorm16).
public readonly struct SNorm16x4
{
    readonly ushort m_X, m_Y, m_Z, m_W;

    public SNorm16x4(float x, float y, float z, float w)
    {
        m_X = FloatToSNorm16(x);
        m_Y = FloatToSNorm16(y);
        m_Z = FloatToSNorm16(z);
        m_W = FloatToSNorm16(w);
    }

    // Converts a float in range [-1, 1] to a 16-bit signed normalized representation by clamping and scaling by 32767.
    static ushort FloatToSNorm16(float v) => (ushort)(32767f * Mathf.Clamp(v, -1f, 1f));
}

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
class SetVertexBufferDataExample : MonoBehaviour
{
    // Vertex structure with sequential memory layout containing position, compressed 16-bit normal, 32-bit color, and half-precision texture coordinates
    [StructLayout(LayoutKind.Sequential)]
    struct Vertex
    {
        public Vector3 position;
        public SNorm16x4 normal;
        public Color32 color;
        public Float16x2 texCoord;
    }

    // Vertex layout descriptor array defining the format and component count for each vertex attribute, matching the Vertex struct 
    static readonly VertexAttributeDescriptor[] k_VertexDescriptors = new VertexAttributeDescriptor[]
    {
        new(VertexAttribute.Position, VertexAttributeFormat.Float32, 3),
        new(VertexAttribute.Normal, VertexAttributeFormat.SNorm16, 4),
        new(VertexAttribute.Color, VertexAttributeFormat.UNorm8, 4),
        new(VertexAttribute.TexCoord0, VertexAttributeFormat.Float16, 2),
    };

    Mesh m_Mesh;

    void Start()
    {
        // Create mesh with predefined bounds to avoid recalculation
        m_Mesh = new Mesh
        {
            name = "SampleMesh",
            bounds = new Bounds(Vector3.zero, Vector3.one * 2f),
        };

        // Create and assign triangle vertices
        using (var vertices = GenerateVertices())
        {
            // Configure vertex buffer layout and allocate space
            m_Mesh.SetVertexBufferParams(vertices.Length, k_VertexDescriptors);

            // Assigns the generated vertices to the mesh
            m_Mesh.SetVertexBufferData(vertices, 0, 0, vertices.Length);
        }

        // Create and assign triangle indices
        using (var indices = new NativeArray<uint>(new uint[] { 0, 1, 2 }, Allocator.Temp))
        {
            // Configure index buffer format and allocate space
            m_Mesh.SetIndexBufferParams(indices.Length, IndexFormat.UInt32);

            // Assigns the generated indices to the mesh
            m_Mesh.SetIndexBufferData(indices, 0, 0, indices.Length);

            // Define single sub-mesh spanning all indices
            m_Mesh.SetSubMesh(0, new SubMeshDescriptor(0, indices.Length));
        }

        // Assign mesh to MeshFilter & MeshRenderer
        GetComponent<MeshFilter>().sharedMesh = m_Mesh;
        GetComponent<MeshRenderer>().material = GraphicsSettings.currentRenderPipeline != null ? GraphicsSettings.currentRenderPipeline.defaultMaterial : new Material(Shader.Find("Standard"));
    }

    void OnDestroy() => Destroy(m_Mesh);

    // Creates an array with the triangle vertices
    NativeArray<Vertex> GenerateVertices()
    {
        var vertices = new NativeArray<Vertex>(3, Allocator.Temp);
        for (int i = 0; i < 3; i++)
        {
            // Create and assign the vertex with the computed position, matching normal, UVs, and position-derived color
            vertices[i] = new Vertex
            {
                position = new Vector3(i - 1f, i % 2 * Mathf.Sqrt(2f), 0f),
                normal = new SNorm16x4(0f, 0f, -1f, 0f),
                texCoord = new Float16x2(i, i % 2 * Mathf.Sqrt(2f)),
                color = new Color32(i == 0 ? byte.MaxValue : byte.MinValue, i == 1 ? byte.MaxValue : byte.MinValue, i == 2 ? byte.MaxValue : byte.MinValue, byte.MaxValue),
            };
        }
        return vertices;
    }
}

Additional resources: SetVertexBufferParams, ::SetIndexBufferData, MeshUpdateFlags.