为三角形中的每个顶点设置颜色

Set color for each vertex in a triangle

我想从红色、蓝色和绿色的网格中设置三角形的每个三个顶点。

如第一部分 this 教程中所见,这是针对另一种语言的。这是他们用来为网格中每个三角形中的每个顶点设置红色、绿色和蓝色的代码:

function set_wireframe_colors(m)
    local cc = {}
    for i = 1, m.size/3 do
        table.insert(cc, color(255,0,0))
        table.insert(cc, color(0,255,0))
        table.insert(cc, color(0,0,255))
    end
    m.colors = cc
end

这是使用简单顶点颜色着色器的输出结果:


我试图用 C# 在 Unity 中重新创建同样的东西,但我在学习本教程的第一部分时遇到困难。

这是我的代码:

void Start()
{
    Mesh mesh = GetComponent<MeshFilter>().mesh;
    Vector3[] vertices = mesh.vertices;

    //Create new colors array where the colors will be created.
    Color32[] colors = new Color32[vertices.Length];

    for (int i = 0; i < vertices.Length; i += 3)
    {
        colors[i] = new Color32(255, 0, 0, 255);
        colors[i + 1] = new Color32(0, 255, 0, 255);
        colors[i + 2] = new Color32(0, 0, 255, 255);
    }

    //assign the array of colors to the Mesh.
    mesh.colors32 = colors;
}

但这是我使用简单的顶点颜色着色器从 Unity 获得的输出:


如果你仔细观察,你会发现我的立方体中的每个顶点都没有分配给它的 rgb 颜色,就像我第一个屏幕截图中的立方体一样。虽然它看起来非常接近。

代码有什么问题?为什么每个顶点不像我第一个屏幕截图中的图像那样具有 rgb 颜色。

着色器:

这个问题可能与着色器无关,但这里是 Unity 中的简单颜色着色器:

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    float4 color : COLOR;
};

struct v2f
{
    float2 uv : TEXCOORD0;
    UNITY_FOG_COORDS(1)
    float4 vertex : SV_POSITION;
    float4 color : COLOR;
};

sampler2D _MainTex;
float4 _MainTex_ST;


v2f vert(appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.color = v.color;

    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    UNITY_TRANSFER_FOG(o,o.vertex);
    return o;
}

float4 frag(v2f i) : SV_Target
{
    return i.color;
}

他使用的网格每个三角形有 3 个单独的顶点(每个四边形 6 个顶点)。在统一立方体中,每个面都是一个有 4 个顶点的四边形,每个面上的 2 个三角形共享 2 个顶点。

左边是一个有 4 个顶点的四边形,mesh.triangles 数组是 0 1 2 1 0 3,右边是一个有 6 个顶点的四边形,mesh.triangles = 0 1 2 3 4 5(顶点顺序对于背面剔除很重要。在我的着色器中,我将剔除设置为关闭)。

因此,正如您在该着色器的图像中所见,您可以使用由 4 个顶点四边形组成的网格,只要您小心并确保每个三角形在每个顶点中都有一种颜色。


正如我在评论中所说,您可以拆分网格,以便每个三角形都有 3 个独特的顶点。

void Start () {
    Mesh mesh = GetComponent<MeshFilter>().mesh;        
    SplitMesh(mesh);
    SetColors(mesh);
}

void SplitMesh(Mesh mesh)
{
    int[] triangles = mesh.triangles; 
    Vector3[] verts = mesh.vertices;
    Vector3[] normals = mesh.normals;
    Vector2[] uvs = mesh.uv;

    Vector3[] newVerts;
    Vector3[] newNormals;
    Vector2[] newUvs;

    int n = triangles.Length;
    newVerts   = new Vector3[n];
    newNormals = new Vector3[n];
    newUvs     = new Vector2[n];

    for(int i = 0; i < n; i++)
    {
        newVerts[i] = verts[triangles[i]];
        newNormals[i] = normals[triangles[i]];
        if (uvs.Length > 0)
        {
            newUvs[i] = uvs[triangles[i]];
        }
        triangles[i] = i; 
    }        
    mesh.vertices = newVerts;
    mesh.normals = newNormals;
    mesh.uv = newUvs;        
    mesh.triangles = triangles;            
}   
void SetColors(Mesh mesh)
{
    Color[] colors = new Color[mesh.vertexCount];
    for (int i = 0; i < colors.Length; i+=3)
    {
        colors[i] = Color.red;
        colors[i + 1] = Color.green;
        colors[i + 2] = Color.blue;
    }
    mesh.colors = colors;
}

这不是一个非常优雅的解决方案,但这对我有用。

    Mesh newMesh = newObject.GetComponent<MeshFilter>().mesh = mesh;
    Vector3[] vertices = newMesh.vertices;
    Vector3[] normals = newMesh.normals;
    int[] triangles = newMesh.triangles;
    var newVertices = new Vector3[triangles.Length];
    var newNormals = new Vector3[triangles.Length];
    var newTriangles = new int[triangles.Length];

    for (var i = 0; i < triangles.Length; i++)
    {
        newVertices[i] = vertices[triangles[i]];
        newNormals[i] = normals[triangles[i]];
        newTriangles[i] = i;
    }
    newMesh.vertices = newVertices;
    newMesh.normals = newNormals;
    newMesh.triangles = newTriangles;

    Color[] colors = new Color[newVertices.Length];
    for (int i = 0; i < newVertices.Length-5; i++)
    {
        float r = UnityEngine.Random.value;
        float g = UnityEngine.Random.value;
        float b = UnityEngine.Random.value;
        if (i % 6 == 0)
        {
            colors[i] = new Color(r, g, b, 1f);
            colors[i + 1] = new Color(r, g, b, 1f);
            colors[i + 2] = new Color(r, g, b, 1f);
            r = UnityEngine.Random.value;
            g = UnityEngine.Random.value;
            b = UnityEngine.Random.value;
            colors[i + 3] = new Color(r, g, b, 1f);
            colors[i + 4] = new Color(r, g, b, 1f);
            colors[i + 5] = new Color(r, g, b, 1f);
        }
    }

    newMesh.colors = colors;