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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Reversing normals

Discussion in 'General Graphics' started by koljo45, Jul 28, 2016.

  1. koljo45

    koljo45

    Joined:
    Nov 1, 2015
    Posts:
    3
    Hi,

    I'm working in unity for quite a while now and only recently have I noticed an interesting thing concerning normals when the triangle array of a mesh is edited. When I want to recalculate normals I edit Mesh.normals array and call Mesh.RecalculateNormals(). In one of my projects I was editing normals as well as adding new triangles and I stumbled across a problem. About a third of triangles were rendered with inverted normals. I didn't know how to solve this problem because I was 100% sure my normals were calculated correctly. I found this ReverseNormals script. It seams that vertices have a specific order in the triangle that can be edited as well. After this I tried to make the triangles render the other way around just by changing the order of indices in the trianges array, I didn't call Mesh.RecalculateNormals(), It worked (just kept the triangles part from ReverseNormals). From documentation for Mesh.RecalculateNormals():
    . I guess these calculations depend on vertex order in the triangle.

    I made a script to visualize this more easily. I have no idea how unity does this but I used cross product. Maybe it takes the normals of the vertices in the triangle and uses those for recalculation (why is it sensitive to order then)?
    Code (CSharp):
    1.         Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
    2.  
    3.         Vector3[] vertices = mesh.vertices;
    4.         int[] triangles = mesh.triangles;
    5.  
    6.         Vector3 scale = new Vector3(5, 5, 5);
    7.         Color c = Random.ColorHSV();
    8.         c.a = 1;
    9.  
    10.         for(int i =0;i<triangles.Length; i += 3)
    11.         {
    12.             Vector3 v1 = vertices[triangles[i]];
    13.             Vector3 v2 = vertices[triangles[i + 1]];
    14.             Vector3 v3 = vertices[triangles[i + 2]];
    15.  
    16.             Vector3 center = (v1 + v2 + v3) / 3;
    17.             Vector3 normal = Vector3.Cross(v2 - v1, v3 - v1);
    18.             normal = Vector3.Scale(normal, scale);
    19.  
    20.             Debug.DrawLine(transform.TransformPoint(center), transform.TransformPoint(center + normal), c, 100);
    21.         }
    How does unity combine triangle data and per-vertex normals in these calculations? When do I need to use Mesh.RecalculateNormals?
     
  2. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    In graphics programming, you use the order of vertices in the triangle to determine whether you're looking at the back face or front face (clockwise order means it's a front face in Unity, "winding order" is the only way to determine which direction the triangle is facing based on vertex positions alone). Normals usually point in the direction the front face is facing, so vertex order matters when calculating normals based on vertex position. I would recalculate the normals after each time you edit the triangles or vertex positions.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,248
    Also if you're manually setting the normals, RecalculateNormals() actually blows those changes away.
     
  4. koljo45

    koljo45

    Joined:
    Nov 1, 2015
    Posts:
    3
    Thank you for your replies. I did notice the clockwise order. 0-1-2-0-1-2... I made a mistake when adding new triangles where I was using this order: 1-2, 0-2, 0-1. I made a mistake when assigning 0-2 instead of 2-0, this change fixed it. In my test I only changed the vertex order in the triangles array as in ReverseNormals and still got flipped normals without calling RecalculateNormals(). This means that you can just reorder vertices inside the triangle to flip the normals without calling the RecalculateNormals(). I read that assigning a new triangle array to the mesh causes the mesh to recalculate its bounds, maybe the same is true for the normals of the mesh. I guess that editing the normals of the mesh is faster and enables you to calculate the normals yourself. ReverseNormals script edits the triangles as well because if we were to call RecalculateNormals() the normals of the mesh would regain their values prior to the flipping of the normals, but if RecalculateNormals() is automatically called when triangles are reassigned there is no need to flip the normals yourself in the first place, just reorder the vertices inside the triangles and be done with it. Also this would mean that editing the normals before assigning new triangles to the mesh is pointless because they are going to get recalculated anyway.