copenglmappingtexturing

Texturing a sphere in OpenGL with glTexGen


I want to get an earth texture on sphere. My sphere is an icosphere built with many triangles (100+) and I found it confusing to set the UV coordinates for whole sphere. I tried to use glTexGen and effects are quite close but I got my texture repeated 8 times (see image) . I cannot find a way to make it just wrap the whole object once. Here is my code where the sphere and textures are created.

    glEnable(GL_TEXTURE_2D);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glBegin(GL_TRIANGLES);

for (int i = 0; i < new_sphere->NumOfTrians; i++)
{
    Triangle *draw_Trian = new_sphere->Trians+i;
    glVertex3f(draw_Trian->pnts[0].coords[0], draw_Trian->pnts[0].coords[1], draw_Trian->pnts[0].coords[2]);
    glVertex3f(draw_Trian->pnts[1].coords[0], draw_Trian->pnts[1].coords[1], draw_Trian->pnts[1].coords[2]);
    glVertex3f(draw_Trian->pnts[2].coords[0], draw_Trian->pnts[2].coords[1], draw_Trian->pnts[2].coords[2]);

}
glDisable(GL_TEXTURE_2D);
free(new_sphere->Trians);
free(new_sphere);

glEnd();

enter image description here


Solution

  • You need to define how your texture is supposed to map to your triangles. This depends on the texture you're using. There are a multitude of ways to map the surface of a sphere with a texture (since no one mapping is free of singularities). It looks like you have a cylindrical projection texture there. So we will emit cylindrical UV coordinates.

    I've tried to give you some code here, but it's assuming that

    Your code would look something like this. I've defined a new function for emitting cylindrical UVs, so you can put that wherever you like.

    /* Map [(-1, -1, -1), (1, 1, 1)] into [(0, 0), (1, 1)] cylindrically */
    inline void uvCylinder(float* coord) {
      float angle = 0.5f * atan2(coord[2], coord[0]) / 3.14159f + 0.5f;
      float height = 0.5f * coord[1] + 0.5f;
      glTexCoord2f(angle, height);
    }
    
    glEnable(GL_TEXTURE_2D);
    glBegin(GL_TRIANGLES);
    
    for (int i = 0; i < new_sphere->NumOfTrians; i++) {
      Triangle *t = new_sphere->Trians+i;
    
      uvCylinder(t->pnts[0].coords);
      glVertex3f(t->pnts[0].coords[0], t->pnts[0].coords[1], t->pnts[0].coords[2]);
      uvCylinder(t->pnts[1].coords);
      glVertex3f(t->pnts[1].coords[0], t->pnts[1].coords[1], t->pnts[1].coords[2]);
      uvCylinder(t->pnts[2].coords);
      glVertex3f(t->pnts[2].coords[0], t->pnts[2].coords[1], t->pnts[2].coords[2]);
    
    }
    
    glEnd();
    glDisable(GL_TEXTURE_2D);
    
    free(new_sphere->Trians);
    free(new_sphere);
    

    Note on Projections

    The reason it's confusing to build UV coordinates for the whole sphere is that there isn't one 'correct' way to do it. Mathematically-speaking, there's no such thing as a perfect 2D mapping of a sphere; hence why we have so many different types of projections. When you have a 2D image that's a texture for a spherical object, you need to know what type of projection that image was built for, so that you can emit the correct UV coordinates for that texture.