How to draw a triangle in the center of a line using GL?

I am making a node-based custom editor window (something like the animator window). I now can draw nodes and edges between them. The thing I want to do now is to draw a triangle arrowhead in the middle of the edge (like the one you see in the animator window). From this post , I started to try GL to draw the triangle. Here’s my code:

private void OnGUI()
     {
         // Do other stuff...
         Vector2 startPos = ...; // The start position (Center of the from node. This is from the node's rect which mean it used the rect's coordinate system)
         Vector2 endPos = ...; // The end position (Center of the to node. Also from a rect)

         Vector2 center = MathUtils.Average(startPos, endPos); // The center of the current edge
         Vector2 dir = (endPos - startPos).normalized; // The direction of the current egde

         // Making an equilateral triangle
         Vector3 a = center + dir                               * 10; // From the center move 10 more unit along the line's direction
         Vector3 b = center + Rotate(dir,  120 * Mathf.Deg2Rad) * 10; // Rotate the dir  120 degree and move along that direction 10 more unit
         Vector3 c = center + Rotate(dir, -120 * Mathf.Deg2Rad) * 10; // Rotate the dir -120 degree and move along that direction 10 more unit

         // The coordinate of the GUI is (0, 0) on the top left conner, this will convert it to the normal GL coordinate ((0, 0) on the bottom left connor)
         // Also the position property is a inheritance property from the EditorWindow (in case you don't know)
         a.y = position.height - a.y;
         b.y = position.height - b.y;
         c.y = position.height - c.y;

         // InverseLerp will return the value from [(0, 0), (1, 1)] because that what GL.Vertex() use
         a = InverseLerp(Vector2.zero, position.size, a);
         b = InverseLerp(Vector2.zero, position.size, b);
         c = InverseLerp(Vector2.zero, position.size, c);

         DrawGLTriangle(a, b, c); // Draw the triangle
         Handles.DrawAAPolyLine(10, startPos, endPos); // Draw the egde between the two current nodes

         // Do other stuff...
     }

     public static Vector2 InverseLerp(Vector2 start, Vector2 end, Vector2 value)
     {
         return (value - start) / (end - start);
     }

     public static Vector2 Rotate(Vector2 v, float angle)
     {
         return new Vector2(
         v.x * Mathf.Cos(angle) - v.y * Mathf.Sin(angle),
         v.x * Mathf.Sin(angle) + v.y * Mathf.Cos(angle)
     );
     }

     // This function is directly taken from Unity https://docs.unity3d.com/ScriptReference/GL.TRIANGLES.html
     public static void DrawGLTriangle(Vector3 a, Vector3 b, Vector3 c)
     {
         GL.PushMatrix();
         GL.LoadOrtho();
         GL.Begin(GL.TRIANGLES);
         GL.Vertex(a);
         GL.Vertex(b);
         GL.Vertex(c);
         GL.End();
         GL.PopMatrix();
     }

Here’s the result, the triangle is not on the line. Its x position seems correct but the y position is a little higher than it should be. It seems to rotate correctly.

Anyone?

I haven’t taken a deep look at your code, but try drawing a debug point at center to make sure your center is correct. If it’s correct, then your code may be computing the triangle points wrong. If it’s incorrect, then maybe the center is being offset by the height of the window heading (“State Machine”).

@TonyLi The center is correct. I tested it before and just tested it again, still exactly on the center of the line.
I also think that the problem comes from the triangle points. Even if I set one of them to the center, it didn’t draw correctly (the Y is still above the center but the X works well). The computing of the triangle consists of two parts: Create the points and convert them from the GUI coordinate to the GL coordinate. The first part works fine, I think it’s the second part that fails. Here’s the converting part:

Did you check if it’s offset by the height of the title bar?

How high is the title bar? In the above code, I just flip it by removing y from position.height (a.y = position.height - a.y).

I believe, depending on your Unity version, the title bar height is determined by the GUI skin’s window style border, and position.height includes the height of the title bar.

The GL class actually uses the whole screen to draw, including the editor window tab height (You can access it with Screen.safeArea). I was clamping the value between 0 and position.height (doesn’t include the tab height) so that’s why the Y coordinate didn’t align correctly (account for the tab height). Just change the code to this:

// GL use the whole screen and clamp it to [0,1] but position doesn't include the window tab height so need to use Screen.height and Screen.safeArea
        a.y = Screen.height - a.y;
        b.y = Screen.height - b.y;
        c.y = Screen.height - c.y;

        // Remove the height of the window tab.
        a.y -= 21;
        b.y -= 21;
        c.y -= 21;

        // Return the value in [(0, 0), (1, 1)] because that what GL.Vertex use
        a = MathUtils.InverseLerp(Vector2.zero, Screen.safeArea.size, a);
        c = MathUtils.InverseLerp(Vector2.zero, Screen.safeArea.size, c);
        b = MathUtils.InverseLerp(Vector2.zero, Screen.safeArea.size, b);

Also, if you want to know how high is the window tab just use something like:

Debug.Log(Screen.height - position.height);