1
\$\begingroup\$

GeoSphere

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;
}
\$\endgroup\$
  • \$\begingroup\$ More info please, what is your texture sampler state? Are you using an indexed mesh and how are you calculating it? \$\endgroup\$ – MickLH May 31 '14 at 18:18
  • \$\begingroup\$ I just added some additional information. \$\endgroup\$ – TheWanderer May 31 '14 at 20:15
  • \$\begingroup\$ You need the u value to be 0.0 on one side of the seam and 1.0 on the other side. It doesn't look like the UV generation code you posted will do that, since it's based on the normal, and the normal should be the same on both sides of the seam. (BTW, you can easily tell if it's a mipmapping issue by disabling mipmaps.) \$\endgroup\$ – Nathan Reed Jun 1 '14 at 1:24
  • \$\begingroup\$ Yes, the code that duplicates the vertices runs after the generation of the initial vertices. I just added the code used to duplicate the vertices along the seam. \$\endgroup\$ – TheWanderer Jun 1 '14 at 10:55
  • \$\begingroup\$ @AvengerDr OK, that looks reasonable, but there are enough details that it's hard to be sure it's right from looking at the code. Have you verified that all the seam vertices are detected correctly? Have you stepped through in a debugger and verified that it's generating the UVs you expect? \$\endgroup\$ – Nathan Reed Jun 1 '14 at 22:32
1
\$\begingroup\$

This problem may be related to mipmapping. The pixels along the edge are being mapped to a much more copressed LOD than the rest of the sphere, so the entire map is actually being compressed into that line.

You may try putting in a tex2Dlod call in the shader and forcing the LOD to 0:

return tex2Dlod(TextureSampler, float4(u, v, 0, 0));

Explanation and possible solution for this over was found on stackoverflow: https://stackoverflow.com/questions/19723698/sphere-texture-mapping-error

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.