I'm programming a simple graphics engine in C++ that should be capable of representing the Earth. The Earth is modelled as an icosphere, and I planned to map its texture using the normals of each vertex. To do so, I'm essentially trying to get vertical and horizontal coordinates (φ and θ, respectively) (i.e. latitude and longitude) from the vertices' normals.
The following is the (edited) function that implements my approach (called when new vertices are generated). It should return texture coordinates from (0,0)
to (1,1)
when the parameter n
is a normal vector:
glm::vec2 Icosphere::getTexCoord(glm::vec3 n)
{
float theta = (atan2f(n.x, n.z) / PI) / 2.f + 0.5f;
float phi = (asinf(-n.y) / (PI / 2.f)) / 2.f + 0.5f;
return glm::vec2(theta, phi);
}
However, this is yielding unexpected results. With this test image, my icosphere looks like this:
Small white and red triangles are located at (x,y,z) = (1,0,0)
. In the first image, I generated the icosphere with less triangular faces (320), whilst in the latter the icosphere is generated with ~82k triangles.
I'm suspecting that what causes those texture "glitches" is the fact that coordinates (0,*)
and (1,*)
are not considered adjacent. Is there a proper way of doing this?
NB: These are my texture parameters:
/* Configure texture parameters: */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
I finally managed to overcome this ugly texture mapping. The problem is indeed caused by the characteristic non-uniform orientation of triangles in an icosphere. In an icosphere (as well as in an icosahedron) it is impossible to find a plane in the origin (0,0,0)
that does not intersect any triangle. If we think of the Earth, this means that all its meridians intersect some triangles. It also means that when mapping a texture, the triangles located in the texture vertical edges (i.e. with tex. coord. (1,y)
and (0,y)
) will have some of their vertices in either of the sides. When this happens, the texture is interpolated from x≈1
to x≈0
, producing the effect showed in my images.
In order to solve this, I set the texture wrapping to GL_REPEAT
and simply forced some vertices to be away from the texture coordinate space (i.e. x > 1
). This allowed the texture edges to be adjacent and mapped the texture perfectly:
/* Configure texture parameters: */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Not GL_CLAMP_TO_EDGE.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Not GL_CLAMP_TO_EDGE.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
After modifying texture coordinates of triangles in the edges (with GL_CLAMP_TO_EDGE
):
Changing texture parameters to GL_REPEAT
:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With