Seamless Procedural Sphere

Good day, I apologize for my poor language (This is not my mother tongue and I’m just learning :))

I’m doing the procedural generation of the planet. I can write a cube, normalize it and even apply 3D noise Simplex. However, I am faced with problems - these are seams between the planes. There are no gaps, but shadows spoil the whole view.

I think the problem is in the wrong normalization. Since there are no so-called “neighbours” on the edge of my peaks. I was advised to add them, but I did not quite understand how it works. Some incomprehensible word for me, “average your vertices on the edges.” Can someone help me with this?

I can not solve the problem for more than two weeks.
And I have already tried all sorts of methods, but the seams remain.
The other day I was able to almost remove them, normalizing the sphere through the formula, but this only partially eliminated them.

Can you post the code you’re using? How are you calculating the normals and tangents after normalization?

The thing is, what about the recalculation of the normals I found out about recently.
The code was written yesterday, but I’m not sure if I’m taking the right indexes as three inputs.

This is my code with generate triangle


if (Y_index == YSize + Skirt - 1) //skirts
            {
                myVertexPosition.X = X_index / (static_cast<float>(XSize + Skirt) - 1) - 0.5f * 2.f;
                myVertexPosition.Y = (Y_index + YSize) / (static_cast<float>(YSize + Skirt) - 1) - 0.5f * 2.f;
                myVertexPosition.Z = 1.0f;

                float position_noise = GenerateTerrain(myVertexPosition);
                myVertexPosition.Normalize();
                myVertexPosition *= (Radius + position_noise);

                Vertices.Add(myVertexPosition);
            }
            else
            {
                myVertexPosition.X = X_index / (static_cast<float>(XSize + Skirt) - 1) - 0.5f * 2.f;
                myVertexPosition.Y = (Y_index + YSize) / (static_cast<float>(YSize + Skirt) - 1) - 0.5f * 2.f;
                myVertexPosition.Z = 1.0f;

                float position_noise = GenerateTerrain(myVertexPosition);
                myVertexPosition.Normalize();
                myVertexPosition *= (Radius + position_noise);

                Vertices.Add(myVertexPosition);
            }

Code with recalculate normals


if (X_index > (Skirt / 2 - 1) && X_index < XSize + (Skirt / 2 - 1))
            {
                if (Y_index > (Skirt / 2 - 1) - 2 && Y_index < YSize + (Skirt / 2 - 1) - 1)
                {
                    int indexMeshA = (X_index * (YSize + Skirt)) + Y_index;
                    int indexMeshB = (X_index * (YSize + Skirt)) + (Y_index - 1);
                    int indexMeshC = ((X_index + 1) * (YSize + Skirt)) + Y_index;

                    FVector sideAB = Vertices[indexMeshB] - Vertices[indexMeshA];
                    FVector sideAC = Vertices[indexMeshC] - Vertices[indexMeshA];
                    FVector normal = FVector::CrossProduct(sideAB, sideAC);

                    Vertices[indexMeshA] += normal;
                    Vertices[indexMeshB] += normal;
                    Vertices[indexMeshC] += normal;

                    Vertices[indexMeshA].Normalize();
                    Vertices[indexMeshA] *= Radius;

                    Vertices[indexMeshB].Normalize();
                    Vertices[indexMeshB] *= Radius;

                    Vertices[indexMeshC].Normalize();
                    Vertices[indexMeshC] *= Radius;

                    GenerateTrienglesTest(0, X_index, Y_index - 1);
                }
            }