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

Question How to get the triangles of the face of a cube

Discussion in 'Scripting' started by Biell2015, Sep 16, 2023.

Thread Status:
Not open for further replies.
  1. Biell2015

    Biell2015

    Joined:
    Aug 8, 2017
    Posts:
    19
    I'm throwing a Raycast in a face of a cube, getting the hit.point where it hitted and the I can determine what face of the cube it hitted, and the vertices that it is made, but I'm not able to determine what triangle this vertices are forming.

    Code (CSharp):
    1. RaycastHit hit;
    2.  
    3. if(!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
    4. {
    5.     return;
    6. }
    7.  
    8. Mesh mesh = hit.transform.GetComponent<MeshFilter>().sharedMesh;
    9. Vector3[] vertices = mesh.vertices;
    10. List<Vector3> matchedVertices = new List<Vector3>();
    11.  
    12. foreach (Vector3 vertice in vertices)
    13. {
    14.     var realX = hit.transform.TransformPoint(vertice).x;
    15.     var realY = hit.transform.TransformPoint(vertice).y;
    16.     var realZ = hit.transform.TransformPoint(vertice).z;
    17.  
    18.     bool xBool = (hit.point.x == realX);
    19.     bool yBool = (hit.point.y == realY);
    20.     bool zBool = (hit.point.z == realZ);
    21.  
    22.     if (xBool)
    23.     {
    24.         matchedVertices.Add(vertice);
    25.     }
    26.     else if (yBool)
    27.     {
    28.        matchedVertices.Add(vertice);
    29.     }
    30.     else if (zBool)
    31.     {
    32.         matchedVertices.Add(vertice);
    33.     }
    34. }
    I tried looping through matchedVertices and get the distance between the vertices and hit.point, to select the 3 nearest ones to form a triangle, but I did not succeed.
     
    Last edited: Sep 16, 2023
  2. irene_reko

    irene_reko

    Joined:
    Feb 14, 2019
    Posts:
    11
    The RaycastHit has a property triangleIndex. The documentation has an example code for accessing the triangle vertices:

    Code (CSharp):
    1. Mesh mesh = meshCollider.sharedMesh;
    2. Vector3[] vertices = mesh.vertices;
    3. int[] triangles = mesh.triangles;
    4. Vector3 p0 = vertices[triangles[hit.triangleIndex * 3 + 0]];
    5. Vector3 p1 = vertices[triangles[hit.triangleIndex * 3 + 1]];
    6. Vector3 p2 = vertices[triangles[hit.triangleIndex * 3 + 2]];
     
    SaariTech and Bunny83 like this.
  3. Biell2015

    Biell2015

    Joined:
    Aug 8, 2017
    Posts:
    19
    My cube has a BoxCollider, from what I know, triangleIndex only works on MeshColliders.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    I've read your post several times now and I still don't understand what you're asking. You hit a BoxCollider but want to know what triangle it hits. What triangle is this? It's a box primitive, not a mesh from a MeshFilter as would be used by a MeshCollider.

    Are you saying you have a Mesh that is a Box (with triangles, normals etc) but perform a raycast against a BoxCollider primitive and want to find which triangle its an equivalent in the separate mesh? Wouldn't it be easier to use a MeshCollider here so you can use the triangle index?

    If not, you need to use the normals too of the hit which will give you the (presumably) one of two triangles in your mesh. You can then check the hit point against each triangle.
     
    Bunny83 likes this.
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    If you insist on NOT using a MeshCollider then you would need to use the position returned by the Raycast and then spin all the polygons you wish to consider (remember, there is no direct reference between BoxColliders, CapsuleColliders and SphereColliders and any "happens to be here" mesh they might be approximating!!) and find the closest one.

    Otherwise, here's the standard easy MeshCollider solution wrapped up in a demo scene:

    https://github.com/kurtdekker/makegeo/blob/master/makegeo/Assets/ClickTriangle/ClickTriangle.cs
     
    DragonCoder and Bunny83 like this.
  6. Biell2015

    Biell2015

    Joined:
    Aug 8, 2017
    Posts:
    19
    Yes I have a Primitive Cube, there isn't even the word "Mesh" in my original post, I don't know why are you assuming that I was talking about anything else besides a Primitive Cube, and Primitive Cubes doesn't came with a MeshCollider, if not I would use it.
     
  7. Biell2015

    Biell2015

    Joined:
    Aug 8, 2017
    Posts:
    19
    Why Unity Colliders (CapsuleColliders, BoxColliders, etc. Or the MeshFilter component, since you can retrieve the vertices and triangles of a primitive cube from it.) doesn't have a function to retrieve a triangle index? Do they assumed that no one would try to do this? Basically if I want a script to remove triangles from primitives for some reason, I would have to make a custom prefab of the primitives with a MeshCollider in them or modify it, putting a MeshCollider in it and duplicate it? It's seems bad for me.

    Here, the code that I used to delete the triangle:
    Code (CSharp):
    1. RaycastHit hit;
    2.  
    3. var camera = Camera.main;
    4.  
    5. if (!Physics.Raycast (camera.ScreenPointToRay(Input.mousePosition), out hit))
    6. {
    7.    return;
    8. }
    9.  
    10. var meshCollider = hit.collider as MeshCollider;
    11.  
    12. if (meshCollider == null || meshCollider.sharedMesh == null)
    13.    return;
    14.  
    15. var mesh = meshCollider.sharedMesh;
    16. var triangles = mesh.triangles;
    17. var p0 = triangles[hit.triangleIndex * 3 + 0];
    18. var p1 = triangles[hit.triangleIndex * 3 + 1];
    19. var p2 = triangles[hit.triangleIndex * 3 + 2];
    20.  
    21. for (int i = 0; i < triangles.Count; i+=3)
    22. {
    23.     bool trianglePoint1 = (triangles[i + 0] == p0);
    24.     bool trianglePoint2 = (triangles[i + 1] == p1);
    25.     bool trianglePoint3 = (triangles[i + 2] == p2);
    26.  
    27.     if (trianglePoint1 && trianglePoint2 && trianglePoint3)
    28.     {
    29.         triangles.RemoveRange(i, 3);
    30.     }
    31. }
    32. mesh.Clear();
    33. mesh.vertices = vertices;
    34. mesh.triangles = triangles;
    35. hit.transform.gameObject.GetComponent<MeshCollider>().mesh = mesh;
    36.  
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Remove the BoxCollider, add a MeshCollider.
     
  9. Biell2015

    Biell2015

    Joined:
    Aug 8, 2017
    Posts:
    19
    There is some way to get the another triangle of the same face with the information that I got? Modifying "hit.triangleIndex * 3 + x" doesn't work, I tried a lot of combinations, all the other triangles that are being deleted are in another faces of the cube.
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Don't try combinations. That's not engineering. Instead, try your hand at debugging your problem.

    Nobody here can do it for you because we're not running your code in your exact setup on your exact machine.

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    If your problem is with OnCollision-type functions, print the name of what is passed in!

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
  11. Biell2015

    Biell2015

    Joined:
    Aug 8, 2017
    Posts:
    19
    Here's the exact code that I'm using.
    Please, if you don't know how to help me, just don't say anything, it would be better that no help.
     
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Sorry but I feel the need to respond to this because you said it here....
    ... and here ...
    ... and you were told that using a MeshCollider means you can get the triangle index directly from the raycast but despite Kurt giving you code that works, you've now said....
    That's not how forums work. If you don't communicate what you're doing, we have to guess what you need. The forums are not here to write code for you. Kurt was trying to explain that you need to debug your code not just "trying combinations" which is a fair point.

    So to try to help .....

    You're now asking for code that, given a specific triangle index in the mesh, finds another triangle that lives on the same "face". A way to do that is to do what I original stated which is go through the triangles checking their normals to see if they are the same as the triangle you hit. This would be the fastest way assuming it's a small mesh (cube). Of course, if you know that a triangle on the same face is always going to be immediately before or after the one you have then you can simply check those for a match (using the normal).
     
  13. Biell2015

    Biell2015

    Joined:
    Aug 8, 2017
    Posts:
    19
    Don't worry you 2, since you don't want to explain S*** neither show code, I myself will search it, and I found a gentlement that explain better than you AND show code where I can follow and try to understand what is happening. Here is the link::https://forum.unity.com/threads/how-do-i-get-the-normal-of-each-triangle-in-mesh.101018/

    To solve this, first you calculate the normals of each point of the triangle that the Raycast hitted:
    Code (CSharp):
    1.  
    2. var normalHittedTriangle0 = normals[triangles[hit.triangleIndex * 3 + 0]];
    3. var normalHittedTriangle1 = normals[triangles[hit.triangleIndex * 3 + 1]];
    4. var normalHittedTriangle2 = normals[triangles[hit.triangleIndex * 3 + 2]];
    5.  
    And them the normal of the face of the cube:
    Code (CSharp):
    1.  
    2. var hittedTriangleNormal = ((normalHittedTriangle0 + normalHittedTriangle1 + normalHittedTriangle2) / 3);
    3.  
    And them you loop through all the triangles in the Cube. Get the normal of each point of the triangle, get the normal of the whole triangle and check if it match with the normal of the triangle that the Raycast hitted, if it matched add it to a list.
    Code (CSharp):
    1.  
    2. List<int> trianglesToRemove = new List<int>();
    3.  
    4. for (int i = 0; i < triangles.Length; i += 3)
    5. {
    6.         var p0 = vertices[triangles[i + 0]];
    7.         var p1 = vertices[triangles[i + 1]];
    8.         var p2 = vertices[triangles[i + 2]];
    9.  
    10.         p0 = normals[triangles[i + 0]];
    11.         p1 = normals[triangles[i + 1]];
    12.         p2 = normals[triangles[i + 2]];
    13.  
    14.         if (((p0 + p1 + p2) / 3) == hittedTriangleNormal)
    15.         {
    16.                 trianglesToRemove.Add(triangles[i + 0]);
    17.                 trianglesToRemove.Add(triangles[i + 1]);
    18.                 trianglesToRemove.Add(triangles[i + 2]);
    19.         }
    20. }
    21.  
    Loop through the triangles of the Cube by a step of 3 (because triangles are grouped by 3), find the 2 triangles that match with the list and then if it matched, remove it from the triangles of the Cube.
    Code (CSharp):
    1.  
    2. for (int i = 0; i < triangles.Length; i+=3)
    3. {
    4.         bool v1 = (triangles[i + 0] == trianglesToRemove[0]);
    5.         bool v2 = (triangles[i + 1] == trianglesToRemove[1]);
    6.         bool v3 = (triangles[i + 2] == trianglesToRemove[2]);
    7.  
    8.         if ((v1 && v2 && v3))
    9.         {
    10.                 triangles.RemoveRange(i, trianglesToRemove.Count);
    11.         }
    12. }
    13.  
    All the code:
    Code (CSharp):
    1.  
    2. if (Input.GetMouseButtonUp(0))
    3. {
    4.         RaycastHit hit;
    5.  
    6.         var camera = Camera.main;
    7.  
    8.         if (!Physics.Raycast (camera.ScreenPointToRay(Input.mousePosition), out hit))
    9.         {
    10.            return;
    11.         }
    12.  
    13.         var meshCollider = hit.collider as MeshCollider;
    14.  
    15.         if (meshCollider == null || meshCollider.sharedMesh == null)
    16.            return;
    17.  
    18.         var mesh = meshCollider.sharedMesh;
    19.         var triangles = mesh.triangles;
    20.         var normals = mesh.normals;
    21.         Transform objectPosition = hit.transform;
    22.  
    23.         var normalHittedTriangle0 = normals[triangles[hit.triangleIndex * 3 + 0]];
    24.         var normalHittedTriangle1 = normals[triangles[hit.triangleIndex * 3 + 1]];
    25.         var normalHittedTriangle2 = normals[triangles[hit.triangleIndex * 3 + 2]];
    26.  
    27.         var hittedTriangleNormal = ((normalHittedTriangle0 + normalHittedTriangle1 + normalHittedTriangle2) / 3);
    28.  
    29.         List<int> trianglesToRemove = new List<int>();
    30.  
    31.         for (int i = 0; i < triangles.Length; i += 3)
    32.         {
    33.             var p0 = vertices[triangles[i + 0]];
    34.             var p1 = vertices[triangles[i + 1]];
    35.             var p2 = vertices[triangles[i + 2]];
    36.  
    37.             p0 = normals[triangles[i + 0]];
    38.             p1 = normals[triangles[i + 1]];
    39.             p2 = normals[triangles[i + 2]];
    40.  
    41.             if (((p0 + p1 + p2) / 3) == hittedTriangleNormal)
    42.             {
    43.                 trianglesToRemove.Add(triangles[i + 0]);
    44.                 trianglesToRemove.Add(triangles[i + 1]);
    45.                 trianglesToRemove.Add(triangles[i + 2]);
    46.             }
    47.         }
    48.  
    49.         GameObject newCube = new GameObject();
    50.         newCube.transform.position = objectPosition;
    51.  
    52.         newCube.AddComponent<MeshFilter>();
    53.         newCube.AddComponent<MeshRenderer>();
    54.  
    55.         for (int i = 0; i < triangles.Length; i+=3)
    56.         {
    57.             bool v1 = (triangles[i + 0] == trianglesToRemove[0]);
    58.             bool v2 = (triangles[i + 1] == trianglesToRemove[1]);
    59.             bool v3 = (triangles[i + 2] == trianglesToRemove[2]);
    60.  
    61.             if ((v1 && v2 && v3))
    62.             {
    63.                 triangles.RemoveRange(i, trianglesToRemove.Count);
    64.             }
    65.         }
    66.  
    67.         mesh.Clear();
    68.         mesh.vertices = vertices;
    69.         mesh.triangles = triangles;
    70.         newCube.GetComponent<MeshFilter>().mesh = mesh;
    71. }
    72.  
     
    Last edited: Sep 17, 2023
  14. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    We collectively wish you the best! Let us know how it goes.
     
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    If you wish to continue using these forums, please stop with this aggressive tone. You are also being aggressive to someone who even provided you with part of your solution above.

    It has no place on these forums.
     
    Bunny83 and irene_reko like this.
Thread Status:
Not open for further replies.