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

[Solved]No shadows on generated mesh

Discussion in 'Scripting' started by Sebastianp-ta, Aug 25, 2016.

  1. Sebastianp-ta

    Sebastianp-ta

    Joined:
    Jul 22, 2015
    Posts:
    12
    Hello everyone,

    in my project with the procedural dungeon creation ( here ) i ran into another problem. It is not directly connected to the previous one so i am opening a new thread.

    After generating the 2d map i traced the borders and extracted multiple lines of 2D vertices. From these lines i am trying to build walls in 3d. This is what i get right now:

    pd_shadows.png

    I have a plane underneath the mesh, a directional light and also set the mesh to cast and receive shadows. Yet, i am not getting any shading on the "walls". This is my code:

    Code (CSharp):
    1. void BuildMesh () {
    2.        
    3.         Mesh mesh = GetComponent<MeshFilter>().mesh;
    4.  
    5.         mesh.Clear ();
    6.  
    7.         List<Vector3> meshVertices = new List<Vector3> ();
    8.         List<Vector2> meshUV = new List<Vector2>();
    9.         List<Vector3> meshNormals = new List<Vector3> ();
    10.         List<int> meshTriangles = new List<int> ();
    11.  
    12.         //Limiting to the first line, for debugging purpose
    13.         for (int i = 0; i < 1; i++) {
    14.  
    15.             int lineStart = meshVertices.Count;
    16.  
    17.             //borderLines is a List<List<Vector2>> and contains all borders on the map
    18.             if (borderLines[i].Count > 1) {
    19.  
    20.                 Debug.Log ( borderLines[i].Count );
    21.  
    22.                 //for each border 2d vertex a 3d vertex is generated and another above it.
    23.                 for (int j = 0; j < borderLines[i].Count; j++) {
    24.  
    25.                     meshVertices.Add (new Vector3 (borderLines [i] [j].x, 0.0f, borderLines [i] [j].y));
    26.                     meshUV.Add ( new Vector2((float)j % 2, 0.0f) );
    27.                     meshNormals.Add ( Vector3.one );
    28.                     meshVertices.Add (new Vector3 (borderLines [i] [j].x, 10.0f, borderLines [i] [j].y));
    29.                     meshUV.Add ( new Vector2((float)j % 2, 1.0f) );
    30.                     meshNormals.Add ( Vector3.one );
    31.  
    32.                 }
    33.  
    34.                 //Triangles are generated double sided because i do not know whats outside and whats inside
    35.                 for (int j = lineStart + 1; j < (borderLines [i].Count + lineStart); j++) {
    36.  
    37.                     meshTriangles.Add ((j - 1) * 2);
    38.                     meshTriangles.Add (((j - 1) * 2) + 1);
    39.                     meshTriangles.Add (j * 2);
    40.  
    41.                     meshTriangles.Add ((j - 1) * 2);
    42.                     meshTriangles.Add (j * 2);
    43.                     meshTriangles.Add (((j - 1) * 2) + 1);
    44.  
    45.                     meshTriangles.Add (((j - 1) * 2) + 1);
    46.                     meshTriangles.Add ((j * 2) + 1);
    47.                     meshTriangles.Add (j * 2);
    48.  
    49.                     meshTriangles.Add (((j - 1) * 2) + 1);
    50.                     meshTriangles.Add (j * 2);
    51.                     meshTriangles.Add ((j * 2) + 1);
    52.  
    53.                 }
    54.  
    55.             }
    56.  
    57.         }
    58.  
    59.         Debug.Log (meshVertices.Count);
    60.         Debug.Log (meshTriangles.Count);
    61.  
    62.         //Transferring the lists to arrays to store in the mesh
    63.         Vector3[] vertexHolder = new Vector3[meshVertices.Count];
    64.         for (int i = 0; i < meshVertices.Count; i++) {
    65.             vertexHolder [i] = meshVertices [i];
    66.         }
    67.         mesh.vertices = vertexHolder;
    68.         Vector2[] uvHolder = new Vector2[meshUV.Count];
    69.         for (int i = 0; i < meshUV.Count; i++) {
    70.             uvHolder [i] = meshUV [i];
    71.         }
    72.         mesh.uv = uvHolder;
    73.         int[] triangleHolder =  new int[meshTriangles.Count];
    74.         for (int i = 0; i < meshTriangles.Count; i++) {
    75.             triangleHolder [i] = meshTriangles [i];
    76.         }
    77.         mesh.triangles = triangleHolder;
    78.         Vector3[] normalHolder = new Vector3[meshNormals.Count];
    79.         for (int i = 0; i < meshNormals.Count; i++) {
    80.             normalHolder [i] = meshNormals[i];
    81.         }
    82.         mesh.normals = normalHolder;
    83.  
    84.         Debug.Log ("V: " + mesh.vertices.Length + " T: " + mesh.triangles.Length + " U: " + mesh.uv.Length);
    85.  
    86.         mesh.RecalculateBounds ();
    87.         mesh.RecalculateNormals ();
    88.  
    89.     }
    As always: it might be an obvious and stupid mistake, but i spend some time looking at it and cant find anything wrong. I am generating normals for each vertex (i know they are not correct but at least some form of shadowing or shading should show up even with all normals Vector3.one)

    Ideas?

    Thanks!
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    Do you have a material assigned to this mesh?
     
  3. Sebastianp-ta

    Sebastianp-ta

    Joined:
    Jul 22, 2015
    Posts:
    12
    Hello,

    yes,i have a material on the object. In the screenshot above i forgot to add it. Here is a screenshot with the actual Object. I added a standard Material to it and i have a plane and a cube in the scene to show that the directional light is casting shadows for other objects...

    pd_shadows2.png
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    Hmm, that's puzzling. I don't see anything obvious you're missing. I would say, try some different shaders — some shaders require tangents, for example, while some don't. Also be sure to look in the Console for errors or warnings.

    One little thing: instead of those for-loops to copy your lists into arrays, you can just use .ToArray to do it in one step. I don't think that has anything to do with the problem, but you may as well simplify your code.
     
    Sebastianp-ta likes this.
  5. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You're assign normals but then calling RecalculateNormals at the end of your mesh generation. If you're generating double-sided triangles but sharing vertices between both faces my guess would be that the normal calculation is barfing because it uses the average facing of the 3 vertices making up each triangle.

    It might be helpful to use a shader that visualizes normal direction as vertex color. There's an (old) example on this page if you scroll down a bit: https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html

    It's also worth mentioning that I believe you can turn backface culling off via shader so actually generating the geometry would only be necessary if you plan to apply different materials to each face - which it looks you might be planning to do anyway.
     
    guy_lateur and Sebastianp-ta like this.
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    That's a good point — at the very least, the calculated normals would be wrong for half the triangles. To do double-sided triangles properly, you need to double the vertices too.

    Another thing I've done on occasion is use Debug.DrawLine (in, say, Update) to draw all the normals as little lines.

    Well, or if you want them shaded correctly. If you turn backface culling off, the backfaces will be drawn but still shaded as if they're facing the other way. That's really only useful if you're using only diffuse or unlit shading, i.e. in cases where normals don't matter.

    Better would probably be to just figure out which way is "inside" and make the triangles face that way.

    So, @Sebastianp-ta, why don't you start by just taking out the doubled triangles... just make them always face the same way, based on the winding of the border lines. So, yeah, there's a 50% chance that any particular quad will be facing the wrong way until you figure out how to generate your border lines consistently, but at least you should see some shading, and it will help confirm or refute @KelsoMRK's excellent idea about the confused normals.
     
    KelsoMRK likes this.
  7. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Fair point. And I suppose I misspoke. That's technically not disabling backface culling but is just enabling a 2-sided mesh. Backface culling is the process of discarding triangles that face away from the camera in an effort to save rendering time. Not really pertinent to the conversation but I didn't want a graphics guru to come in here and call me on it. :)
     
    JoeStrout likes this.
  8. Sebastianp-ta

    Sebastianp-ta

    Joined:
    Jul 22, 2015
    Posts:
    12
    Hey!

    Thank you guys very much i think it might really be a problem with vertex sharing and recalculating the normals. I was so convinced that the problem had to be somewhere else that i forgot about the RecalculateNormals(). I commented it out and i got some form of shading and shadows working. I will now try to double the vertices to make it easier to calculate normals...

    Oh and the reason i did not use ToArray on the Lists was so i could examine each element with a debug output line... I know its not the best way but i was desperate ;) I will clean up and streamline the code when it works!
     
    Last edited: Aug 26, 2016
    JoeStrout likes this.
  9. Sebastianp-ta

    Sebastianp-ta

    Joined:
    Jul 22, 2015
    Posts:
    12
    pd_shadows3.png

    Aaand its working...

    Yes, you guys were right, it was a problem with the normals and reusing the vertices. I switched to creating two meshes, one for "front facing" and one for "back facing" triangles and combined them at the end.

    Here is the code that is working:

    Code (CSharp):
    1. void BuildMesh () {
    2.  
    3.         Mesh meshComponent = GetComponent<MeshFilter>().mesh;
    4.  
    5.         Mesh frontFaceMesh = new Mesh ();
    6.         Mesh backFaceMesh = new Mesh ();
    7.  
    8.         meshComponent.Clear ();
    9.         frontFaceMesh.Clear ();
    10.         backFaceMesh.Clear ();
    11.  
    12.         List<Vector3> meshVertices = new List<Vector3> ();
    13.         List<Vector2> meshUV = new List<Vector2>();
    14.         List<Vector3> frontFaceMeshNormals = new List<Vector3> ();
    15.         List<int> frontFaceMeshTriangles = new List<int> ();
    16.         List<Vector3> backFaceMeshNormals = new List<Vector3> ();
    17.         List<int> backFaceMeshTriangles = new List<int> ();
    18.  
    19.         for (int i = 0; i < 1; i++) {
    20.  
    21.             int lineStart = meshVertices.Count;
    22.  
    23.             if (borderLines[i].Count > 1) {
    24.  
    25.                 Debug.Log ( borderLines[i].Count );
    26.  
    27.                 for (int j = 0; j < borderLines[i].Count; j++) {
    28.  
    29.                     meshVertices.Add (new Vector3 (borderLines [i] [j].x, 0.0f, borderLines [i] [j].y));
    30.                     meshUV.Add ( new Vector2((float)j % 2, 0.0f) );
    31.                     frontFaceMeshNormals.Add ( Vector3.one );
    32.                     backFaceMeshNormals.Add ( Vector3.one * -1.0f );
    33.                     meshVertices.Add (new Vector3 (borderLines [i] [j].x, 10.0f, borderLines [i] [j].y));
    34.                     meshUV.Add ( new Vector2((float)j % 2, 1.0f) );
    35.                     frontFaceMeshNormals.Add ( Vector3.one );
    36.                     backFaceMeshNormals.Add ( Vector3.one * -1.0f );
    37.  
    38.                 }
    39.  
    40.                 for (int j = lineStart + 1; j < (borderLines [i].Count + lineStart); j++) {
    41.  
    42.                     frontFaceMeshTriangles.Add ((j - 1) * 2);
    43.                     frontFaceMeshTriangles.Add (((j - 1) * 2) + 1);
    44.                     frontFaceMeshTriangles.Add (j * 2);
    45.  
    46.                     backFaceMeshTriangles.Add ((j - 1) * 2);
    47.                     backFaceMeshTriangles.Add (j * 2);
    48.                     backFaceMeshTriangles.Add (((j - 1) * 2) + 1);
    49.  
    50.                     frontFaceMeshTriangles.Add (((j - 1) * 2) + 1);
    51.                     frontFaceMeshTriangles.Add ((j * 2) + 1);
    52.                     frontFaceMeshTriangles.Add (j * 2);
    53.  
    54.                     backFaceMeshTriangles.Add (((j - 1) * 2) + 1);
    55.                     backFaceMeshTriangles.Add (j * 2);
    56.                     backFaceMeshTriangles.Add ((j * 2) + 1);
    57.  
    58.                 }
    59.  
    60.             }
    61.  
    62.         }
    63.  
    64.         Debug.Log (meshVertices.Count);
    65.         Debug.Log (frontFaceMeshTriangles.Count);
    66.  
    67.         Vector3[] vertexHolder = new Vector3[meshVertices.Count];
    68.         for (int i = 0; i < meshVertices.Count; i++) {
    69.             vertexHolder [i] = meshVertices [i];
    70.         }
    71.         frontFaceMesh.vertices = vertexHolder;
    72.         backFaceMesh.vertices = vertexHolder;
    73.  
    74.         Vector2[] uvHolder = new Vector2[meshUV.Count];
    75.         for (int i = 0; i < meshUV.Count; i++) {
    76.             uvHolder [i] = meshUV [i];
    77.         }
    78.         frontFaceMesh.uv = uvHolder;
    79.         backFaceMesh.uv = uvHolder;
    80.  
    81.         int[] frontFaceTriangleHolder =  new int[frontFaceMeshTriangles.Count];
    82.         int[] backFaceTriangleHolder =  new int[backFaceMeshTriangles.Count];
    83.         for (int i = 0; i < frontFaceMeshTriangles.Count; i++) {
    84.             frontFaceTriangleHolder [i] = frontFaceMeshTriangles [i];
    85.             backFaceTriangleHolder [i] = backFaceMeshTriangles [i];
    86.         }
    87.         frontFaceMesh.triangles = frontFaceTriangleHolder;
    88.         backFaceMesh.triangles = backFaceTriangleHolder;
    89.  
    90.  
    91.         Vector3[] frontFaceNormalHolder = new Vector3[frontFaceMeshNormals.Count];
    92.         Vector3[] backFaceNormalHolder = new Vector3[backFaceMeshNormals.Count];
    93.         for (int i = 0; i < frontFaceMeshNormals.Count; i++) {
    94.             frontFaceNormalHolder [i] = frontFaceMeshNormals[i];
    95.             backFaceNormalHolder [i] = backFaceMeshNormals[i];
    96.         }
    97.         frontFaceMesh.normals = frontFaceNormalHolder;
    98.         backFaceMesh.normals = backFaceNormalHolder;
    99.  
    100.         Debug.Log ("V: " + frontFaceMesh.vertices.Length + " T: " + frontFaceMesh.triangles.Length + " U: " + frontFaceMesh.uv.Length);
    101.  
    102.         frontFaceMesh.RecalculateBounds ();
    103.         backFaceMesh.RecalculateBounds ();
    104.         frontFaceMesh.RecalculateNormals ();
    105.         backFaceMesh.RecalculateNormals ();
    106.  
    107.         Mesh[] meshArray = new Mesh[2];
    108.  
    109.  
    110.         CombineInstance[] meshCombine = new CombineInstance[2];
    111.  
    112.         meshCombine [0].mesh = frontFaceMesh;
    113.         meshCombine [0].transform = GetComponent<MeshFilter> ().transform.localToWorldMatrix;
    114.         meshCombine [1].mesh = backFaceMesh;
    115.         meshCombine [1].transform = GetComponent<MeshFilter> ().transform.localToWorldMatrix;
    116.  
    117.         meshComponent.CombineMeshes (meshCombine);
    118.  
    119.     }
    Yes, i was too lazy to calculate the normals by hand and just called RecalculateNormals in the end :)
     
    KelsoMRK and JoeStrout like this.
  10. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    That's not lazy, that's smart. If there's something you can let the engine do then by all means let it do it. Glad you got it figured out!