As you can see from the above picture there is a visible seam in the texture mapping. The underlying mesh is a geosphere based on octahedron subdivisions. On that particular latitude, vertices have been duplicated. However there still is a visible seam.
Here is how I calculate the UV coordinates:
float longitude = (float)Math.Atan2(normal.X, -normal.Z);
float latitude = (float)Math.Acos(normal.Y);
float u = (float)(longitude / (Math.PI * 2.0) + 0.5);
float v = (float)(latitude / Math.PI);
Is this a problem in the coordinates or a mipmapping issue?
Edit: the GeoSphere is generated using SharpDX's Toolkit code. My SamplerState is set to Clamp. Further, I am using a normal mapping shader.
Could it be that the tangent of the duplicated vertices needs to be altered? I am using a Vector4 element for it, where w is the handedness. If so, how should it be modified?
Edit2: this is the code used to duplicate the vertices along the seam
int preCount = vertices.Count;
var indicesArray = indexList.ToArray();
fixed (void* pIndices = indicesArray)
{
indices = (int*)pIndices;
for (int i = 0; i < preCount; ++i)
{
// This vertex is on the prime meridian if position.x and texcoord.u are both zero (allowing for small epsilon).
bool isOnPrimeMeridian = MathUtil.WithinEpsilon(vertices[i].Position.X, 0, XMVectorSplatEpsilon)
&& MathUtil.WithinEpsilon(vertices[i].TextureCoordinate.X, 0, XMVectorSplatEpsilon);
if (isOnPrimeMeridian)
{
int newIndex = vertices.Count;
// copy this vertex, correct the texture coordinate, and add the vertex
VertexPositionNormalTexture v = vertices[i];
v.TextureCoordinate.X = 1.0f;
vertices.Add(v);
// Now find all the triangles which contain this vertex and update them if necessary
for (int j = 0; j < indexList.Count; j += 3)
{
var triIndex0 = &indices[j + 0];
var triIndex1 = &indices[j + 1];
var triIndex2 = &indices[j + 2];
if (*triIndex0 == i)
{
// nothing; just keep going
}
else if (*triIndex1 == i)
{
Utilities.Swap(ref *triIndex0, ref *triIndex1);
Utilities.Swap(ref *triIndex1, ref *triIndex2);
}
else if (*triIndex2 == i)
{
Utilities.Swap(ref *triIndex0, ref *triIndex2);
Utilities.Swap(ref *triIndex1, ref *triIndex2);
}
else
{
// this triangle doesn't use the vertex we're interested in
continue;
}
// check the other two vertices to see if we might need to fix this triangle
if (Math.Abs(vertices[*triIndex0].TextureCoordinate.X - vertices[*triIndex1].TextureCoordinate.X) > 0.5f ||
Math.Abs(vertices[*triIndex0].TextureCoordinate.X - vertices[*triIndex2].TextureCoordinate.X) > 0.5f)
{
// yep; replace the specified index to point to the new, corrected vertex
indices[j + 0] = newIndex;
}
}
}
}
FixPole(northPoleIndex);
FixPole(southPoleIndex);
// Clear indices as it will not be accessible outside the fixed statement
indices = (int*)0;
}