Texturing a Sphere

From OpenGL.org
Revision as of 07:52, 21 April 2012 by V-man (Talk | contribs) (Cubemapping a Sphere: Adding GLSL version)

Jump to: navigation, search

Let's assume you want to create something that looks like the planet earth. You want to apply a map of the earth to a sphere.
There are 2 ways to texture a sphere. Either by applying a cubemap or either by applying a 2D texture. For best result, use a cubemap. The problem with applying a 2D texture is that when you wrap a 2D texture onto a sphere, the top and bottom area of the sphere, the texture looks squeezed.

Cubemapping a Sphere

Load a cubemap as shown in Creating a Cubemap Texture
Let's assume that we'll be using shaders. If you haven't learned shaders yet, now is the time.
This code is in GLSL 1.10. The vertex shader :

  //[VERTEX SHADER]
  #version 110
  uniform mat4 ProjectionModelviewMatrix;
  varying vec3 TexCoord0;
  void main()
  {
     gl_Position = ProjectionModelviewMatrix * gl_Vertex;
     TexCoord0 = gl_Normal;
  }

The fragment shader. Notice that the normal has been copied to TexCoord0 and this will be used to sample the cubemap.

  //[FRAGMENT SHADER]
  #version 110
  uniform samplerCube Texture0;
  varying vec3 TexCoord0;
  void main()
  {
     vec4 texel = textureCube(Texture0, TexCoord0);
     gl_FragColor = texel;
  }

2D Texture Mapping a Sphere

Either you need to write your own code to create a sphere and you compute the texcoords yourself or you use another library like GLU or glhlib.

GLU

C

 GLUquadricObj *sphere=NULL;
 sphere = gluNewQuadric();
 gluQuadricDrawStyle(sphere, GLU_FILL);
 gluQuadricTexture(sphere, TRUE);
 gluQuadricNormals(sphere, GLU_SMOOTH);
 //Making a display list
 mysphereID = glGenLists(1);
 glNewList(mysphereID, GL_COMPILE);
 gluSphere(sphere, 1.0, 20, 20);
 glEndList();
 gluDeleteQuadric(sphere);
 //-----------------
 //and whenever you want to render, call glCallList(mysphereID)
 //to kill the display list, glDeleteLists(mysphereID, 1);

Java

 Texture earth;
 try {
   earth = TextureIO.newTexture(new File(dataPath("EarthMap_2500x1250.jpg")), true);
 }
 catch (IOException e) {    
   javax.swing.JOptionPane.showMessageDialog(null, e);
 }
 GLUQuadric sphere = new GLUQuadric();
 gluQuadricDrawStyle(sphere, GLU_FILL);
 gluQuadricTexture(sphere, true);
 gluQuadricNormals(sphere, GLU_SMOOTH);
 //Making a display list
 mysphereID = glGenLists(1);
 glNewList(mysphereID, GL_COMPILE);
 earth.enable();
 earth.bind();
 gluSphere(sphere, 1000.0, 20, 20);
 earth.disable();
 glEndList();
 gluDeleteQuadric(sphere);
 //-----------------
 //and whenever you want to render, call glCallList(mysphereID)
 //to kill the display list, glDeleteLists(mysphereID, 1);

GLHLIB

If you want to use glhlib http://sourceforge.net/projects/glhlib/
The header file glhlib.h explains how to use :

 glhSphereObject2 Sphere;
 memset(&Sphere, 0, sizeof(glhSphereObject2));
 Sphere.RadiusA=1.0;
 Sphere.RadiusB=1.0;
 Sphere.RadiusC=1.0;
 Sphere.Stacks=10;
 Sphere.Slices=10;
 Sphere.IndexFormat=GLH_INDEXFORMAT_16BIT;
 Sphere.VertexFormat=GLHVERTEXFORMAT_VNT;
 Sphere.TexCoordStyle[0]=1;
 Sphere.ScaleFactorS[0]=Sphere.ScaleFactorT[0]=1.0;
 //-----------------
 glhCreateSpheref2(&Sphere);
 //-----------------
 //HOW TO RENDER (You might want to use VBO, I'm just using VA here):
 glBindTexture(GL_TEXTURE_2D, TextureID);
 //-----------------
 glVertexPointer(3, GL_FLOAT, sizeof(GLHVertex_VNT), Sphere.pVertex);
 uint mypointer=(uint)Sphere.pVertex;
 mypointer+=12;
 glNormalPointer(GL_FLOAT, sizeof(GLHVertex_VNT), (uint *)mypointer);
 mypointer+=12;
 glTexCoordPointer(2, GL_FLOAT, sizeof(GLHVertex_VNT), (uint *)mypointer);
 glDrawRangeElements(GL_TRIANGLES, Sphere.Start_DrawRangeElements, Sphere.End_DrawRangeElements, Sphere.TotalIndex, GL_UNSIGNED_SHORT, Sphere.pIndex16Bit);
 //.........and delete it when your program closes
 glhDeleteSpheref2(Sphere);