3

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

KamCho
  • 131
  • 2
  • 10

1 Answers1

1

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.

Josh Parnell
  • 1,166
  • 9
  • 10
  • Thank You, your solution give quite nice effect. There are still some artefacts but I think I will be able to manage it. I'm aware of problems with building flat coordinates for sphere but I was thinking that this is so common problem that OpenGL could manage it automatically. Well, I was wrong. – KamCho May 29 '17 at 05:00
  • @KamCho glad to hear it. Artifacts are probably from wrapping at the boundary of the image. And yeah, GL does not help you in this regard, sorry. – Josh Parnell May 29 '17 at 05:06