Some triangles are black on a mesh generated by script
Iam trying to generate a mesh in unity by script. Eventualy i want this to be a tilemap. Iam getting something strange with some triangles not rendering properly as you can see in this image: !
Before i added a material to it it was looking fine (solid pink color). All the triangles seem to be there too. I have only started making meshes by code since today so i cannot figure out what i did wrong here.
This is the code iam using currently (note UpdateMesh() is not being used atm):
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshCollider))]
public class Tilemap : MonoBehaviour {
public int size_x;
public int size_y;
public float TileSize;
// Use this for initialization
void Start () {
BuildMesh ();
}
public void BuildMesh(){
TileMapData map = new TileMapData (size_x, size_y);
int numTiles = size_x * size_y;
int numVerts = numTiles * 4;
Vector3[] vertices = new Vector3[numVerts];
Vector3[] normals = new Vector3[numVerts];
Vector2[] uv = new Vector2[numVerts];
int [] triangles = new int[numTiles * 6];
int x, y;
for (y = 0; y < size_y; y++){
for (x = 0; x < size_x; x++){
Debug.Log(y*size_x+x);
vertices[(y*size_x+x)*4] = new Vector3(x*TileSize, y*TileSize,0);
vertices[(y*size_x+x)*4+1] = new Vector3(x*TileSize+TileSize, y*TileSize,0);
vertices[(y*size_x+x)*4+2] = new Vector3(x*TileSize+TileSize, y*TileSize+TileSize,0);
vertices[(y*size_x+x)*4+3] = new Vector3(x*TileSize, y*TileSize+TileSize,0);
uv[(y*size_x+x)*4] = new Vector2(0,0);
uv[(y*size_x+x)*4+1] = new Vector2(1,0);
uv[(y*size_x+x)*4+2] = new Vector2(1,1);
uv[(y*size_x+x)*4+3] = new Vector2(0,1);
normals[(y*size_x)*4] = new Vector3(0,0,-1);
normals[(y*size_x+x)*4+1] = new Vector3(0,0,-1);
normals[(y*size_x+x)*4+2] = new Vector3(0,0,-1);
normals[(y*size_x+x)*4+3] = new Vector3(0,0,-1);
}
}
Debug.Log ("Done Verts!");
for (y = 0; y < size_y; y++){
for (x = 0; x < size_x; x++){
int squareindex = y*size_x+x;
int triOffset = squareindex*6;
Debug.Log(squareindex);
triangles[triOffset + 0] = 1+squareindex*4;
triangles[triOffset + 1] = 0+squareindex*4;
triangles[triOffset + 2] = 3+squareindex*4;
triangles[triOffset + 3] = 1+squareindex*4;
triangles[triOffset + 4] = 3+squareindex*4;
triangles[triOffset + 5] = 2+squareindex*4;
}
}
Debug.Log ("Done Triangles!");
Mesh mesh = new Mesh ();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = normals;
mesh.uv = uv;
MeshFilter mesh_filter = GetComponent<MeshFilter> ();
MeshCollider mesh_collider = GetComponent<MeshCollider> ();
mesh_filter.mesh = mesh;
mesh_collider.sharedMesh = mesh;
Debug.Log ("Done Mesh!");
//UpdateMesh ();
}
public void UpdateMesh(){
Mesh meshtoupdate = GetComponent<MeshFilter> ().mesh;
int uvoffset = 0;
int vsize_x = size_x + 1;
int vsize_y = size_y + 1;
int numVerts = vsize_x * vsize_y;
int x, y;
Vector2[] uv = meshtoupdate.uv;
for (y = 0; y < vsize_y-15; y++){
for (x = 0; x < vsize_x-15; x++){
uv[uvoffset] = new Vector2(0.0f,0.0f);
uv[uvoffset+1] = new Vector2(0.0f,0f);
uv[uvoffset+2] = new Vector2(0.0f,0f);
uv[uvoffset+3] = new Vector2(0.0f,0f);
uvoffset += 4;
Debug.Log(uvoffset);
}
}
meshtoupdate.uv = uv;
Debug.Log("Done MeshUpdate!");
Debug.Log(uv.Length);
}
}
Answer by Statement · Oct 31, 2015 at 09:03 PM
Normals were not written properly.
normals[(y*size_x)*4] = new Vector3(0,0,-1);
Should be
normals[(y*size_x+x)*4] = new Vector3(0, 0, -1);
I also cleaned it up a little bit to make it less prone for errors and provide a simplified mesh for PhysX.
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshCollider))]
public class Tilemap : MonoBehaviour
{
public int size_x;
public int size_y;
public float TileSize;
void Start()
{
BuildMesh();
}
public void BuildMesh()
{
MeshFilter mesh_filter = GetComponent<MeshFilter>();
mesh_filter.sharedMesh = CreateGfxMesh();
MeshCollider mesh_collider = GetComponent<MeshCollider>();
mesh_collider.sharedMesh = CreateSimplePhysxMesh();
}
Mesh CreateGfxMesh()
{
int numTiles = size_x * size_y;
int numVerts = numTiles * 4;
int numTris = numTiles * 6;
Vector3[] vertices = new Vector3[numVerts];
Vector3[] normals = new Vector3[numVerts];
Vector2[] uv = new Vector2[numVerts];
int[] triangles = new int[numTris];
for (int y = 0; y < size_y; y++)
{
for (int x = 0; x < size_x; x++)
{
int tileIndex = y * size_x + x;
int tileTriangleIndex = tileIndex * 6;
int tileVertexIndex = tileIndex * 4;
// Tile vertex corner positions
// xAyA -- xByA
// | |
// | |
// | |
// xAyB -- xByB
float xA = x * TileSize;
float yA = y * TileSize;
float xB = xA + TileSize;
float yB = yA + TileSize;
vertices[tileVertexIndex + 0] = new Vector3(xA, yA, 0);
vertices[tileVertexIndex + 1] = new Vector3(xB, yA, 0);
vertices[tileVertexIndex + 2] = new Vector3(xB, yB, 0);
vertices[tileVertexIndex + 3] = new Vector3(xA, yB, 0);
uv[tileVertexIndex + 0] = new Vector2(0, 0);
uv[tileVertexIndex + 1] = new Vector2(1, 0);
uv[tileVertexIndex + 2] = new Vector2(1, 1);
uv[tileVertexIndex + 3] = new Vector2(0, 1);
normals[tileVertexIndex + 0] = new Vector3(0, 0, -1);
normals[tileVertexIndex + 1] = new Vector3(0, 0, -1);
normals[tileVertexIndex + 2] = new Vector3(0, 0, -1);
normals[tileVertexIndex + 3] = new Vector3(0, 0, -1);
triangles[tileTriangleIndex + 0] = 1 + tileVertexIndex;
triangles[tileTriangleIndex + 1] = 0 + tileVertexIndex;
triangles[tileTriangleIndex + 2] = 3 + tileVertexIndex;
triangles[tileTriangleIndex + 3] = 1 + tileVertexIndex;
triangles[tileTriangleIndex + 4] = 3 + tileVertexIndex;
triangles[tileTriangleIndex + 5] = 2 + tileVertexIndex;
}
}
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uv;
mesh.triangles = triangles;
return mesh;
}
Mesh CreateSimplePhysxMesh()
{
// Create a simple quad, it'll be faster for baking mesh for physx.
// For a 32x32 test, shaves 10 ms off (5x speedup).
Vector3[] vertices = new Vector3[4];
Vector3[] normals = new Vector3[4];
int[] triangles = new int[6];
float w = size_x * TileSize;
float h = size_y * TileSize;
vertices[0] = new Vector3(0, 0, 0);
vertices[1] = new Vector3(w, 0, 0);
vertices[2] = new Vector3(w, h, 0);
vertices[3] = new Vector3(0, h, 0);
normals[0] = new Vector3(0, 0, -1);
normals[1] = new Vector3(0, 0, -1);
normals[2] = new Vector3(0, 0, -1);
normals[3] = new Vector3(0, 0, -1);
triangles[0] = 1;
triangles[1] = 0;
triangles[2] = 3;
triangles[3] = 1;
triangles[4] = 3;
triangles[5] = 2;
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.normals = normals;
mesh.triangles = triangles;
return mesh;
}
}
Thanks man. $$anonymous$$ade a kinda simple error it seems but just couldnt find it
Thanks again!
I suggest you keep a pair of debugging shaders handy if you are going to procedurally generate meshes :) One that displays UV and one that displays Normals could be useful for tracking down issues.
You can use Tutorial/Display Normals for viewing normals and make a copy of that, set name "Tutorial/Display UV" or something and set o.color = fixed3(v.texcoord.x, v.texcoord.y, 0);
ins$$anonymous$$d of o.color = v.normal * 0.5 + 0.5;
.
Updated the script by removing redundant secondary loop and giving the collider a simplified mesh.
Never worked with shaders before but that does seem very handy for debugging purposes.