Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 978
KamCho Avatar asked Nov 24 '25 23:11

KamCho


1 Answers

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 mesh is a unit sphere (i.e., centered at 0 and has radius 1)
  • pnts.coords is an array of floats
  • You want to use the second coordinate (coord[1]) as the 'up' direction (or the height in a cylindrical mapping)

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.

like image 148
Josh Parnell Avatar answered Nov 26 '25 11:11

Josh Parnell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!