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

How do you manipulate vertices correctly?

Discussion in 'Scripting' started by Etwus, Jun 21, 2019.

  1. Etwus

    Etwus

    Joined:
    Dec 12, 2016
    Posts:
    18
    Lets say if I need to offset vertices of mesh by Vector3(3.0f, 3.0f, 3.0f), rotate them by 30 degrees in x axis and scale them by Vector3(2f, 2f, 2f), what would be the most efficient way?

    I have static class which holds multiple meshes (Loaded from resources), and I need to add them to main mesh and apply to them different positions, rotations and scaling.

    This is my solution so far: It looks quite uneffective, and I have no idea how to do rotations.

    Code (CSharp):
    1. public static Vector3[] TransformMesh(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 scale)
    2. {
    3.     Vector3[] vertices = mesh.vertices;
    4.     for (int i = 0; i < vertices.Length; i++)
    5.     {
    6.         vertices[i] = Vector3.Scale(vertices[i], scale) + position;
    7.     }
    8.     return vertices;
    9. }
     
  2. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    I'm not sure to understand what you are trying to do here.

    Do you really have to manipulate mesh vertices, or could you have a GameObject that hold a mesh as one of it's component, giving you the ability to easily manipulate it (rotation, scale, position..) So you would end up with a hierarchy of gameobject, having each one a meshRenderer.

    Or do you really need to have one final mesh (for optimization purpose maybe) ?

    "I have static class which holds multiple meshes (Loaded from resources), and I need to add them to main mesh and apply to them different positions, rotations and scaling."

    So i'm not sure of what is your final goal again, but it makes me think of having something like a terrain, and instanciating objects on it (like rocks or tree) in random position / rotation. If it is the case than you should probably create a bunch of prefab with your different meshes, and manipulate gameObjects.

    But again, I don't know what you are trying to achieve so thiis may be totally irrelevant ^^
     
  3. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,355
    Assuming you have each mesh as a separate object, I think you could simply apply different position, rotation, and scaling on each object by using the object's transform. Then, when everything is in place, combine them with the CombineMeshes function.
    https://docs.unity3d.com/ScriptReference/Mesh.CombineMeshes.html
     
    insominx and Thibault-Potier like this.
  4. Etwus

    Etwus

    Joined:
    Dec 12, 2016
    Posts:
    18
    Its going to be building system and I am very concerned about performance and mainly I hate using monobehaviours for global constants.

    Meshes should be avaible to all scenes, and should load at certain time. I am not using gameobjects for this, as I guess I can't instantiate gameobjects on separate thread (So far with my system I can handle 1 mil cubes at once without problems).

    Everything works, but I have no clue what to do about rotations.
     
  5. Etwus

    Etwus

    Joined:
    Dec 12, 2016
    Posts:
    18
    I figured it out.

    Code (CSharp):
    1.         public static Vector3[] TransformMesh(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 scale)
    2.         {
    3.            
    4.             Vector3[] vertices = mesh.vertices;
    5.             Matrix4x4 matrix = Matrix4x4.TRS(position, rotation, scale);
    6.             for (int i = 0; i < vertices.Length; i++)
    7.             {
    8.                 vertices[i] = matrix.MultiplyPoint(vertices[i]);
    9.             }
    10.             return vertices;
    11.         }
     
  6. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    Have you tested it to prove it is faster than your previous code? I really doubt it because scale + translate is just 3 multiplications and 3 additions, while matrix4x4 multiplication involves 64 multiply ops and 48 adds. You might gain much more performance writing non-allocating version of your code. And more, if you'll just combine those meshes as is and scale+translate your vertices using vertex shader. You may use additional shader channels to pass scale and translation vectors along with vertices.
     
  7. Etwus

    Etwus

    Joined:
    Dec 12, 2016
    Posts:
    18
    I did not test it, as I still have no idea how to do rotations without matrix multiplication.
     
  8. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    You want to rotate all vertices around the pivot of the mesh? The formula is simple
    Code (csharp):
    1.  x' = x cos θ − y sin θ
     
  9. Etwus

    Etwus

    Joined:
    Dec 12, 2016
    Posts:
    18
    I guess using sin and cos would be less effective than using matrix multiplications? Anyway, I measured matrix multiplication for 1 000 000 vertices, and I guess this will do. Sorry if I was not clear what I was asking for, I basically wanted to find way how to rotate vertex, and if possible, use some fancy function, that is already built into unity.
     
  10. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    Sine/cosine are not that hard to compute, see here https://www2.clarku.edu/faculty/djoyce/trig/compute.html Moreover, modern cpus and gpus use trigonometric tables to calculate results even faster. And you should know what using Matrix4x4.TRS already includes trigonometric calculations bot sin and cos for all rotation angles. So I think your guess is wrong. Looks like the fastest way it tio combine meshes as they are, send them to the GPU along with transformation data and transform vertices on GPU using simple formulas without matrix multiplication.
     
    Etwus likes this.
  11. Etwus

    Etwus

    Joined:
    Dec 12, 2016
    Posts:
    18
    Oh, I see. You are right, I was somehow thinking that I would need to recalculate trigonometric functions for every vertex, instead I should do it only once for mesh. Thanks for your patience, I will definitively try this.
     
  12. mysticcoder

    mysticcoder

    Joined:
    Oct 9, 2014
    Posts:
    7
    If you need CPU matrix multiply - set up the matrices before transformation and do your (hopefully parallel) transformations through that matrix on the input vertices / normals. Use Matrix4x4.TRS as commented in earlier posts.

    Don't listen to anyone saying "sin and cos" aren't expensive. They are pissing in your pocket and telling you it's raining. They are expensive. If you can not use them - don't. Unity has helper functions for this purpose.

    If there are enough vertices in the mesh / cluster - use a compute shader - if your platform(s) allow for it. When you are doing generic transformations on data that can be parallelized - consider compute shaders - for almost anything you want to accelerate. You will win.

    https://docs.unity3d.com/Manual/class-ComputeShader.html