12

I want to set each three vertex of a triangle from a mesh red, blue and green.

As seen in the first part this tutorial which is for another language. This is the code they are using to set red, green and blue to each vertext in the each triangle from a mesh:

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

and this is what the output looks like with a simple vertex color shader:

enter image description here


I tried to recreate the-same thing in Unity with C# but I am struggling with the first part of this tutorial.

Here is my code:

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;
}

but this is the output I get from Unity with a simple vertex color shader:

enter image description here


If you look closely you will see that each vertex in my cube does not have an rgb color assigned to it like the cube from my first screenshot. It looks very close though.

What's wrong with the code? Why does each vertex not have rgb color like the image from my first screenshot.

Shader:

This problem likely has nothing to do with the shader but here the simple color shader in 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;
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • check this one... will be helpfull: https://forum.unity3d.com/threads/standard-shader-with-vertex-colors.316529/ – joreldraw Aug 24 '17 at 06:38
  • Just red that. That post is talking about making vertex shaders which I can do. This question is about how to set color of each vertex in each triangle in a mesh, from code, not from shader. That's different and I think the problem is likely from the C# code. Maybe the vertices are not in order. – Programmer Aug 24 '17 at 06:52
  • you dont specified shader or code...only vertex color – joreldraw Aug 24 '17 at 07:33
  • Your cube has an rgb color assigned to each vertex. But standard unity cube has 24 vertex. Each corner has 3 different ones in this same place. – Woltus Aug 24 '17 at 08:25
  • @Woltus If figure that could be the problem. I've am still wrapping my head on how to fix this. – Programmer Aug 24 '17 at 08:39
  • Make 2-dimension array of vertices and each vertex in row get the same color. Vertices on the same corner should have the same or veeery symiliar position. – Woltus Aug 24 '17 at 09:56

2 Answers2

11

The mesh he is using has a 3 separate vertices for each triangle (6 vertices per quad). In a unity cube each face is a quad with 4 vertices and the 2 triangles on each face share 2 of the vertices.
enter image description here

On the left is a quad that has 4 vertices and the mesh.triangles array would be 0 1 2 1 0 3, and on the right is a quad with 6 vertices with mesh.triangles = 0 1 2 3 4 5 (vertex order matters for back-face culling. In my shader I have Cull set to off).

So as you can see in the image for this shader you can use meshes made out of 4 vertices quads as long as you are careful and make sure that each triangle has one of each color in each vertex.


As I said in the comments you can split your mesh so that you have 3 unique vertices for each triangle.

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;
}

enter image description here

Pluto
  • 3,911
  • 13
  • 21
  • Wow everything makes more sense. I just made a simple cube in Maya and imported it into Unity. I think it would be hard to sort the order of the vertex. If you have a solution that can do this, that would be fine. – Programmer Aug 24 '17 at 17:59
  • @Programmer What is this for? Can you use geometry shaders? If not, you can split your mesh either in unity or in a 3d program like Maya or Blender with veretx/edge split. Otherwise you are looking at a [Graph coloring problem](https://en.wikipedia.org/wiki/Graph_coloring) – Pluto Sep 06 '17 at 17:34
  • Nope, I cannot use Geometry shaders in order to make it compatible on different devices. This is for displaying an object in wireframe. See [this](https://codea.io/talk/discussion/3170/render-a-mesh-as-wireframe) post to understand this well. I just can't get the first part of this to work correctly..... – Programmer Sep 06 '17 at 17:38
  • Can you split your mesh? – Pluto Sep 06 '17 at 17:39
  • If from a 3D program then no. I just want this to be 100% code+shader solution like the linked post suggest. – Programmer Sep 06 '17 at 17:42
  • Sure! If splitting it is the only viable option then that's fine. – Programmer Sep 06 '17 at 17:45
0

Not a very elegant solution, but this works for me.

    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;
FaffyWaffles
  • 125
  • 1
  • 7