// 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. // --------------------------------------------------------------------- // Section 1: Variables // Now to start off, here are the variables we are going to be using: // This will hold our texture // GLuint texture[1]; // 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[0] // texture[0] = LoadTextureRAW( "texture.raw" ); // 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[0]); // 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 #include #include #include #include #include #include GLuint texture[1]; 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[0]); 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[0] = 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; }