Texturing a Sphere

From OpenGL Wiki
Revision as of 20:43, 8 October 2010 by V-man (talk | contribs) (Again, use glGenLists instead of just assigning a random value to the display list. For good programming.)
Jump to navigation Jump to 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. The vertex shader :

 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.

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