Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Click to select mesh triangle?

Discussion in 'Editor & General Support' started by Kobus, Feb 10, 2016.

  1. Kobus

    Kobus

    Joined:
    Mar 27, 2015
    Posts:
    48
    Hi
    I am busy with a complex mesh that I want to be able to deform and manipulate at run-time. The mesh has almost 10000 triangles. The mesh forms an object with multiple sections. I did not create the initial mesh so I am trying to analyse the mesh by determining which triangles form which sections. With this information I will be able to deform any section of the mesh as required.
    I thought the easiest way to be able to determine which triangles form which section is to be able to click on it and print in the console the index of the triangle in the int[] array.
    I have created a script. When the mouse moves over the object in the game view the particular triangle is highlighted in the scene view (See attached image. I am just using a capsule here for demonstration purposes). This is done by drawing lines on the edges. When the mouse moves away from the triangle it is no longer highlighted. When I am over the triangle I want to investigate I click the mouse button and the index of the triangle is printed by using Debug.log().

    This works okay, but I would like to be able to see all the triangle that I have clicked on to be displayed permanently in a different color. This will allow me to see all the triangle as a unit and this will make it easier to determine accurately if they all should be part of the same section. This is especially important where one section changes into the next section. When I click on a triangle a second time it should change its color back to the original color (i.e. selecting/deselecting it).

    Can anyone assist me with this?

    My script currently is as follows:

    Code (CSharp):
    1. // This script draws a debug line around mesh triangles
    2. // as you move the mouse over them.
    3. using UnityEngine;
    4. using System.Collections;
    5.  
    6. public class TriangleInfo : MonoBehaviour {
    7.  
    8.     public Camera camera;
    9.  
    10.     private float duration = 0f;
    11.     private Color lineColor = Color.red;
    12.  
    13.  
    14.     void OnMouseDown()
    15.     {
    16.         AnalyseTriangle();
    17.     }
    18.  
    19.  
    20.     void Update()
    21.     {
    22.         HighlightTriangle();
    23.     }
    24.  
    25.  
    26.     void HighlightTriangle()
    27.     {
    28.         RaycastHit hit;
    29.         if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
    30.         {
    31.             return;
    32.         }
    33.  
    34.         MeshCollider meshCollider = hit.collider as MeshCollider;
    35.         if (meshCollider == null || meshCollider.sharedMesh == null)
    36.         {
    37.             return;
    38.         }
    39.  
    40.         Mesh mesh = meshCollider.sharedMesh;
    41.         Vector3[] vertices = mesh.vertices;
    42.         int[] triangles = mesh.triangles;
    43.  
    44.         Vector3 p0 = vertices[triangles[hit.triangleIndex * 3 + 0]];
    45.         Vector3 p1 = vertices[triangles[hit.triangleIndex * 3 + 1]];
    46.         Vector3 p2 = vertices[triangles[hit.triangleIndex * 3 + 2]];
    47.  
    48.         Transform hitTransform = hit.collider.transform;
    49.         p0 = hitTransform.TransformPoint(p0);
    50.         p1 = hitTransform.TransformPoint(p1);
    51.         p2 = hitTransform.TransformPoint(p2);
    52.  
    53.         Debug.DrawLine(p0, p1, lineColor, duration);
    54.         Debug.DrawLine(p1, p2, lineColor, duration);
    55.         Debug.DrawLine(p2, p0, lineColor, duration);
    56.     }
    57.  
    58.  
    59.     void AnalyseTriangle()
    60.     {
    61.         RaycastHit hit;
    62.         if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
    63.         {
    64.             return;
    65.         }
    66.  
    67.         MeshCollider meshCollider = hit.collider as MeshCollider;
    68.         if (meshCollider == null || meshCollider.sharedMesh == null)
    69.         {
    70.             return;
    71.         }
    72.  
    73.         Mesh mesh = meshCollider.sharedMesh;
    74.         Vector3[] vertices = mesh.vertices;
    75.         int[] triangles = mesh.triangles;
    76.         int triangleIndex = hit.triangleIndex;
    77.         Debug.Log("hit.triangleIndex = " + hit.triangleIndex);
    78.     }
    79.  
    80.  
    81. }
    82.  
    I know it is not the most efficient code, but for now I have just been struggling to get it to work.
     

    Attached Files:

  2. LeJawa

    LeJawa

    Joined:
    Oct 1, 2020
    Posts:
    3
    I know this is a 6-year-old question but I found it when having a similar problem and the file shared put me right on track to finally solving it. I therefore wanted to pay forward my gratitude to you. So thanks for that!
    Please be aware that my solution didn't involve any textures and I am pretty sure it will not work with one.

    This is my modified script - my changes are at the very end of the AnalyseTriangle method:

    Code (CSharp):
    1. using UnityEngine;
    2. // This script draws a debug line around mesh triangles
    3. // as you move the mouse over them.
    4. // Copied from https://forum.unity.com/threads/click-to-select-mesh-triangle.385270/
    5.  
    6. namespace com.gravitygames.uwgame {
    7.     public class TriangleInfo : MonoBehaviour {
    8.    
    9.         public Camera camera;
    10.    
    11.         private float duration = 0f;
    12.         private Color lineColor = Color.red;  
    13.    
    14.         void Update()
    15.         {
    16.             if (Input.GetMouseButtonDown(0)) {
    17.                 AnalyseTriangle();
    18.             }
    19.          
    20.          
    21.             HighlightTriangle();
    22.         }
    23.    
    24.    
    25.         void HighlightTriangle()
    26.         {
    27.             RaycastHit hit;
    28.             if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
    29.             {
    30.                 return;
    31.             }
    32.    
    33.             MeshCollider meshCollider = hit.collider as MeshCollider;
    34.             if (meshCollider == null || meshCollider.sharedMesh == null)
    35.             {
    36.                 return;
    37.             }
    38.    
    39.             Mesh mesh = meshCollider.sharedMesh;
    40.             Vector3[] vertices = mesh.vertices;
    41.             int[] triangles = mesh.triangles;
    42.    
    43.             Vector3 p0 = vertices[triangles[hit.triangleIndex * 3 + 0]];
    44.             Vector3 p1 = vertices[triangles[hit.triangleIndex * 3 + 1]];
    45.             Vector3 p2 = vertices[triangles[hit.triangleIndex * 3 + 2]];
    46.    
    47.             Transform hitTransform = hit.collider.transform;
    48.             p0 = hitTransform.TransformPoint(p0);
    49.             p1 = hitTransform.TransformPoint(p1);
    50.             p2 = hitTransform.TransformPoint(p2);
    51.    
    52.             Debug.DrawLine(p0, p1, lineColor, duration);
    53.             Debug.DrawLine(p1, p2, lineColor, duration);
    54.             Debug.DrawLine(p2, p0, lineColor, duration);
    55.         }
    56.    
    57.    
    58.         void AnalyseTriangle()
    59.         {
    60.             RaycastHit hit;
    61.             if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
    62.             {
    63.                 return;
    64.             }
    65.    
    66.             MeshCollider meshCollider = hit.collider as MeshCollider;
    67.             if (meshCollider == null || meshCollider.sharedMesh == null)
    68.             {
    69.                 return;
    70.             }
    71.    
    72.             Mesh mesh = meshCollider.sharedMesh;
    73.             Vector3[] vertices = mesh.vertices;
    74.             int[] triangles = mesh.triangles;
    75.             int triangleIndex = hit.triangleIndex;
    76.  
    77.             var colors = mesh.colors;
    78.  
    79.             Color color = Color.green;
    80.             bool checkIfAlreadySelectedTriangle = colors[triangles[triangleIndex * 3]] == Color.green;
    81.             if (checkIfAlreadySelectedTriangle) {
    82.                 color = Color.blue;
    83.             }
    84.          
    85.             colors[triangles[triangleIndex * 3]] = color;
    86.             colors[triangles[triangleIndex * 3 + 1]] = color;
    87.             colors[triangles[triangleIndex * 3 + 2]] = color;
    88.          
    89.             mesh.Clear();
    90.  
    91.             mesh.vertices = vertices;
    92.             mesh.triangles = triangles;
    93.             mesh.colors = colors;
    94.          
    95.             Debug.Log("hit.triangleIndex = " + triangleIndex);
    96.         }
    97.     }
    98. }
    This works... partially with a "normal" mesh. The issue being the color gradient created between vertices.
    To solve this I increased the number of vertices so that a vertex only belongs to one triangle. The end result is that the vertices and triangles arrays ended up being the same size. Here is a snippet of my code to convert the mesh. The arrays vertices and triangles are defined earlier in the script.

    Code (CSharp):
    1. var verticesArray = new Vector3[triangles.Length];
    2. int verticesArrayIndex = 0;
    3.  
    4. foreach (var index in triangles) {
    5.     var position = new Vector3(vertices[index].X, vertices[index].Y, 0f);
    6.     verticesArray[verticesArrayIndex++] = position;
    7. }
    8.  
    9. for (int i = 0; i < triangles.Length; i++) {
    10.     triangles[i] = i;
    11. }
    12.  
    13. var colors = new Color[verticesArray.Length];
    14. for (int i = 0; i < verticesArray.Length; i++) {
    15.     colors[i] = Color.blue;
    16. }
    17.  
    18. Mesh mesh = new Mesh {
    19.     vertices = verticesArray,
    20.     triangles = triangles,
    21.     colors = colors
    22. };
    23.  
    24. gameObject.GetComponent<MeshFilter>().mesh = mesh;
    25. gameObject.GetComponent<MeshCollider>().sharedMesh = mesh;
    My solution works great for me because I am in 2D with meshes with relatively small number of vertices. Not sure how well it scales in 3D with models with high poly numbers...
     

    Attached Files: