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 Label Mesh Face Index at Triangle Center

Discussion in 'Scripting' started by mysticvalleycsa, Jan 13, 2021.

  1. mysticvalleycsa


    Sep 22, 2020
    Toward An Advanced Collision Flags System

    For a state machine, it would be helpful to prep animations and actions to react intuitively/naturally to impacts in various directions. Unity's prebuilt character controller class is inadequate for my project. So I've come up with a few options for responsive code:
    Mathematic domains of spherical segments. I'm exploring some algorithms, but it doesn't seem as adaptive of a solution as the other, which had the added benefit of trivial implementation.

    A custom mesh collider, with faces indexed to relate to top left, top left forward, left center up, centroids, etc.,. In order to do so, I had to create a diagnostic.

    Goal: Map the Index of a Face to Its Center, Horizontal to Scene View
    I built a metaball in Rhino3d; Blender & Unity confirmed its coherence. A cube with each face divided in 9, further split from quads to tris, should make 56quads, 112 tris. Rounding down the corners has produced 108 after import into Unity.

    I copied the array of face indices of the attached mesh
    In a for loop, multiplied the relevant index position times three, incremented twice after for each vertex. Cache the averaged result in a new array, piped it to GUI.Label.

    Yesterday it was logging the averaged position fine, not sure what I changed, but today it only logs the length of triangle array.

    Either way, the IMGUI is not displaying anything.

    ( I cleared the index out of bounds exception by dividing in the field.)

    Code (CSharp):
    1.     public GameObject metaball;
    2.     public Mesh mesh;
    3.     private Vector3[] vertices;
    4.     private int[] triangles;
    5.     private Vector3[] meshFaceCent;
    6.     Vector3 baryCenter;
    7.     int trianglesCount;
    9.     private void Awake()
    10.     {
    11.         Mesh mesh = GetComponent<MeshFilter>().mesh;
    12.         vertices = mesh.vertices;
    13.         triangles = mesh.triangles;
    14.     }
    15.     private void Start()
    16.     {
    17.         int trianglesCount = triangles.Length/3;
    18.         Debug.Log("Triangles Count:" + triangles.Length);
    20.          BaryCenter();
    21.          OnGUI();
    22.     }
    24.     private Vector3[] BaryCenter()
    25.     {
    26.         for (int i = 0; i < trianglesCount; i++)
    27.         {
    28.             Vector3 n0 = vertices[triangles[(i * 3) + 0]];
    29.             Vector3 n1 = vertices[triangles[i * 3 + 1]];
    30.             Vector3 n2 = vertices[triangles[i * 3 + 2]];
    32.             Vector3 baryCenter = (n0 + n1 + n2) / 3;
    33.             Console.WriteLine("Coordinates of Face {0} are: {1}", i, baryCenter);
    34.             meshFaceCent[i] = baryCenter;
    35.         }
    36.         return meshFaceCent;
    37.     }
    39.     void OnGUI()
    40.     {
    41.         for (int i = 0; i < trianglesCount; i++)
    42.             GUI.Label(new Rect(meshFaceCent[i].x - 0.05f, meshFaceCent[i].y - 0.05f, 0.5f, 0.5f), i.ToString());
    43.     }

    Attached Files:

    Last edited: Jan 13, 2021
  2. mysticvalleycsa


    Sep 22, 2020
    I'm beginning to think that I have misunderstood IMGUI and it is geared more toward dynamic lexical/comm activity--instead I should use a text object. It just came up as a "developer tool" when I searched label arrays. I'm learning as I go here. I've been spoiled by the grasshopper library, which has many tools which are prefabs of common function patterns. I'll find it, but I'm interested in further discussion about what an advanced collision & impact prep system may look like.

    Particularly, for an acrobatic low-gravity game. Does it seem like a good idea to distribute actions into separate interaction and locomotion classes?
    Last edited: Jan 13, 2021
  3. Bunny83


    Oct 18, 2010
    Well, there are several things a bit strange. First of all, never manually call OnGUI. It's an event processor that is called by Unity. Every call is paired with the data provided in Event.current and all GUI methods rely on that data. While this single call from Start probably won't hurt (It may cause an exception but since it's at the end of start it doesn't matter) you should generally never do this.

    The next issue I see is your private "meshFaceCent" array. It seems you never actually create an instance of that array, so the variable would be null and you would receive a null reference exception anytime you try accessing the array's content.

    Finally mesh vertices are specified in local space coordinates of the mesh. Depending on the objects transform (position, rotation and scale) the object may be located somewhere totally different in worldspace. Finally the worldspace is mapped to the screen with a camera which also involves a transformation and finally a projection to screen space.

    GUI coordinates also have their y component inverted since GUI space has its origin at the top left screen corner while normal screenspace has its origin at the bottom left. So it seems very very strange that you use the local space face center positions as GUI coordinates.

    Your next issue is that you redeclared your triangleCount variable inside Start so you never set the triangleCount variable of your class, so it always stays at 0.

    So in short even with quite a few changes your script could have never worked in that state. Furthermore in your screenshot you get an index out of bounds exception. That's not really possible from the code you've shown. So there may be some code missing or you have already changed some of that code. This generally does not help to debug your problem. You should never fix a bug you don't understand.
  4. mysticvalleycsa


    Sep 22, 2020
    Thank you for your input, I resolved it that week but I missed uploading by the weekend and it's slipped my mind until now.

    It was as I expected: IMGUI was not was I was looking for. I grappled textmeshpro and swapped it in. It worked, with a minor hiccup: the arbitrarily placed text object I used for reference (I didn't internalize it) became the last item in the series, and 0 was duplicated. Also, the textbox didn't rotate to parallel with the face.
    Here is the functional script:

    Code (CSharp):
    1. using UnityEngine;
    2. using TMPro;
    4. public class Metaball_Triangle_Index : MonoBehaviour
    5. {
    6.     public GameObject metaball;
    7.     public Mesh mesh;
    8.     private Vector3[] vertices;
    9.     private int[] triangles;
    10.     Vector3[] meshFaceCenter = new Vector3[108];
    11.     Vector3 baryCenter;
    12.     int trianglesCount;
    13.     TextMeshPro go_tmp;
    14.     Vector3[] l_normals;
    15.     Quaternion[] q_faceTurn = new Quaternion[108];
    17.     private void Awake()
    18.     {
    19.         Mesh mesh = GetComponentInChildren<MeshFilter>().mesh;
    20.         vertices = mesh.vertices;
    21.         triangles = mesh.triangles;
    22.         go_tmp = GetComponentInChildren<TextMeshPro>();
    23.         l_normals = mesh.normals;
    25.     }
    26.     private void Start()
    27.     {
    28.         trianglesCount = triangles.Length/3;
    29.         Debug.Log("Triangles Count:" + trianglesCount);
    30.         BaryCenter();
    31.         BCNormal();
    32.         DisplayIndices();
    33.     }
    35.     private Vector3[] BaryCenter()
    36.     {
    37.         for (int i = 0; i < trianglesCount; i++)
    38.         {
    39.             Vector3 n0 = vertices[triangles[(i * 3) + 0]];
    40.             Vector3 n1 = vertices[triangles[i * 3 + 1]];
    41.             Vector3 n2 = vertices[triangles[i * 3 + 2]];
    43.             baryCenter = (n0 + n1 + n2) / 3;
    44.             Debug.Log(($"Coordinates of Face {0} are: {1}", i, baryCenter));
    45.             meshFaceCenter[i] = baryCenter;
    46.         }
    47.         return meshFaceCenter;
    48.     }
    50.     //not working:  may be an issue of converting quaternion to euler
    51.     private Quaternion[] BCNormal()
    52.     {
    53.         for (int i = 0; i < trianglesCount; i++)
    54.         {
    55.             Vector3 n0 = l_normals[triangles[i * 3 + 0]];
    56.             Vector3 n1 = l_normals[triangles[i * 3 + 1]];
    57.             Vector3 n2 = l_normals[triangles[i * 3 + 2]];
    59.             baryCenter = (n0 + n1 + n2) / 3;
    60.             Debug.Log(($"Coordinates of Face {0} are: {1}", i, baryCenter));
    61.             q_faceTurn[i] = Quaternion.Euler(baryCenter);
    62.         }
    63.         return q_faceTurn;
    64.     }
    66.     void DisplayIndices()
    67.     {
    68.         for (int i = 0; i < trianglesCount; i++)
    69.         {
    70.             //Rect coreRect = new Rect(meshFaceCenter[i].x - 0.05f, meshFaceCenter[i].y - 0.05f, 0.5f, 0.5f);
    71.             Instantiate(go_tmp, meshFaceCenter[i], q_faceTurn[i], metaball.transform);
    72.             go_tmp.SetText(i.ToString());
    73.                 //new Rect(meshFaceCenter[i].x - 0.05f, meshFaceCenter[i].y - 0.05f, 0.5f, 0.5f), i.ToString());
    74.         }
    75.     }
    76. }
    I tested it on the same obj with the same import settings in my main project, and sadly, it was different. Instances were static, however. Documentation says this is the only time it's optimized and cleaned, but I worry it might change when the full package is compiled or if I cross platforms. I guess I'll slog through internalization if that happens.

    So next step, I believe, is to create a hash id table, and distribute to the animator as parameters and input/command classes for each action state. Anything else I should consider?

    Attached Files:

  5. mysticvalleycsa


    Sep 22, 2020
    Oh and I know it looks like there are more duplicates but that's just because the text wrapped (I resized the textbox after screenshot). If I seem messy, I'm just doing a rush, I figure I'll come back to niceties like internalizing and immutability after I get proof of concept.