- Home /
Odd lighting on procedurally generated mesh
I'm making a bunch of meshes based on a set of 2d coordinates and an extrusion modifier. The shape creation is working well (mostly, but that's another question), but I'm having trouble with normals/uvs. As you can see from this image, the lighting is very odd. I've followed this tutorial, but still end up with this odd lighting. Any suggestions?
The code specific to UV:
//Create the UV map. Nothing special here, copied and pasted.
Vector2[] uvs = new Vector2[AllVerts.Length];
for (int i=0; i<uvs.Length; i++) {
uvs[i] = new Vector2(AllVerts[i].x, AllVerts[i].z);
}
newMesh.uv = uvs;
newMesh.triangles = NewTriangles;
newMesh.RecalculateNormals();
The entire function:
//Given a name, list of points, and a depth, return a procedurally generated shape.
GameObject CreateObject(string name, List<Vector2> points, float depth){
if(depth < 0){ //TODO: Swap this into something that moves the plane down, or reverses triangles or vertices, for negatives
depth = Mathf.Abs(depth);
}
GameObject newObject = new GameObject(name);
newObject.AddComponent<MeshFilter>();
newObject.AddComponent<MeshRenderer>();
Mesh newMesh = new Mesh();
int howManyVerts = points.Count; //Count the number of verts on a flat surface
Vector3[] AllVerts = new Vector3[howManyVerts * 2]; //Twice as many verst as on a flab surface
List<int> TriangleList = new List<int>(); //Gotta put all of the triangles somewhere - defined by the index of 3 verts in AllVerts
for(int i = 0; i < howManyVerts; i++){
AllVerts[i] = new Vector3(points[i].x, 0, points[i].y); //Convert points to Vector3
AllVerts[i+howManyVerts] = new Vector3(points[i].x, depth, points[i].y); //Replaces with depth
if(i < howManyVerts-1){
//First triangle
TriangleList.Add (i+howManyVerts);
TriangleList.Add (i+1);
TriangleList.Add (i);
//Second triangle
TriangleList.Add (i+howManyVerts+1);
TriangleList.Add (i+1);
TriangleList.Add (i+howManyVerts);
}
else{//For the final piece of wall
//First triangle
TriangleList.Add (i+howManyVerts);
TriangleList.Add (0);
TriangleList.Add (i);
//Second triangle
TriangleList.Add (i+howManyVerts);
TriangleList.Add (howManyVerts);
TriangleList.Add (0);
}
}
//Create data for caps
Vector2[] TopCapVertices= new Vector2[howManyVerts];
for(int i = 0; i<howManyVerts; i++){
TopCapVertices[i] = points[i];
}
Triangulator tr = new Triangulator(TopCapVertices);
int[] indices = tr.Triangulate();
int[] NewTriangles = new int[TriangleList.Count + indices.Length];
//Add triangles from TriangleList
for(int i = 0; i<TriangleList.Count; i++){
NewTriangles[i] = TriangleList[i];
}
//Add triangles from the Triangulator
for(int i = 0; i<indices.Length; i++){
NewTriangles[i+TriangleList.Count] = indices[i]+howManyVerts;
}
newMesh.vertices = AllVerts;
//Create the UV map. Nothing special here, copied and pasted.
Vector2[] uvs = new Vector2[AllVerts.Length];
for (int i=0; i<uvs.Length; i++) {
uvs[i] = new Vector2(AllVerts[i].x, AllVerts[i].z);
}
newMesh.uv = uvs;
newMesh.triangles = NewTriangles;
newMesh.RecalculateNormals();
newObject.GetComponent<MeshFilter>().mesh = newMesh;
newObject.AddComponent<MeshCollider>();
//ADD MATERIAL
Material defaultMaterial = new Material(Shader.Find ("Diffuse"));
defaultMaterial.color = Color.blue;
newObject.renderer.material = defaultMaterial;
return newObject;
}
It looks like you're not setting the normals of your mesh
Yeah, that was my feeling too, but this is after running new$$anonymous$$esh.RecalculateNormals(); When I ran it without that, it shows up entirely flat.
Answer by Bunny83 · Oct 10, 2013 at 06:42 PM
There are a few things wrong in your script (and the tutorial).
First you can't use shared vertices it you want to have lighting (which requires normals). If you share the top front vertices with both surfaces (top and side) you can't have a sharp edge which you need it the think should look like a box. The normals are part of the vertices. Each vertex has one normal. Since you share the vertices between two or more surfaces the normal which got calculated by RecalculateNormals is in between both surfaces which makes the box look like curved thing.
Next thing is the uv coordinates. Besides that you also need to split the vertices for the UVs, the way you calculate them is based on the vertex positions x and z values. However that doesn't work for the side faces because the top and bottom vertices have the same x and z value (since they are on top of each other).
Unfortunately I can't give you any advices how to fix this since I don't know where your data is comming from and what's the desired result. Why do you calculate UVs when you don't use textures? Do you want to use textures in the end?
Thanks a ton for pointing that out, and about the uvs! I added in the following snippet and replaced the vertices and triangle arrays with the result,, and it's definitely working much better now. I deactivated the uv portion of the script entirely, but I would like to apply textures. Can you suggest any simple/elegant ways of correctly apply a map to an extruded n-gon?
//Creating a new set of verts and triangle definitions with unique vertices for every tri
Vector3[] correctedVerts = new Vector3[NewTriangles.Length];
int[] correctedTriangles = new int[NewTriangles.Length];
for(int i = 0; i<NewTriangles.Length; i++){
correctedVerts[i] = AllVerts[NewTriangles[i]];
correctedTriangles[i] = i;
}
Well, it even depends on what kind of textures you want to display. If the shape is arbitrary using the x - z method you used is the best bet, but only for the top faces. All side faces are quads, so either map them to [0,0,1,1] the entire texture, or use a world space mapping like for the top faces but based on x-y and z-y. Which mapping you should use you have to deter$$anonymous$$e by the direction the face is facing ;)
Answer by DarkPixel · Oct 10, 2013 at 06:39 PM
If RecalculateNormals give weird result, it's because you probably share vertices between faces. If you want your normal to be "exact", you need to have 4 uniques vertices per faces.