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 Transforming local polygon points to Word Position

Discussion in 'Scripting' started by Digika, Sep 3, 2023.

  1. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    I have a 2D polygon:

    Extents: 2, 0.75, 0
    Center: -160, 49.25, 0
    Points: (4, -1.5) (0, -0.5), (0, 0) and (4, -1)

    How can I calculate world coordinates of the local points that make up polygon? Simple naive solution would be just addition of the vectors, just add each to the center, however, it obviously does not work and the results are wrong.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    Bunny83 likes this.
  3. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    Au contraire, it handles it perfectly.

    Go back and check over your work. You're doing something else.

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. // @kurtdekker
    4. //
    5. // Transforms arbitrary local space points (such as what
    6. // you can extract from a Mesh) to world space.
    7. //
    8. // to use:
    9. //    - put this on the target Transform in question
    10. //    - press run
    11. //    - transform (wiggle) the Transform we're on and observe the telltale
    12. //        - move it
    13. //        - rotate it
    14. //        - scale it
    15. //
    16.  
    17. public class TransformPoint : MonoBehaviour
    18. {
    19.     GameObject telltale;        // something for us to watch
    20.  
    21.     void Start ()
    22.     {
    23.         telltale = GameObject.CreatePrimitive( PrimitiveType.Cube);
    24.     }
    25.  
    26.     void Update ()
    27.     {
    28.         // simulated local point we're gonna transform
    29.         Vector3 localPoint = new Vector3( 1, 2, 0);
    30.  
    31.         // transform!
    32.         Vector3 worldPoint = transform.TransformPoint( localPoint);
    33.  
    34.         // display
    35.         telltale.transform.position = worldPoint;
    36.     }
    37. }
     
    Bunny83 likes this.
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    EDIT: I read this as PolygonCollider2D, forgive me if this isn't the case. Nevertheless, I'll leave this info here as it might help someone. :)


    Here's an example of how to do it:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class PolygonOutline : MonoBehaviour
    5. {
    6.    public PolygonCollider2D PolygonCollider;
    7.  
    8.    private readonly List<Vector2> m_Path = new();
    9.  
    10.    private void OnDrawGizmos()
    11.    {
    12.        if (!PolygonCollider)
    13.          return;
    14.  
    15.       // Fetch the polygon path.
    16.       var vertexCount = PolygonCollider.GetPath(0, m_Path);
    17.  
    18.       // Fetch the polygon path and transform it to world-space.
    19.       var colliderTransform = PolygonCollider.transform.localToWorldMatrix;
    20.       for (var i = 0; i < vertexCount; ++i)
    21.          m_Path[i] = colliderTransform.MultiplyPoint(m_Path[i]);
    22.  
    23.       // Draw the path.
    24.       Gizmos.color = Color.yellow;
    25.       for (var i = 0; i < vertexCount; ++i)
    26.       {
    27.          var j = (i + 1) % vertexCount;
    28.          Gizmos.DrawLine(m_Path[i], m_Path[j]);
    29.       }
    30.    }
    31. }
    As a note: the path isn't an actual physics shape so instead you can get the actual physics shape(s) that the polygon (or any collider) produces with Collider2D.GetShapes along with the local-to-world matrix to transform those shapes with Rigidbody2D.localToWorld (and Collider2D.localToWorld) but you cannot use these Matrix4x4 for the path. They also don't contain any scaling as that is already baked into the physics shape(s).

    Finally, you can also create a representation as a planar mesh if you desire with Collider2D.CreateMesh and Collider2D.GetShapeHash to detect if the shapes have changed.

    Hope that helps.
     
    Last edited: Sep 4, 2023
  6. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    Collider2D.CreateMesh does not exist for me in 2021.x Unity.

    Do you know how to properly calculate local-to-world points of a BxoCollider2D, taking into account rotation and center offset from GO? You can't simply use bounds here because it implies default position with enter synced to GO/parent.
     
  7. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    The docs state it does.
     
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    I believe that landed in 2019.3.

    Bounds are not useful at all in this case as they're an AABB i.e. a non-rotated encapsulating box.

    It's pretty trivial, something like this:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DrawBoxGizmo : MonoBehaviour
    4. {
    5.     public BoxCollider2D Box;
    6.     public Color GizmoColor = Color.white;
    7.  
    8.     private readonly Vector3[] m_Vertices = new Vector3[4];
    9.  
    10.     private void OnDrawGizmos()
    11.     {
    12.         if (!Box)
    13.             return;
    14.  
    15.         // Fetch the box details.
    16.         var boxTransform = Box.transform;
    17.         var boxSize = Box.size;
    18.         var extents = new Vector3(boxSize.x * 0.5f, boxSize.y * 0.5f, 0f);
    19.         var offset = (Vector3)Box.offset;
    20.  
    21.         // Calculate the box vertices.
    22.         m_Vertices[0] = offset - extents;
    23.         m_Vertices[1] = offset + new Vector3(-extents.x, extents.y);
    24.         m_Vertices[2] = offset + extents;
    25.         m_Vertices[3] = offset + new Vector3(extents.x, -extents.y);
    26.  
    27.         // Transform the box.
    28.         boxTransform.TransformPoints(m_Vertices);
    29.  
    30.         // Draw the vertices.
    31.         Gizmos.color = GizmoColor;
    32.         var vertexCount = m_Vertices.Length;
    33.         for (var s = 0; s < vertexCount; ++s)
    34.         {
    35.             var t = (s + 1) % vertexCount;
    36.             Gizmos.DrawLine(m_Vertices[s], m_Vertices[t]);
    37.         }
    38.     }
    39. }
    40.  
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Note: TransformPoints came in 2022 with Span<T> support so in earlier versions, just iterate the points using TransformPoint but obviously it's not critical to the answer which is contained in lines 22-28.
     
  10. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    I see, thanks.
    And last question - how can I flatten the transform hierarchy under which CircleCollider2D is buried (lets say this component attached to a gameObject which has parent which has parent which has parent and all the parents have different scales) to get the final/effective scaled radius?

    Code (CSharp):
    1. r = r * Mathf.Max(Mathf.Abs(c2d.transform.lossyScale.x), Mathf.Abs(c2d.transform.lossyScale.x));
    gives me incorrect results
     
    Last edited: Sep 6, 2023
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Is there a reason you keep asking about different specific colliders? Polygon then Box now Circle. The result is the same really, I don't follow the specific question you're asking. It's just the Transform stuff above.
     
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    But to answer your question; you can grab the single shape it creates (CircleShape) and read that radius (using the GetShapes API above) or if you want to just calculate it without reading the shape, you can do:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DrawCircleScript : MonoBehaviour
    4. {
    5.     public CircleCollider2D Circle;
    6.     public Color GizmoColor = Color.white;
    7.  
    8.     private void OnDrawGizmos()
    9.     {
    10.         if (Circle == null)
    11.             return;
    12.  
    13.         var circleTransform = Circle.transform;
    14.  
    15.         // Fetch the transform scale.
    16.         var scale = circleTransform.lossyScale;
    17.        
    18.         // Scale the circle radius by the maximum of the XY scale.
    19.         // NOTE: Ellipse is not supported so this is used.
    20.         var scaledRadius = Circle.radius * Mathf.Max(scale.x, scale.y);
    21.  
    22.         // Draw it.
    23.         Gizmos.color = GizmoColor;
    24.         Gizmos.DrawSphere(circleTransform.position + (Vector3)Circle.offset, scaledRadius);
    25.     }
    26. }
    27.  
     
  13. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    Yeah, I working with collider shapes.

    How complex would be to calculate the tris for the concave polygon2D (it already provides .points in order)? The convex seem simple enough, you can use one vertex as a centerpiece, but this wont work with concave.
     
  14. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    At least respond to my post above; did it help?

    Whilst I'm happy to help, endless questions without responses isn't something I'm here for TBH.
     
    Bunny83 likes this.
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Try looking at the links above I've mentioned twice now. It gives you the actual shapes it produces.
     
  16. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    I dont have function to generate mesh from the 2Dcollider in this version of Unity, hence why are the questions.
    I dont know when `Create2DMesh` was introduced but it is not applicable to me anyway, I can't swap.

    Regardless, I appreciate all the help so far @MelvMay!
     
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    You do, you're not reading the posts above:

    https://forum.unity.com/threads/tra...points-to-word-position.1487883/#post-9275364

    Simplt look at the version drop down in the scripting docs and select your Unity version and you'll see it's there.

    https://docs.unity3d.com/2021.2/Documentation/ScriptReference/Collider2D.CreateMesh.html
    https://docs.unity3d.com/2021.2/Documentation/ScriptReference/Collider2D.GetShapes.html
     
  18. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    As I mentioned before, I cannot change the environment configuration. I decomplied Unity assemblies and this function is not present, hence, as I mentioned before, all my questions.
     
  19. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Nobody has said you need to change your Unity Version.

    You're doing something wrong then if you cannot see it so you need to fix that on your side; not ask for equivalent functionality for what's already there. ;)

    Unity 2021.3.30f1 although I get the same in 2019.3:
    CreateMesh.png

    2019.3 source reference:
    https://github.com/Unity-Technologi...indings/Physics2D.bindings.cs#L3291C1-L3291C1
     
  20. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    Yes, I understand but as I said I do not have that function, nor the means to change something to have it.
    Right now my only issues are basic geometry:
    * generate verts/tris for polygons (+ special case for concave, but for now I ignore them)
    * generate verts/tris for circle
     
  21. Digika

    Digika

    Joined:
    Jan 7, 2018
    Posts:
    225
    @Kurt-Dekker
    Nope. If PolygonCollider2D has an offset, TransformPoint fails spectacularly.
     
  22. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    Then you just add the offset...
     
    Bunny83 and Kurt-Dekker like this.
  23. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    Your post started with:

    Local coordinates are taken generally to mean, "points in the local coordinate space of the Transform."

    When you write this:

    That means those are NOT local coordinates.

    Those are offset local coordinates.

    As Spiney says, deoffset them, then offset them back after you transform.

    It's just data. Understand the data. Don't get hung up on it like it's something special. It's not.
     
    Bunny83 likes this.
  24. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    I'm sorry but it's impossible to not have that method if you're using 2019.3 onwards. Methods don't just disappear. Something else is going on here. o_O

    You seem to be arguing against things like TransformPoint saying that it doesn't work but it works perfectly in the example I took the time to write for you here and that handles offset correctly so did you try it?

    https://www.nuget.org/packages/LibTessDotNet
    https://github.com/AngusJohnson/Clipper2


    I believe I've provided enough information for all your questions here now so good luck.
     
  25. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    Let me guess, you try to manipulate a third party game and inject your own code into it? That may be why you don't have the method because the original developer probably used code stripping? If that's the case, you don't really develop a Unity game...
     
    Kurt-Dekker likes this.