# 31. OpenGL Sphere Creation

Fancy… Here we are going to create our own sphere without the use of
GLUT. I chose to write this tutorial, because I did not like the way
you could and could not texture the sphere created by GLUT and when
I looked on the internet, I could not find any tutorials on it. The advantage
of our sphere, is that we can set texture coordinates and if need be, place it
inside either a display list, vertex array, or vertex buffer object, allowing
us to call alot more than in immediate mode.

———————————————————————
Section 1: Variables

Now to start off, here are the variables we are going to be using:

This will hold our texture
GLuint texture;

This will just hold our angle of rotation
double angle = 0;

This here will hold the information of all our vertices, such as
x, y and z coordinates along with texture coordinates.
typedef struct
{

The x position of our current vertex
int X;
The Y position of our current vertex
int Y;
The Z position of our current vertex
int Z;

The U(x) texture coordinate of the current vertex
double U;
The V(x) texture coordinate of the current vertex
double V;
}VERTICES;

Next we are going to use PI to convert our angles in degrees to radians.
const double PI = 3.1415926535897;

This here is going to determine how far apart each of our vertices are
the further apart, the faster the program, but the squarer the sphere.
I chose 10 because it looks nice, and runs excellent.
const space = 10;

This will hold out total amount of vertices.
const VertexCount = (90 / space) * (360 / space) * 4;

Now we set up how many vertices we are going to use.
VERTICES VERTEX[VertexCount];

———————————————————————
Section 2: Enabling and Creating

Here I am enabling depth testing, texturing and face culling. The depth testing
is so that we acctually have depth to our scene, the texturing is so that
we can apply textures to our sphere, and culling to used to speed up the
application. I have set the front face for culling to Counter Clock Wise, as triangle
strips cull the opposite face to most other shapes.
glEnable(GL_DEPTH_TEST);
glEnable( GL_TEXTURE_2D );
glDepthFunc(GL_LEQUAL);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);

Now we load our texture to be used. It will be stored in texture

Now we call to create the sphere, I do not know why it does this, but the first
input seems to choose how many subdivisions to perform. The next lets you choose
where to move the sphere on the x, y and z axis.
CreateSphere(70,0,0,0);

Now for the actual creation code. We are inputting R as the number of subdivisions,
H as the translation on the horizontal axis, K as the translation on the vertical
axis, and Z as the translation on the Z axis.
void CreateSphere (double R, double H, double K, double Z) {
Now are variables for this is as followed. n is the current vertex we are working
with. While a and b are used to control our loops.
int n;
double a;
double b;

Set n to 0 to start off with the first vertex
n = 0;

Assign our b loop to go through 90 degrees in intervals of our variable space
for( b = 0; b <= 90 – space; b+=space){
Assign our a loop to go through 360 degrees in intervals of our variable space
for( a = 0; a <= 360 – space; a+=space){

Start editing our vertex.
I am calculating the X value here.
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) – H;
The Y value here.
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + K;
The Z value here.
VERTEX[n].Z = R * cos((b) / 180 * PI) – Z;
Now I am calculating the texture coordinates. I have used (2*b) as the texture
is twice as wide as it is high. Hence 2:1. You can remove the (2*) if you wish
to use a texture with the same width and height, or increase it accordingly.
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a) / 360;

Then start working with the next vertex
n++;

Then we do the same calculations as before, only adding the space variable
to the b values.
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI) – H;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) – Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a) / 360;
n++;

Then we do the same calculations as the first, only adding the space variable
to the a values.
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI) – H;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b) / 180 * PI) – Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a + space) / 360;
n++;

Then we do the same calculations as the first again, only adding the space variable
to both the b and the a values.
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) / 180 * PI) – H;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) – Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a + space) / 360;
n++;

}
}
}

———————————————————————————
Section 3: Displaying the Sphere

To display the sphere I am calling this funtion which will set the size of it
to 5 and assign the texture specified.
DisplaySphere(5, texture);

This is the actual displaying code itself, it inputs the radius and texture
void DisplaySphere (double R, GLuint texture){
This variable will control which vertex we are currently working with
int b;

I have chosen to scale it here to 0.0125 times its original size, and then
increase it by R as the original sphere is rather large.
glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);

Now I am rotating it because, if you run it, it is sideways 🙂
glRotatef (90, 1, 0, 0);

Now I bind the texure we inputted above.
glBindTexture (GL_TEXTURE_2D, texture);

Now to begin drawing the sphere itself. I am drawing it with triangle strips
as they are the fastest shape for this.
glBegin (GL_TRIANGLE_STRIP);
Now I am looping through each vertex
for ( b = 0; b <= VertexCount; b++){
Assigning the texture coordinates of the current vertex
glTexCoord2f (VERTEX[b].U, VERTEX[b].V);
And the drawing the specified vertex with the Z coordinate inverted. Because
our creation code only draws half a sphere, which is why I am also doing
this loop again for the other half below.
glVertex3f (VERTEX[b].X, VERTEX[b].Y, -VERTEX[b].Z);
}

And here I do the same as above, only this time, I invert
the V(y) texture coordinate.
for ( b = 0; b <= VertexCount; b++){
glTexCoord2f (VERTEX[b].U, -VERTEX[b].V);
glVertex3f (VERTEX[b].X, VERTEX[b].Y, VERTEX[b].Z);
}

Then end the shape.
glEnd();
}

———————————————————————————
And there we have it. A textured sphere without the need for GLUT

If you have any questions, please email me at swiftless@gmail.com

 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. #include #include #include #include #include #include GLuint texture; double angle = 0; typedef struct  {     int X;     int Y;     int Z;          double U;     double V; }VERTICES; const double PI = 3.1415926535897; const space = 10; const VertexCount = (90 / space) * (360 / space) * 4; VERTICES VERTEX[VertexCount]; GLuint LoadTextureRAW( const char * filename ); void DisplaySphere (double R, GLuint texture){     int b;          glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);              glRotatef (90, 1, 0, 0);          glBindTexture (GL_TEXTURE_2D, texture);          glBegin (GL_TRIANGLE_STRIP);     for ( b = 0; b <= VertexCount; b++){         glTexCoord2f (VERTEX[b].U, VERTEX[b].V);         glVertex3f (VERTEX[b].X, VERTEX[b].Y, –VERTEX[b].Z);     }          for ( b = 0; b <= VertexCount; b++){         glTexCoord2f (VERTEX[b].U, –VERTEX[b].V);         glVertex3f (VERTEX[b].X, VERTEX[b].Y, VERTEX[b].Z);     }     glEnd(); } void CreateSphere (double R, double H, double K, double Z) {     int n;     double a;     double b;          n = 0;          for( b = 0; b <= 90 – space; b+=space){              for( a = 0; a <= 360 – space; a+=space){                           VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) – H;             VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + K;             VERTEX[n].Z = R * cos((b) / 180 * PI) – Z;             VERTEX[n].V = (2 * b) / 360;             VERTEX[n].U = (a) / 360;             n++;                          VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI             ) – H;             VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI             ) + K;             VERTEX[n].Z = R * cos((b + space) / 180 * PI) – Z;             VERTEX[n].V = (2 * (b + space)) / 360;             VERTEX[n].U = (a) / 360;             n++;                          VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI             ) – H;             VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI             ) + K;             VERTEX[n].Z = R * cos((b) / 180 * PI) – Z;             VERTEX[n].V = (2 * b) / 360;             VERTEX[n].U = (a + space) / 360;             n++;                          VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) /              180 * PI) – H;             VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) /              180 * PI) + K;             VERTEX[n].Z = R * cos((b + space) / 180 * PI) – Z;             VERTEX[n].V = (2 * (b + space)) / 360;             VERTEX[n].U = (a + space) / 360;             n++;                              }     } } void display (void) {         glClearDepth(1);         glClearColor (0.0,0.0,0.0,1.0);         glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);         glLoadIdentity();               glTranslatef(0,0,–10);              glRotatef(angle,0,1,0);         DisplaySphere(5, texture);              glutSwapBuffers();         angle ++; } void init (void) {     glEnable(GL_DEPTH_TEST);     glEnable( GL_TEXTURE_2D );     glDepthFunc(GL_LEQUAL);     glCullFace(GL_BACK);     glFrontFace(GL_CCW);     glEnable(GL_CULL_FACE);     texture = LoadTextureRAW( “earth.raw” );     CreateSphere(70,0,0,0); } void reshape (int w, int h) {         glViewport (0, 0, (GLsizei)w, (GLsizei)h);         glMatrixMode (GL_PROJECTION);         glLoadIdentity ();         gluPerspective (60, (GLfloat)w / (GLfloat)h, 0.1, 100.0);         glMatrixMode (GL_MODELVIEW); } int main (int argc, char **argv) {         glutInit (&argc, argv);         glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH);         glutInitWindowSize (500, 500);         glutInitWindowPosition (100, 100);         glutCreateWindow (“A basic OpenGL Window“);         init();         glutDisplayFunc (display);         glutIdleFunc (display);         glutReshapeFunc (reshape);         glutMainLoop ();         return 0; } GLuint LoadTextureRAW( const char * filename ) {       GLuint texture;       int width, height;       unsigned char * data;       FILE * file;            file = fopen( filename, “rb” );       if ( file == NULL ) return 0;            width = 1024;       height = 512;       data = (unsigned char *)malloc( width * height * 3 );            fread( data, width * height * 3, 1, file );       fclose( file );            glGenTextures( 1, &texture );             glBindTexture( GL_TEXTURE_2D, texture );            glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,      GL_MODULATE );             glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,      GL_LINEAR_MIPMAP_NEAREST );            glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,      GL_LINEAR );            glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,      GL_REPEAT );       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,      GL_REPEAT );            gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,      GL_RGB, GL_UNSIGNED_BYTE, data );            free( data );            return texture;     }