4
\$\begingroup\$

I am trying to use Unity to display a model and color some triangles on the model to high light those parts of the model.

I have created a scene, with a camera, a light source and a cube. After the scene loads I have a script on the cube where I am importing a new mesh and replacing the cube mesh with the new mesh. I am also giving each triangle a random color.

    void Update () {
    if (Time.time > 10 && newShapeLoaded)
    {
        System.Collections.Generic.List<facet> newModel = readStl(@"C:\testing1\stls\sphere.stl");
        System.Collections.Generic.List<Vector3> vertices = new System.Collections.Generic.List<Vector3>();
        foreach (facet f in newModel)
        {
            vertices.Add(f.vecA);
            vertices.Add(f.vecB);
            vertices.Add(f.vecC);
        }
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.vertices = vertices.ToArray();
        int[] t = new int[vertices.Count];
        Color32[] colors = new Color32[vertices.Count];
        Color32 currentColor = new Color32();
        for (int i = 0; i < vertices.Count; i++)
        {
            t[i] = i;
            colors[i] = currentColor;
            if (i % 3 == 0)
            {
                currentColor = new Color(
                                    Random.Range(0.0f, 1.0f),
                                    Random.Range(0.0f, 1.0f),
                                    Random.Range(0.0f, 1.0f),
                                    1.0f);
            }
            colors[i] = currentColor;
        }
        mesh.triangles = t;
        mesh.colors32 = colors;
        mesh.RecalculateBounds();
        mesh.RecalculateNormals();
        mesh.UploadMeshData(true);
        newShapeLoaded = false;
    }
}/* Update() */

This was not working and searching I found I needed to change the material type to a material that uses vertex color shading. I found the Particles>VertexLit Blended Shader colors the triangle but then the triangles are drawn in the wrong order so the shape appears inside out.

Is their anyone that knows more about Unity and 3D that could give me some advice or let me know where I have gone wrong with this?

(edit) So I have investigated this further and I believe the comment made about the particle material being the reason for the shape appears inside out is correct. example I also noticed that the original cube has this problems before I change the mesh as well. So I have tried to find a material with a shader that will still let me color the triangles but not break the render order of the triangles. Unfortunatly I haven't been able to get anything to work. I have found a thread here where several people have tried to create a shader to do this and I have downloaded their projects and run them and tried to get them to work with very limited success. This lead me to also find several tutorials on shader programming to try and understand what was happening, but these have not given me any better understanding of how to get vertex coloring working.

I am now wondering if I have gone off track because all I really want to do is to make a simple model and change the color of some triangles on the model. I though this would be like a simple hello world exercise for 3D graphics, but I have put over a week into this now and tried several different approaches and still have not been able to get this working.

I would be very grateful if someone could show me an example of changing colors of triangles on a mesh? Or if someone that understands 3D graphics could just point me in the right direction to a tutorial or guide that will help me learn what I need to know to get this working and let me know if this is the correct way to try and be able to change colors on a mesh?

\$\endgroup\$
2
  • \$\begingroup\$ Your problem is particle materials are made for transparent blending, so they don't write to the depth buffer to occlude in correct depth order. You'll want to add vertex colours to an opaque shader. Which shader you use as a base will depend on what other appearance/features you want. Do you want lighting on your mesh, or just unlit vertex colours? \$\endgroup\$
    – DMGregory
    Commented Mar 4, 2017 at 14:16
  • \$\begingroup\$ For future reference, adding extra paragraphs describing how much you've searched and how hard it is and promising gratitude... doesn't actually improve your question in any way. If you'd replied back with a simple answer to the clarifying question above, "lit or unlit?" I or another user could have provided you a working shader very quickly. Usually if you're not getting answers, it's not due to a lack of empathy, but a lack of details about your problem & goals - so always focus on adding more constructive information. \$\endgroup\$
    – DMGregory
    Commented May 17, 2017 at 12:42

2 Answers 2

1
\$\begingroup\$

As mentioned in the comments above, the "inside out" or incorrect ordering effect comes from using a particle shader - these are written for layering transparent content so they don't write to the depth buffer the way we'd want an opaque shader to do.

So,we just need to make our own opaque shader that uses vertex colours. I'd been hoping to keep the answer concise by showing just a lit or unlit version depending on what the asker wanted, but since they never replied back on that point, here's one of each...

Unlit:

Shader "Unlit/VertexColored"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                // Read vertex color from mesh.
                fixed4 color : COLOR0;    
            };

            struct v2f
            {
                // Pass interpolated vertex color to fragment.
                fixed4 color : COLOR0;    
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.color = v.color; // Pass the color through.
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // Output the color straight.
                return i.color;
            }
            ENDCG
        }
    }
}

Using Unity's standard lighting model:

Shader "Custom/VertexColoredStandard" {
    Properties {
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        struct Input {
            // Ask Unity to pass the vertex color through.
            float4 color : COLOR0;
        };

        half _Glossiness;
        half _Metallic;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Use the vertex color as albedo.
            fixed4 c = IN.color;
            o.Albedo = c.rgb;
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
\$\endgroup\$
-1
\$\begingroup\$

By inside out, do you mean the face normals are reversed? If so, try to manually calculate the normals. The code below should be pretty easy to follow.

//mesh.RecalculateNormals();
mesh.normals = RecalculateNormals(vertices, triangles);

    public static Vector3[] RecalculateNormals(Vector3[] vertices, int[] triangles) {

        var normals = new Vector3[vertices.Length];

        for (var i = 0; i < triangles.Length; i += 3) {
            int i1 = triangles[i];
            int i2 = triangles[i + 1];
            int i3 = triangles[i + 2];

            //Calculate the normal of the triangle
            Vector3 p1 = vertices[i2] - vertices[i1];
            Vector3 p2 = vertices[i3] - vertices[i1];
            Vector3 normal = Vector3.Cross(p1, p2).normalized;

            normals[i1] += normal;
            normals[i2] += normal;
            normals[i3] += normal;

        }

        for(int i = 0; i < normals.Length; i++){
            normals[i] = normals[i].normalized;
        }

        return normals;
    }

If this still produces backwards normals, then just invert the final assignment to the normals array; normals[i] = -normals[i].normalized;

If that isn't the issue, then I can only assume it has something to do with how you are reading from the .stl file, or with the shader. If not, it would go a long way to see a picture of your issue.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .