OpenGL allows us to map an image (also referred to as a texture) to a 3D shape or polygon. This process is also called texture mapping. Qt appears to be the best combination with OpenGL in this case because it provides an easy way to load images that belong to one of the common formats (BMP, JPEG, PNG, TARGA, TIFF, and so on) and you don't have to implement it by yourself. We will use the previous example with a spinning cube and try to map it with a texture!
mainwindow.h
and add the following header to it:#include <QGLWidget>
private:
QOpenGLContext* context;
QOpenGLFunctions* openGLFunctions;
float rotation;
GLuint texID[1];
mainwindow.cpp
and add the following code to initializeGL()
to load the texture file:void MainWindow::initializeGL() { // Enable Z-buffer depth test glEnable(GL_DEPTH_TEST); // Enable texturing glEnable(GL_TEXTURE_2D); QImage image("bricks"); QImage texture = QGLWidget::convertToGLFormat(image); glGenTextures(1, &texID[0]); glBindTexture(GL_TEXTURE_2D, texID[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width(), texture.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.bits()); // Make sure render at the correct aspect ratio resizeGL(this->width(), this->height()); }
paintGL()
function to apply the texture to the 3D cube:glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID[0]);
// FRONT
glBegin(GL_POLYGON);
glColor3f(0.0, 0.0, 0.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.5, -0.5, -0.5);
glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5, 0.5, -0.5);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5, 0.5, -0.5);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5, -0.5, -0.5);
glEnd();
// BACK
glBegin(GL_POLYGON);
glColor3f(0.0, 1.0, 0.0);
glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5, -0.5, 0.5);
glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5, 0.5, 0.5);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5, 0.5, 0.5);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5, -0.5, 0.5);
glEnd();
// RIGHT
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 1.0);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.5, -0.5, -0.5);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.5, 0.5, -0.5);
glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5, 0.5, 0.5);
glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5, -0.5, 0.5);
glEnd();
// LEFT
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 0.0);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5, -0.5, 0.5);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5, 0.5, 0.5);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5, 0.5, -0.5);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5, -0.5, -0.5);
glEnd();
// TOP
glBegin(GL_POLYGON);
glColor3f(0.0, 0.0, 1.0);
glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5, 0.5, 0.5);
glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5, 0.5, -0.5);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5, 0.5, -0.5);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5, 0.5, 0.5);
glEnd();
// Red side - BOTTOM
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5, -0.5, -0.5);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5, -0.5, 0.5);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5, -0.5, 0.5);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-0.5, -0.5, -0.5);
glEnd();
glDisable(GL_TEXTURE_2D);
The variable GLuint texID[1]
is an array that stores the texture ID generated by OpenGL when we call glGenTexture()
, which OpenGL uses to allocate the texture from the memory during rendering. In this case, we set the size of the array to 1
because we are only using a single texture in this example. We must tell OpenGL to enable texturing by calling glEnable(GL_TEXTURE_2D)
before doing anything related to texturing. We used two QImage
classes to load the texture, the first one called image
was used to load the image file, and the second one called texture
was used to convert the image to an OpenGL-compatible format. Then we called glGenTextures()
to generate an empty texture using OpenGL, and after that, we called glBindTexture()
to select that particular texture. This step was needed so that the functions called after that will be applied to the texture that we just selected.
Next, we called glTexParameteri()
twice to set both the texture minifying and texture magnification settings to point sampling. This will tell OpenGL how the texture should be rendered. More about that later. After that, we called glTexImage2D()
to supply the pixel information from the texture file loaded by Qt to the empty OpenGL texture we just created. Call glEnabled(GL_TEXTURE_2D)
and glBindTexture()
to enable texturing in OpenGL and select the texture we wanted to use before we start rendering the 3D cube. Then, we must call glTexCoord2f()
before calling glVertex3f()
to tell OpenGL how the texture should be mapped. We supply the coordinates for the texture and OpenGL will figure out the rest for us.
Once you're done, call glDisable(GL_TEXTURE_2D)
to disable texturing.
52.15.42.128