0

I am trying to implement a method using ray casting in unity where I can set different color to selected face of triangle and set different color to the contacted triangle (neighboring triangles) but when I am running it's coloring all triangles same color. I was wondering if there is a problem with my implementation or do I need to update my unity settings (such as materials etc.)

I have shared my implemented code below. Any help will be really appreciated! Thank you.

Unity scene image

using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections.Generic;


public class MyRayDraw : MonoBehaviour
{
    public GameObject spherePrefab;

    // Better to reference those already in the Inspector
    [SerializeField] private MeshFilter meshFilter;
    [SerializeField] private MeshRenderer meshRenderer;
    [SerializeField] private MeshCollider meshCollider;

   //colors
   [SerializeField] private Material startMaterial;
   [SerializeField] private Material newMaterial;
   Renderer objrenderer;

   private Mesh mesh;

    private void Awake()
    {
        if (!meshFilter) meshFilter = GetComponent<MeshFilter>();
        if (!meshRenderer) meshRenderer = GetComponent<MeshRenderer>();
        if (!meshCollider) meshCollider = GetComponent<MeshCollider>(); 

        mesh = meshFilter.mesh;

        // create new colors array where the colors will be created
        var colors = new Color[mesh.vertices.Length];
        for(var i = 0; i < colors.Length; i++)
        {
            colors[i] = Color.black;
        }

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

    }

    private void Update()
    {
        if (!Input.GetMouseButtonDown(0)) return;

        var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;


        if (Physics.Raycast(ray, out hit))
        {
            Debug.Log(hit.triangleIndex);
            
            //cube.transform.position = hit.point;

            // Get current vertices, triangles, uvs and colors
            var vertices = mesh.vertices;
            var triangles = mesh.triangles;
            //var uv = _mesh.uv;
            var colors = mesh.colors;

            // Get the vert indices for this triangle
            var vertIndex_1 = triangles[hit.triangleIndex * 3 + 0];
            var vertIndex_2 = triangles[hit.triangleIndex * 3 + 1];
            var vertIndex_3 = triangles[hit.triangleIndex * 3 + 2];

            // Get the positions for the vertices
            var vertPos_1 = vertices[vertIndex_1];
            var vertPos_2 = vertices[vertIndex_2];
            var vertPos_3 = vertices[vertIndex_3];
            
            // Now for all three vertices we first check if any other triangle if using it
            // by simply count how often the indices are used in the triangles list
            var verticesOccur_1 = 0;
            var verticesOccur_2 = 0;
            var verticesOccur_3 = 0;

            for (var i = 0; i < triangles.Length; i++)
            {
                if (triangles[i] == vertIndex_1) verticesOccur_1++;
                if (triangles[i] == vertIndex_2) verticesOccur_2++;
                if (triangles[i] == vertIndex_3) verticesOccur_3++;
            }
            

            // Create copied Lists so we can dynamically add entries
            var newVertices = vertices.ToList();
            var newTriangles = triangles.ToList();
            //var newUV = uv.ToList();
            var newColors = colors.ToList();

            // Now we check if the vertices are used by more than one triangle
            // If so, we need to split the triangle into three new ones
            // and add the new vertices to the vertices list
            
            if (verticesOccur_1 > 1)
            {
                // Add the new vertices to the vertices list
                newVertices.Add(vertPos_1);
                newVertices.Add(vertPos_2);
                newVertices.Add(vertPos_3);

                // Add the new triangles to the triangles list
                newTriangles.Add(vertIndex_1);
                newTriangles.Add(newVertices.Count - 3);
                newTriangles.Add(newVertices.Count - 1);

                newTriangles.Add(newVertices.Count - 3);
                newTriangles.Add(vertIndex_2);
                newTriangles.Add(newVertices.Count - 2);

                newTriangles.Add(newVertices.Count - 1);
                newTriangles.Add(newVertices.Count - 2);
                newTriangles.Add(vertIndex_3);

                // Add the new colors to the colors list
                newColors.Add(Color.black);
                newColors.Add(Color.black);
                newColors.Add(Color.black);

                // Update the triangle index to the new triangle
                triangles[hit.triangleIndex] =  newTriangles.Count / 3 - 1;
                
            }
            
            if (verticesOccur_2 > 1)
            {
                // Add the new vertices to the vertices list
                newVertices.Add(vertPos_1);
                newVertices.Add(vertPos_2);
                newVertices.Add(vertPos_3);

                // Add the new triangles to the triangles list
                newTriangles.Add(vertIndex_1);
                newTriangles.Add(newVertices.Count - 3);
                newTriangles.Add(newVertices.Count - 1);

                newTriangles.Add(newVertices.Count - 3);
                newTriangles.Add(vertIndex_2);
                newTriangles.Add(newVertices.Count - 2);

                newTriangles.Add(newVertices.Count - 1);
                newTriangles.Add(newVertices.Count - 2);
                newTriangles.Add(vertIndex_3);

                // Add the new colors to the colors list
                newColors.Add(Color.black);
                newColors.Add(Color.black);
                newColors.Add(Color.black);

                // Update the triangle index to the new triangle
                triangles[hit.triangleIndex] =  newTriangles.Count / 3 - 1;
            }
            
            if (verticesOccur_3 > 1)
            {
                // Add the new vertices to the vertices list
                newVertices.Add(vertPos_1);
                newVertices.Add(vertPos_2);
                newVertices.Add(vertPos_3);

                // Add the new triangles to the triangles list
                newTriangles.Add(vertIndex_1);
                newTriangles.Add(newVertices.Count - 3);
                newTriangles.Add(newVertices.Count - 1);

                newTriangles.Add(newVertices.Count - 3);
                newTriangles.Add(vertIndex_2);
                newTriangles.Add(newVertices.Count - 2);

                newTriangles.Add(newVertices.Count - 1);
                newTriangles.Add(newVertices.Count - 2);
                newTriangles.Add(vertIndex_3);

                // Add the new colors to the colors list
                newColors.Add(Color.white);
                newColors.Add(Color.green);
                newColors.Add(Color.yellow);

                // Update the triangle index to the new triangle
                triangles[hit.triangleIndex] =  newTriangles.Count / 3 - 1;
            }
            // Update the mesh with the new data
            mesh.vertices = newVertices.ToArray();
            mesh.triangles = newTriangles.ToArray();
            //mesh.uv = newUV.ToArray();
            mesh.colors = newColors.ToArray();


            // Update the indices of the hit triangle to use the (eventually) new
            // vertices instead
            triangles[hit.triangleIndex * 3 + 0] = vertIndex_1;
            triangles[hit.triangleIndex * 3 + 1] = vertIndex_2;
            triangles[hit.triangleIndex * 3 + 2] = vertIndex_3;
            
            // Now we can simply add the new triangle
            newTriangles.Add(vertIndex_1);
            newTriangles.Add(vertIndex_2);
            newTriangles.Add(vertIndex_3);
            
            // color these vertices
            newColors[vertIndex_1] = Color.red;
            newColors[vertIndex_2] = Color.red;
            newColors[vertIndex_3] = Color.red;


            //color the mesh
             mesh.colors = newColors.ToArray();

            // Recalculate the normals
            mesh.RecalculateNormals();
        }
        else 
        {
            //reset the colors back to original
            var colors = new Color[mesh.vertices.Length];

            for(var i = 0; i < colors.Length; i++)
            {
                colors[i] = Color.black;
            }

            mesh.colors = colors;
            Debug.Log("No hit");
        }
    }
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • have you tried debugging your 3 `verticesOccur_XY > 1` checks? Also you overwrite all three `newColors[vertIndex_XY] = Color.red;` after wards so I wouldn't be too suprised by them all being red .... ? – derHugo Dec 05 '22 at 10:29

1 Answers1

0

I have not really used Unity, but I have done some other work with 3D models.

It looks like you are using vertex colors, with these there is no real way to color an individual triangle. A colored vertex will partially color all triangles it is part of. So your results look just like I would expect.

One workaround for this is to just create unique vertices for each triangle. But this will also force flat-shading, and may have other undesirable effects. You could possibly also generate new triangles in a separate mesh.

Probably the best way would be to associate each triangle with a color-index, and use a shader to apply the correct color. But I have no idea how to do that in unity.

Note that if you want to do anything with "neighboring" triangles/vertices you will need to traverse the graph formed by the mesh. One way to do this efficiently is to use a data structure that contain connectivity in some searchable form, like a (half)Winged edge structure.

JonasH
  • 28,608
  • 2
  • 10
  • 23