I'm currently working on a procedurally generated sphere but I can't get rid of those seams between the meshes. My first step is to generate a cube and normalize all vertices. I've already search the internet for solution but I never achieved a full removal only just made less visible the seams.
Correct me if I'm wrong but the root cause is this: Unity uses per vertex normals for creating smooth shading instead of flat shading and at the mesh edge the normals are not correctly calculated by the built-in RecalculateNormals method.
So the solution what I found: during vertex generation of a mesh also create border vertices and Unity will calculate correct normals and after that I remove border vertices and triangles from the mesh.
Here you can see seams without any fix:
I tried to generate border for every side of the cube, call RecalculateNormals on the Mesh object and reassign vertices, indices and normals without the border. The result is better but not perfect (Solution A):
I was thinking about this border. If I generate one strip border and I normalize also the border vertices then these border triangles won't be there where adjacent mesh's edge triangles are located:
So I tried to move the border vertices to overlap the adjacent mesh's most outer triangles (most outer strip):
And the result is almost perfect but the borders are visible (Solution B):
Is it possible to remove seams fully? I want to use that solution where I just create border on the plane of the current mesh and not move to adjacent mesh. It's easier to create meshes with one unit wider.
EDIT1
This code is used for generation. I collect mesh/border vertices and indices in separate lists in the MeshData object.
private MeshData CalculateMeshData()
{
MeshData meshData = new MeshData();
meshData.ChunkSize = CHUNK_SIZE;
meshData.BorderSize = BORDER_SIZE;
int borderedResolution = meshData.BorderedResolution;
int vertexIndex = -1;
float faceWidth = _radius * 2 / CHUNK_SIZE;
float currentYPosition = -_radius - faceWidth * BORDER_SIZE;
for (int y = 0; y < borderedResolution; y++)
{
float currentXPosition = -_radius - faceWidth * BORDER_SIZE;
for (int x = 0; x < borderedResolution; x++)
{
bool isMeshVertex = !IsBorderVertex(x, y, borderedResolution);
Vector3 axisAOffset = _axisA * currentXPosition;
Vector3 axisbOffset = _axisB * currentYPosition;
Vector3 pointOnUnitCube = _center + axisAOffset + axisbOffset;
Vector3 vertex = pointOnUnitCube.normalized;
vertexIndex++;
meshData.AddVertex(vertex, isMeshVertex);
// Prevents to create more two triangles next to the edge of the mesh.
if (x != borderedResolution - 1 && y != borderedResolution - 1)
{
bool isMeshTriangle = IsMeshTriangle(x, y, borderedResolution);
meshData.AddTriangle(vertexIndex,
vertexIndex + borderedResolution + 1,
vertexIndex + borderedResolution,
isMeshTriangle);
meshData.AddTriangle(vertexIndex,
vertexIndex + 1,
vertexIndex + borderedResolution + 1,
isMeshTriangle);
}
currentXPosition += faceWidth;
}
currentYPosition += faceWidth;
}
return meshData;
}
And here is the mesh creation:
private void GenerateMesh()
{
// Creates object and its components.
_meshObject = new GameObject("mesh");
_meshFilter = _meshObject.AddComponent<MeshFilter>();
_meshRenderer = _meshObject.AddComponent<MeshRenderer>();
_meshRenderer.material = Shape.Material;
_mesh = new Mesh();
_meshFilter.sharedMesh = _mesh;
// Creates the mesh and calculates normals with the border faces.
MeshData meshData = CalculateMeshData();
_mesh.vertices = meshData.GetVertices(true);
_mesh.triangles = meshData.GetIndices(true);
_mesh.RecalculateNormals();
// Recreates mesh without the border.
Vector3[] normals = _mesh.normals;
_mesh.Clear();
_mesh.vertices = meshData.GetVertices(false);
_mesh.triangles = meshData.GetIndices(false);
_mesh.normals = meshData.GetMeshNormals(normals);
}
The GetVertices and GetIndices method has a switch which controls whether mesh data returned including border or not.
The GetMeshNormals method returns normals for the mesh without the border.