- Home /
Procedural mesh's normals are reversed (Solved)
So I am trying to generate a procedural mesh, but I am encountering problems with the normals.
I find this very strange, since the mesh itself seems to be of the right shape. Here is my attempt to explain the code, if anyone ends up wanting to help me:
Based on a variable called "mapsize", I populate an array, blobVerts[], with the position of each vertex. If mapsize is set to 10, then the result is a 10x10 units mesh. (Note that mapverts is just mapsize + 1, because there's one more vertex per row than there are squares)
On alternating rows, the x-value is shifted over by 0.5 units. This gets the zigzag pattern
The triangles are generated in batches of two, with six indices handled in each batch. The "CurrentRow" switch statement is used to alternate the pattern of the batch. Within each batch, the six indices are calculated based on a pivotal vertex. this central vertex is held by the "g" variable (Which is actually being reused from the earlier Vertex section... ugh).
That's about all I can think of to explain it for now. If anyone has questions, such as "Jesus dude, where did you learn to program? The Internet!?", please ask. So here's the code:
blobVerts = new BlobVertex[mapverts * mapverts];
blobVertsArray = new Vector3[mapverts * mapverts];
blobUV = new Vector2[mapverts * mapverts];
blobTriangles = new int[(mapsize * mapsize * 6)];
//Populate the blobVerts class array
for (int i = 0; i < blobVerts.Length; i++)
{
blobVerts[i] = new BlobVertex();
}
//VERTICES
int g = 0;
int row = 3;
//Set the vertices to fill the map grid
for (int i = 0; i < mapverts; i++)
{
for (int h = 0; h < mapverts; h++)
{
blobVerts[g].position = new Vector3(h - ((row % 2) * .5f), 0, i);
g = g + 1;
}
row++;
}
//Transfers positions from blobVerts[].position to blobVertsArray
UpdateBlobVertsArray();
//END VERTICES
//UV
Debug.Log("blobUV.Length: " + blobUV.Length);
// Set the UV verts
for (int i = 0; i < blobUV.Length; i++)
{
//Debug.Log("i = " i);
blobUV[i].x = 0;
blobUV[i].y = 0;
}
//END UV
//TRIANGLES
// Set the triangles
// Interger "h" corresponds with the batch of triangles (form a square)
// Interger "g" is reused as a holder for the real starting vertex in each batch
g = 0;
row = 2;
for (int h = 0; h < (mapsize * mapsize); h++)
{
//this is my attempt at skipping the last vertex in each row, since it does not have a square
if ((g + 1) >= mapverts && (g + 1) % mapverts == 0)
g++;
//Cycle through the six vertices for a pair of triangles (parallelogram)
for (int i = 0; i < 6; i++)
{
int triIndex = (h * 6) + i;
switch((CurrentRow(g) + 2) % 2)
{
case 0:
switch (i)
{
case 5:
blobTriangles[triIndex] = g + mapsize + 2;
break;
case 4:
blobTriangles[triIndex] = g + mapsize + 1;
break;
case 3:
blobTriangles[triIndex] = g + 1;
break;
case 2:
blobTriangles[triIndex] = g + mapsize + 1;
break;
case 1:
blobTriangles[triIndex] = g + 1;
break;
case 0:
blobTriangles[triIndex] = g;
break;
}
break;
case 1:
switch (i)
{
case 5:
blobTriangles[triIndex] = g + mapsize + 2;
break;
case 4:
blobTriangles[triIndex] = g + 1;
break;
case 3:
blobTriangles[triIndex] = g;
break;
case 2:
blobTriangles[triIndex] = g + mapsize + 2;
break;
case 1:
blobTriangles[triIndex] = g + mapsize + 1;
break;
case 0:
blobTriangles[triIndex] = g;
break;
}
break;
}
}
g++;
row++;
}
//END TRIANGLES
EDIT: Here's a few more images to demonstrate what is happening.
With a texture (viewed from the bottom)
Err... Here's something that might be a silly question since I might've just missed it, but... Where are you actually setting normals? I don't see you creating a Vector3[] with normal vectors in it anywhere, and I don't see you assign anything to the mesh either?
Well this is enlightening. I hadn't seen any mention of setting normals. Should I avoid the "RecalculateNormals()" function then and go for something more manual? Do you have a link to documentation on this? Thanks for the reply. :D
The answer to my issue may lie in this post: http://answers.unity3d.com/questions/32100/how-do-i-manually-calculate-normals-for-my-meshes.html
:P I'll let you folks know if it works for me.
I'll readily admit to being a little confused here, myself. I usually create normals manually, but the ReCalculateNormals method should assign an array of normals for you, as well. Looking at the picture above, I don't understand why part of the mesh doesn't have its wireframe showing. Is that because the normals point the wrong way in that area? What does this look like if you assign a material?
I've added an image of it with a texture. It acts the way it should, considering the normals. Perhaps I should just get a shader without Culling enabled, but I've heard that the "reverse" side often has lighting issues.
Answer by aldonaletto · Nov 20, 2011 at 02:03 PM
It seems your problem is already solved, but just to let you know about this triangle winding thing, here goes a drawing:
The winding order informs which's the front side: if the vertices are in clockwise order, you're looking to the front face; if in counter-clockwise order, it's the back face and you will see nothing (unless the shader is double sided). In the drawing above, triangle 1 must be composed by vertices [1,2,4] (or [2,4,1] or [4,1,2]), and triangle 2 by vertices [2,3,4] (or [3,4,2] or [4,2,3]). Since vertices 2 and 4 in this drawing are common to both triangles, usually we calculate their indices and store in two variables, then assign the six vertices based on these variables:
int v2 = ...; // calculate index of vertex 2 int v4 = ...; // calculate index of vertex 4 verts[i++] = v2-1; verts[i++] = v2; verts[i++] = v4; verts[i++] = v2; verts[i++] = v2+1; verts[i++] = v4;NOTE: The pseudo code above is based on the vertices 1..4 showed in the drawing above; it must be changed if the vertices are stored in a different order.
Thanks for the in depth explanation. Hopefully this will prove to be helpful to the next person who finds this.
Answer by Kilometers · Nov 20, 2011 at 01:27 PM
I narrowed it down to two things. First was the blob.Optimize() function. When I comment it out of the code, I get a correct-looking mesh:
However, this only got me halfway there. When I added a texture, things got interesting again:
So I decided to start messing around with the triangle batches. By switching the order in which the vertices where added to the blobTriangle array, I finally got it to work:
Thanks for the help, Christian. I'm still not sure exactly why this worked. There seems to be something about the order in which the vertices are assigned to triangles that affects their (and the surrounding triangles') face normals. Really weird.
EDIT: blobOptimize() was not part of the cause. It was just covering up the problem with the triangles. Also, Christian pointed out that when assigning vertices to the triangles, the order of assignment (clockwise vs counter-clockwise) affects the orientation of the mesh. That was my problem.
I'm +1'ing your question and answer just because you've been great at providing additional information and demonstrative images. :) I wish everyone took their own questions this seriously.
If you're interested in more background information on winding order and clockwise/counterclockwise face culling, I think one of the most exhaustive and well-known resources is the OpenGL Program$$anonymous$$g Guide, the so called "Red Book". It is available as a PDF here:
http://paginas.fe.up.pt/~jbarbosa/ensino/SG/2005-2006/OpenGL%20Program$$anonymous$$g%20Guide.pdf
That page lets you save a copy as well. Do a search for the term "clockwise". It will lead you to relevant parts of the book that explain this concept. In summary, it has to do with the OpenGL convention, that vertices which appear in counterclockwise order in a polygon on the screen are considered front-facing. If they appear in clockwise order, the rendering system considers that polygon to be back-facing, and culls it (causing those gaps you've seen). Unity's mesh class and its triangle array is essentially a wrapper around this same functionality; it draws polygons in the order you declare their vertices in. If some are counterclockwise while others are clockwise, you'll get triangles culled in unexpected ways.
Your answer
Follow this Question
Related Questions
Custom Mesh Normals Problem 1 Answer
How do I combine normals on procedural mesh with multiple tiles? 2 Answers
Are normals from Mesh.RecalculateNormals() normalized? 1 Answer
Unity Mesh Rendering Issue 0 Answers
Holes in procedural mesh 0 Answers