How to apply textures to a quad in order to texture a cube?
Recently I have been looking into OpenGL, and I've got up to the stage were I want to texture things. I thought I would start with texturing a simple cube. I currently have this code, and understand fully how it works:
#include <glut.h>
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 400
float angle = 30.0f;
void Draw() {
glLoadIdentity(); //Reset the drawing perspective
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clears the buffers
//Add positioned light
GLfloat lightColor0[] = {0.5f, 0.5f, 0.5f, 1.0f}; //Color intensity
GLfloat lightPos0[] = {0.0f, 0.0f, 0.0f, 1.0f}; //Positioned at..
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0); //Set our light colour
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0); //Set our light position
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 200);
glRotatef(angle,1.0f,1.0f,1.0f); //Rotate around the origin
glScalef(0.4f, 0.4f, 0.4f); //Scale the shape down
glBegin(GL_QUADS); //Start drawing a Quad
glColor3f(1.0f,0.0f,0.0f); //Set the colour to Red
glVertex3f( 1.0f, 1.0f,-1.0f); //Top right of the quad (Top Face)
glVertex3f(-1.0f, 1.0f,-1.0f); //Top left of the quad (Top Face)
glVertex3f(-1.0f, 1.0f, 1.0f); //Bottom left of the quad (Top Face)
glVertex3f( 1.0f, 1.0f, 1.0f); //Bottom right of the quad (Top Face)
glVertex3f( 1.0f,-1.0f, 1.0f); //Top right of the quad (Bottom Face)
glVertex3f(-1.0f,-1.0f, 1.0f); //Top left of the quad (Bottom Face)
glVertex3f(-1.0f,-1.0f,-1.0f); //Bottom left of the quad (Bottom Face)
glVertex3f( 1.0f,-1.0f,-1.0f); //Bottom right of the quad (Bottom Face)
glVertex3f( 1.0f, 1.0f, 1.0f); //Top right of the quad (Front Face)
glVertex3f(-1.0f, 1.0f, 1.0f); //Top left of the quad (Front Face)
glVertex3f(-1.0f,-1.0f, 1.0f); //Bottom left of the quad (Front Face)
glVertex3f( 1.0f,-1.0f, 1.0f); //Bottom right of the quad (Front Face)
glVertex3f( 1.0f,-1.0f,-1.0f); //Top right of the quad (Back Face)
glVertex3f(-1.0f,-1.0f,-1.0f); //Top left of the quad (Back Face)
glVertex3f(-1.0f, 1.0f,-1.0f); //Bottom left of the quad (Back Face)
glVertex3f( 1.0f, 1.0f,-1.0f); //Bottom right of the quad (Back Face)
glVertex3f(-1.0f, 1.0f, 1.0f); //Top right of the quad (Left Face)
glVertex3f(-1.0f, 1.0f,-1.0f); //Top left of the quad (Left Face)
glVertex3f(-1.0f,-1.0f,-1.0f); //Bottom left of the quad (Left Face)
glVertex3f(-1.0f,-1.0f, 1.0f); //Bottom right of the quad (Left Face)
glVertex3f( 1.0f, 1.0f,-1.0f); //Top right of the quad (Right Face)
glVertex3f( 1.0f, 1.0f, 1.0f); //Top left of the quad (Right Face)
glVertex3f( 1.0f,-1.0f, 1.0f); //Bottom left of the quad (Right Face)
glVertex3f( 1.0f,-1.0f,-1.0f); //Bottom right of the quad (Right Face)
glEnd(); //Finished Drawing The Quad
glutSwapBuffers(); //Send the 3D scene to the screen
}
void 开发者_开发知识库Update(int value){ //Our update function
angle+=0.5f; //Increase the angle by 5
if(angle>360){ //If the angle is greater than 360
angle=0; //Set the angle to 0
}
glutPostRedisplay(); //Tell it that the scene has changed
glutTimerFunc(25,Update,0); //Call "Update" again in another 25ms
}
void Initialize() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING); //Enable lighting
glEnable(GL_LIGHT0); //Enable light No. 0
glEnable(GL_NORMALIZE); //Automatically "normalize" normals
glShadeModel(GL_SMOOTH); //Enable smooth shading (nice effect)
glClearColor(0.0, 0.0, 0.0, 0.0); //Background RGBA
glMatrixMode(GL_MODELVIEW); //MODELVIEW view
glLoadIdentity(); //Start at origin
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); //Set the scale
//X axis = 0 to 1. Y = 0 to 1. Z = -1 to 1.
}
int main() {
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //The display mode
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); //Window Size
glutInitWindowPosition(200, 200); //Window Position
glutCreateWindow("Lighting!"); //Creates a window with the name "Lighting!"
Initialize(); //Call our initialize function.
glutDisplayFunc(Draw); //"Draw" then refresh the window
glutTimerFunc(25,Update,0); //Call "Update" 25ms after program starts
glutMainLoop(); //Process events etc. Also keeps the window open.
return 0; //End the program
}
However after reading many, MANY texturing tutorials (I mean literally all of the ones I could find on the web); I'm still confused about how I would add it to this program. I know that I have to load the texture (somehow) and then bind it using the glBindTexture function before I draw the cube, but I think there is something else I need to do in-between (and I don't know how to load the image properly either).
For loading texture files (png, jpg...) use this: (don't forget to install SDL and SDL_image libraries)
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
GLuint texture_alloc(const char *tex_name, int alpha)
{
GLuint tex_num;
SDL_Surface *tex_img;
glGenTextures(1, &tex_num);
if(tex_img = (SDL_Surface *) IMG_Load(tex_name)) {
glBindTexture(GL_TEXTURE_2D, tex_num);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
if (alpha==1)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_img->w, tex_img->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_img->pixels);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_img->w, tex_img->h, 0, GL_RGB, GL_UNSIGNED_BYTE, tex_img->pixels);
SDL_FreeSurface (tex_img);
}
return tex_num;
}
For setting texture coordinates use glTexCoord function:
glTexCoord2f(0.0f, 0.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
.
.
.
I recommend looking at SOIL, an OpenGL image loading library - its what I use.
As far as getting a texture working, its pretty much:
Unsigned int texture = SOIL_load_OGL_texture(imagePath.c_str(), SOIL_CREATE_NEW_ID, SOIL_LOAD_AUTO, SOIL_FLAG_MIPMAPS);
glBindTexture(texture);
You do however have to use texture co-ordinates so that opengl knows how to wrap your texture. Heres some sample calls that render cube.
int size = 1;
// Begin Rending
glBegin(GL_QUADS);
{
// Face 1
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f( m_size, m_size,-m_size);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-m_size, m_size,-m_size);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-m_size, m_size, m_size);
glTexCoord2f(0.0f, 1.0f);
glVertex3f( m_size, m_size, m_size);
// Face 2
glNormal3f( 0.0f, 0.0f,-1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f( m_size,-m_size, m_size);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-m_size,-m_size, m_size);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-m_size,-m_size,-m_size);
glTexCoord2f(0.0f, 1.0f);
glVertex3f( m_size,-m_size,-m_size);
// Face 3
glTexCoord2f(0.0f, 0.0f);
glVertex3f( m_size, m_size, m_size);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-m_size, m_size, m_size);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-m_size,-m_size, m_size);
glTexCoord2f(0.0f, 1.0f);
glVertex3f( m_size,-m_size, m_size);
// Face 4
glNormal3f( 0.0f,-1.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f( m_size,-m_size,-m_size);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-m_size,-m_size,-m_size);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-m_size, m_size,-m_size);
glTexCoord2f(0.0f, 1.0f);
glVertex3f( m_size, m_size,-m_size);
// Face 5
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-m_size, m_size, m_size);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-m_size, m_size,-m_size);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-m_size,-m_size,-m_size);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-m_size,-m_size, m_size);
// Face 6
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f( m_size, m_size,-m_size);
glTexCoord2f(1.0f, 0.0f);
glVertex3f( m_size, m_size, m_size);
glTexCoord2f(1.0f, 1.0f);
glVertex3f( m_size,-m_size, m_size);
glTexCoord2f(0.0f, 1.0f);
glVertex3f( m_size,-m_size,-m_size);
}
glEnd();
I think the part your missing is the concept of texture coordinates.
Textures are 2d right? So, when you're pushing the 3d points of your object to the graphics card, if you want it textured you also need to associate that 3d point with a position in a texture image which you do with a pair of texture coordinates (pair because textures are 2d)... Take a look at glTexCoord2f()... If you make a call to that right before a call to glVertex3f() you'll associate that 3d point with a point in the image... If you do that for all the points that make up a primitive opengl can interpolate for all the points in between...
For image loading you can also use the SDL-image Library:
http://www.libsdl.org/projects/SDL_image/
It is very handy.
You can use the glaux code from the http://nehe.gamedeve.net/ this also is pretty simple.
AUX_RGBImageRec* LoadBMP(char* Filename)
{
FILE *File = NULL;
if ( !Filename )
return NULL;
File = fopen(Filename,"r");
if ( !Filename )
return NULL;
fclose(File);
return auxDIBImageLoad(Filename);
}
int LoadTextures()
{
int Status = FALSE;
AUX_RGBImageRec *TextureImage[1];
memset(TextureImage,0,sizeof(void*)*1);
if ( TextureImage[0] = LoadBMP("GoneFishing.bmp") )
{
Status = true;
if(texture[0] == -1)
glGenTextures(1,&texture[0]);
glBindTexture(GL_TEXTURE_2D,texture[0]);
// Generate The Texture
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
}
if (TextureImage[0]) // If Texture Exists
{
if (TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
return Status;
}
精彩评论