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 Interpreting and translating Mesh Vertex coords

Discussion in 'Scripting' started by eco_bach, Feb 2, 2021.

  1. eco_bach

    eco_bach

    Joined:
    Jul 8, 2013
    Posts:
    1,601
    I am attempting to make sense of vertex position or coordinate data in a generated mesh.
    https://docs.unity3d.com/ScriptReference/Mesh-vertices.html


    This is for an AR application but I think the question is more coding specific.

    I've attempted to translate the vertex coordinates to World space

    https://answers.unity.com/questions/1304791/getting-the-world-position-of-mesh-vertices.html

    But the values I am getting don't make any sense.

    But I am ALWAYS getting results that are normalized values between -2 and 2 rounded to a single decimal place. ie (1.1, -0.1,1.5).
    I am wondering if I'm simply not translating the coordinates correctly.

    Sample code
    Code (CSharp):
    1. Mesh mesh = meshFilter.mesh;
    2. Vector3[] meshVerts = mesh.vertices;
    3.  
    4. var matrix = transform.localToWorldMatrix;
    5.  
    6. Vector3 world_v1 = matrix.MultiplyPoint3x4(meshVerts[0]);
    7. Vector3 world_v2 = matrix.MultiplyPoint3x4(meshVerts[1]);
    8. Vector3 world_v3 = matrix.MultiplyPoint3x4(meshVerts[2]);
    9. Debug.Log("v1 = "+ world_v1);
    10. Debug.Log("v2 = "+ world_v2);
    11. Debug.Log("v3 = "+ world_v3);
    12.  
    Instead of matrix.MultiplyPoint3x4 also tried transform.TransformPoint and also transform.parent.gameObject.transform.TransformPoint (transform.parent.gameObject is the ArSession Origin).
    Results are always the same.
    Have been working on this for almost a full week!!

    Can any mesh gurus suggest some troubleshooting steps?
     
  2. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    664
    I may be way wrong, but I seem to recall that the ToString method for a Vector3 only prints one decimal place. Try printing the individual x, y, and z components one at a time (world_v1.x, etc.) and see if you get more precise values.
     
    Bunny83, PraetorBlue and Kurt-Dekker like this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    You want the matrix.MultiplyPoint() method.

    Code (csharp):
    1. // your code, haxed up:
    2. using UnityEngine;
    3.  
    4. public class zarb : MonoBehaviour
    5. {
    6.     private void Start()
    7.     {
    8.         var meshFilter = GetComponent < MeshFilter>();
    9.  
    10.         Mesh mesh = meshFilter.mesh;
    11.  
    12.         Vector3[] meshVerts = mesh.vertices;
    13.  
    14.         Debug.Log("points = " + meshVerts.Length);
    15.  
    16.         var matrix = transform.localToWorldMatrix;
    17.  
    18.         Debug.Log("v1 = " + meshVerts[0]);
    19.         Debug.Log("v2 = " + meshVerts[1]);
    20.         Debug.Log("v3 = " + meshVerts[2]);
    21.  
    22.         Vector3 world_v1 = matrix.MultiplyPoint(meshVerts[0]);
    23.         Vector3 world_v2 = matrix.MultiplyPoint(meshVerts[1]);
    24.         Vector3 world_v3 = matrix.MultiplyPoint(meshVerts[2]);
    25.  
    26.         Debug.Log("world1 = " + world_v1);
    27.         Debug.Log("world2 = " + world_v2);
    28.         Debug.Log("world3 = " + world_v3);
    29.     }
    30. }
    My test shape in Blender (a single tri):


    Screen Shot 2021-02-02 at 1.06.20 PM.png

    the transform:


    Screen Shot 2021-02-02 at 1.04.52 PM.png


    the output:

    Screen Shot 2021-02-02 at 1.04.59 PM.png
     
    Bunny83 likes this.
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,446
    Not really necessary. Using MultiplyPoint3x4 is actually better. Normal transformation matrices do not require a homogeneous divide so MultiplyPoint3x4 is cheaper and gives you the same result. Normal transform matrices always have a 4th row that looks like (0,0,0,1).

    Though in this case it doesn't make any difference. Your results look like they should. We need to know the exact gameobject hierarchy with values to make any sense of the OP results. Maybe there's a intermediate scale that is set to 0 or something like that. At the moment we don't even know the local space coordinates of the vertices. In addition without knowing the transform position, rotation and scale values of all parents we can't really tell if there's something wrong or not.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    That's as may be but the 3x4 method was a no-op. It returned the vert passed in using the setup above. That's what made me go looking for another op on matrix.

    Disclaimer: haven't formally studied linear algebra in multiple decades.
     
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,446
    Are you sure about that? Because that would be impossible ^^. MultiplyPoint is defined like this, while MultiplyPoint3x4 is defined like this. They do exactly the same besides that MultiplyPoint performs an additional homogeneous divide. However since the last row of a transformation matrix is (0,0,0,1), the "w" value inside that method will be 1f. So both methods will do exactly the same. You need to use MultiplyPoint when you do a projection as the projection matrix has values in the last row.

    I tried to explain the TSR matrix over here which might help a little bit.
     
  7. eco_bach

    eco_bach

    Joined:
    Jul 8, 2013
    Posts:
    1,601
    Thanks for the great feedback.
    I think my issue has nothing to do with coordinate space but rather that I don't have enough precision to begin with. Vertex coords seem to be rounded by default to a single decimal place.

    Code (CSharp):
    1. string svert0 =meshVerts[0].ToString( format: "F4");
    2. string svert1 =meshVerts[1].ToString( format: "F4");
    3. string svert2 =meshVerts[2].ToString( format: "F4");
    Instead of for instance (1.4, -0.3,-0.2)
    I now get (1.4218, -0.2653, -1.9529)!


    It also seems like a C# bug that you have to convert to a string to get greater accuracy!
    So unless I am mistaken if a coordinate space conversion is required I have to first convert each string value to a float.
    Create a new Vector3 from these floats.
    And only then do the coordinate space conversion using TransformPoint or matrix.MultiplyPoint on these new vec3's.
    Seems kind of ridiculous to me.
     
  8. bobisgod234

    bobisgod234

    Joined:
    Nov 15, 2016
    Posts:
    1,042

    How do you figure that from your above example? Your example shows clearly that the Vector3 stores more precision than the default toString() gives you, which in turn means that converting it to a string is only going to lose precision.

    Try this and see for yourself:

     
    Bunny83 likes this.
  9. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,446
    No, you got that wrong. The ToString method does round to 1 decimal place by default. The values are still just normal 32 bit floating point values. That's what Stevens already said in the first answer you got. Converting to a string has no effect on the actual value.

    Just have a look at the ToString method of the Vector3 struct. If you do not pass a custom format the default used format will be "F1", so you get one decimal place in the string output.

    What exactly brought you to this conclusion. At the moment it seems you only base your analysis on the string conversion of the values. So no, there is no bug, neither in C# nor in Unity. The one decimal rounding is the expected behaviour as they wanted to avoid printing out noise. If you need a higher precistion when you convert your Vector to a string you can supply a different format string. However the string conversion of the Vector has no effect on the actual values of the vector.

    So I guess your confustion is cleared up now?
     
    eco_bach and bobisgod234 like this.
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    Bunny, you're absolutely right... I must have simply misread the first run with with my initial setup and that led me to think I was getting the same values back, so I quickly changed it to the non-3x4 one, and I think that was also when I scaled up the transform to (3,3,3), which made the numbers more visually different rather than essentially just transposing from the (-90,0,0) Blender3D import rotation.

    debugging.png
     
    Bunny83 likes this.
  11. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    664
    Back when our systems were somewhat less reliable than they are today, my colleagues and I used an approach similar to Kurt's:

    upload_2021-2-3_9-45-15.png

    And remember that, if it hadn't been for long compiles, no one ever would have solved Rubik's Cube.
     
    Kurt-Dekker likes this.
  12. eco_bach

    eco_bach

    Joined:
    Jul 8, 2013
    Posts:
    1,601
    Last edited: Feb 6, 2021
  13. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,446
    Why should that be mentioned in the vertices documentation? It has nothing to do with the Mesh class or the vertices array. It's a property of the ToString method of the Vector3 struct. And as expected, it's mentioned there ^^.
     
    bobisgod234 likes this.
  14. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,336
    Also we know that Vector3 is 3 floats, so when you see a
    float
    printed as 0.1 you can be pretty sure it's truncated.