Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly map a 2D image texture to an icosphere

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:

Example 1

Example 2

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);
like image 423
Carles Araguz Avatar asked Nov 09 '22 02:11

Carles Araguz


1 Answers

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);

Results:

After modifying texture coordinates of triangles in the edges (with GL_CLAMP_TO_EDGE):

Result1

Changing texture parameters to GL_REPEAT:

enter image description here

like image 65
Carles Araguz Avatar answered Nov 14 '22 23:11

Carles Araguz