3

I'm trying to get away from immediate mode because I keep getting told that it really isn't the best way to program in Opengl. I found a tutorial that will make a cube and colour it, but it doesn't cover texturing.

This is the code I have:

GLfloat vertices[] = { 1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,   // v0,v1,v2,v3 (front)
                        1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,   // v0,v3,v4,v5 (right)
                        1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,   // v0,v5,v6,v1 (top)
                       -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,   // v1,v6,v7,v2 (left)
                       -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,   // v7,v4,v3,v2 (bottom)
                        1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1 }; // v4,v7,v6,v5 (back)

// normal array
GLfloat normals[]  = { 0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,   // v0,v1,v2,v3 (front)
                        1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,   // v0,v3,v4,v5 (right)
                        0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,   // v0,v5,v6,v1 (top)
                       -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,   // v1,v6,v7,v2 (left)
                        0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,   // v7,v4,v3,v2 (bottom)
                        0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 }; // v4,v7,v6,v5 (back)

// color array
GLfloat colors[]   = { 1, 1, 1,   1, 1, 0,   1, 0, 0,   1, 0, 1,   // v0,v1,v2,v3 (front)
                        1, 1, 1,   1, 0, 1,   0, 0, 1,   0, 1, 1,   // v0,v3,v4,v5 (right)
                        1, 1, 1,   0, 1, 1,   0, 1, 0,   1, 1, 0,   // v0,v5,v6,v1 (top)
                        1, 1, 0,   0, 1, 0,   0, 0, 0,   1, 0, 0,   // v1,v6,v7,v2 (left)
                        0, 0, 0,   0, 0, 1,   1, 0, 1,   1, 0, 0,   // v7,v4,v3,v2 (bottom)
                        0, 0, 1,   0, 0, 0,   0, 1, 0,   0, 1, 1 }; // v4,v7,v6,v5 (back)

// index array of vertex array for glDrawElements() & glDrawRangeElement()
GLubyte indices[]  = { 0, 1, 2,   2, 3, 0,      // front
                       4, 5, 6,   6, 7, 4,      // right
                       8, 9,10,  10,11, 8,      // top
                      12,13,14,  14,15,12,      // left
                      16,17,18,  18,19,16,      // bottom
                      20,21,22,  22,23,20 };    // back

// Initialization routine.
void setup(void)
{
   glClearColor(0.0, 0.0, 0.0, 0.0);
   glEnable(GL_DEPTH_TEST); // Enable depth testing.


}

// Drawing routine.
void drawScene()
{
   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glLoadIdentity();

    // enable and specify pointers to vertex arrays
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);
    glNormalPointer(GL_FLOAT, 0, normals);
    glColorPointer(3, GL_FLOAT, 0, colors);
    glVertexPointer(3, GL_FLOAT, 0, vertices);

    glPushMatrix();
    glTranslatef(0, 0, -5);

    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);

    glPopMatrix();

    glDisableClientState(GL_VERTEX_ARRAY);  // disable vertex arrays
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);

   glutSwapBuffers();
}

// OpenGL window reshape routine.
void resize (int w, int h)
{
   glViewport (0, 0, (GLsizei)w, (GLsizei)h);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0, (float)w/(float)h, 1.0, 20.0);
   glMatrixMode(GL_MODELVIEW);
}

// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
   switch (key) 
   {
      case 27:
         exit(0);
         break;
      default:
         break;
   }
}

// Callback routine for non-ASCII key entry.
void specialKeyInput(int key, int x, int y)
{
   //if(key == GLUT_KEY_UP) if (step < 180) step++;;
   //if(key == GLUT_KEY_DOWN) if (step > 0) step--;;
   glutPostRedisplay();
}

// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
   cout << "Interaction:" << endl;
}

// Main routine.
int main(int argc, char **argv) 
{
   printInteraction();
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow ("sphereInBox2.cpp");
   setup();
   glutDisplayFunc(drawScene);
   glutReshapeFunc(resize);
   glutKeyboardFunc(keyInput);
   glutSpecialFunc(specialKeyInput);
   glutMainLoop();

   return 0;
}

This code will make a cube so I would like to know how to texture each side individually and how to texture the entire model with 1 texture. What would you recommend?

WhyYouNoWork
  • 273
  • 5
  • 18
  • You need a texture coordinate array that would map to a single unwrapped texture containing all 6 faces of your cube. Search for `UV mapping` and `unwrapping`, that's the key words of the technique – j-p Jan 03 '15 at 17:02
  • If I tell your `glEnableClientState(GL_TEXTURE_COORD_ARRAY)` and `glTexCoordPointer` does this give you a hint? ;-) – datenwolf Jan 03 '15 at 17:09
  • @datenwolf I have added both of those to my project. I have made a texcoord variable for the coord pointer, but I don't see a difference. What am I missing? – WhyYouNoWork Jan 04 '15 at 06:11
  • @WhyYouNoWork: Well, you need a texture object in the first place. iggy's answer is fairly complete. You can ignore `glActiveTexture' for the moment; it's OpenGL-1.2 functionality, which like everything above OpenGL-1.1 you have to load at runtime using the extension mechanism (just use GLEW for that). Load the texture after the OpenGL context has been created. Then when you want to use it glBindTexture and for the fixed function pipeline glEnable(GL_TEXTURE_2D). But honestly you should not learn the outdated way of doing things. – datenwolf Jan 04 '15 at 09:34
  • @datenwolf You lost me. Could you provide more detail? – WhyYouNoWork Jan 04 '15 at 16:11
  • @WhyYouNoWork: Well, there are two kinds of OpenGL. The old, legacy one that follows the API design laid down in 1994. And then there's modern OpenGL that did away (good riddance) with all the legacy cruft. So far you've been programming for the legacy stuff. I suggest you look at a tutorial for modern OpenGL; a very good one you can find at http://arcsynthesis.org/gltut – there are two drawbacks though: Setting up a modern OpenGL context requires a bit more effort. And using modern OpenGL requires you to do a all of the work, that used to be built it; the benefit is its far more versatile. – datenwolf Jan 04 '15 at 18:14
  • @datenwolf I'm having a hard time following that tutorial. It is confusing me because there is no complete code and what they do show won't compile. Is there a place on the site to look at code examples? – WhyYouNoWork Jan 05 '15 at 17:26
  • @WhyYouNoWork: If you carefully read http://arcsynthesis.org/gltut/Building%20the%20Tutorials.html you'll find a download link to an archive with all source codes: https://bitbucket.org/alfonse/gltut/downloads – it's also explained on the "Building the Tutorials" chapter, which tools you require and how to build them. – datenwolf Jan 05 '15 at 17:45
  • @datenwolf I've been reading through the tutorial, but am still getting lost in it. I'm finding modern Opengl to be very difficult. For starters what's the difference between glDrawArrays and glDrawElements? – WhyYouNoWork Jan 15 '15 at 16:34
  • @WhyYouNoWork: glDrawArrays processes the elements in the vertex arrays in succession. glDrawElements takes in another array containing the list of indices into the vertex array to process in succession. – datenwolf Jan 15 '15 at 18:13
  • @datenwolf Interesting. Is there a reason to favour one or the other? They sounds like they do the same thing. – WhyYouNoWork Jan 22 '15 at 18:39
  • @WhyYouNoWork: They do not the same thing. Say you want to draw a number of lines from a central point (star shaped). Let the central point be at index 0 and the surrounding points 1, 2, 3, …; then to draw the star you have to draw lines (0,1), (0,2), (0,3), … . Using glDrawElements you can give OpenGL a list 0,1,0,2,0,3,… and it will draw it like this. Using glDrawArrays you tell OpenGL to draw with the indices incrementing in a range, i.e. 0,1,2,3,… – drawing that would draw a line from the central point and then connect every other pair of points along the circumference with lines. – datenwolf Jan 22 '15 at 23:34
  • @datenwolf I'm afraid I still don't quite understand. So does glDrawArray just read x number of coordinates at a time and then make a face? – WhyYouNoWork Jan 23 '15 at 21:24
  • @WhyYouNoWork: I wrote a small program that mimics the access modes of OpenGL glDrawArrays and glDrawElements. I hope this helps you understand. You can find and experiment with it here: http://codepad.org/zePO6Pe6 or here http://ideone.com/9JSqFk – datenwolf Jan 24 '15 at 10:02

1 Answers1

8

First you must provide texture coordinates which can be defined as an array - exactly like you already have with vertices, normals and colors.

GLfloat texcoords[] = {
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f,
};

For each vertex of a face of a cube you must provide UV coordinates that correspond to some placement on the texture. You must provide coordinates for all 6 sides and most of the time they are going to be in different order.

enter image description here

You will then have to load the texture using some other library like SOIL. It will return to you a pointer to the pixels which you can later pass to OpenGL.

Here is how it looks like with OpenGL. First we generate a new texture, set some parameters and fill it with pixels we loaded using external library.

glGenTextures(1, &testTexture);
glBindTexture(GL_TEXTURE_2D, testTexture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, &texData[0]
);

To finally render with this texture you must bind it as an active texture:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, testTexture);

You're almost done! But this part is perhaps the most complicated one. You will have to load your shaders, create a program, compile it with shaders, and start using the program. Once that's done you will simply pass your texture as a uniform sampler to the program.

Iggy
  • 4,767
  • 5
  • 23
  • 34
  • I'm afraid you have lost me. I understand the texturecoord. It is required to write the texture to the face and I understand and it maps a certain percentage of the image to it. I have a few functions to load a png: codepad.org/ygG2U0cF. I don't know what to do next though. glActiveTexture is undefined and your last paragraph after that went way over my head. Could you elaborate further? – WhyYouNoWork Jan 04 '15 at 02:08
  • @WhyYouNoWork Perhaps I could refer you to [this excellent tutorial](http://learnopengl.com/#!Getting-started/Textures)? – Iggy Jan 04 '15 at 15:13
  • I'm reading through the tutorial, but I'm stuck. I don't understand how to get SOIL to work. I can't get any of the files included in it to run. It keeps telling me that the file corrupts when I try to convert them. What's going on? – WhyYouNoWork Jan 04 '15 at 18:59
  • @WhyYouNoWork Building libraries and getting them to work within your project is a skill in its own. You could post another question on StackOverflow about SOIL. – Iggy Jan 04 '15 at 21:14
  • I got the .lib to compile and I am able to properly compile my project, but I'm having problems with the tutorial you sent me. I'm in the section "Applying textures" which is where you said is the most complicated part. It is completely going over my head. What are you suppose to do? – WhyYouNoWork Jan 05 '15 at 03:23
  • @WhyYouNoWork Perhaps you could jump a chapter back in order to understand shaders better? – Iggy Jan 05 '15 at 03:47
  • I looked at the shader tutorial, but I am still having a hard time understanding it. The way how this person set up their tutorial is really confusing me. They broke up their code and anytime they show code it isn't complete. How do you set up a shader in C++? What's the point of them? I feel this person is leaving something out. – WhyYouNoWork Jan 05 '15 at 16:53
  • @WhyYouNoWork shaders aren't written in C++, usually they are small external files which are loaded by C++ and fed into OpenGL for compilation which will run on the GPU for every vertex and fragment. Your question is hard to answer in one comment, I can only recommend that you read every possible tutorial you can find on the subject and if you have a particular question - post it on StackOverflow. – Iggy Jan 05 '15 at 17:26