我一直在尝试使用 SDL_image 和 OpenGL 将纹理加载到立方体上。由于某种原因,当我尝试使用纹理时,整个窗口都保持空白。通过注释掉我的纹理初始化调用,窗口将按应有的方式呈现,除了白色纹理。当我对 glEnable(GL_TEXTURE_2D) 的调用被注释掉时,这同样适用。我已经尝试了几个小时来解决这个问题,并且大部分人都在网上寻找是否有人提出了解决方案,但我没有尝试过任何工作。我只在下面发布了我的代码部分,如果需要更多,请告诉我。
OpenGL 初始化(glEnable(GL_TEXTURE_2D) 的顺序可能不正确):
//Configures OpenGL for 3d rendering
//Needs to know the window height and width
void setUpOpenGL(int width, int height)
{
//Enable depth testing, necessary for 3d worlds
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
//Set the background colour to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//Set the clear depth at 1m?
glClearDepth(1.0f);
//Configure the viewport, giving height and width
glViewport(0, 0, width, height);
//Clear the colour buffer
glClear(GL_COLOR_BUFFER_BIT);
//Initiate OpenGL for projection drawing
glMatrixMode(GL_PROJECTION);
//Load identity, purpose still unknown
glLoadIdentity();
//Initiate viewport as perspective, give the field of view, aspect ratio (width/height), minimum distance and maximum distance
gluPerspective(45.0f, (float)width / (float)height, 0.01f, 500.0f);
//Initiate OpenGL for model drawing, preparation for frame rendering
glMatrixMode(GL_MODELVIEW);
//Load identity again (identity matrix?)
glLoadIdentity();
//Set the shading model to smooth. Other options feasable, but don't look as good
glShadeModel(GL_SMOOTH);
//For whatever reason, we need to state how to calculate depth. Grouped under "Alpha Function"
glDepthFunc(GL_LEQUAL);
//Calculate perspective as "nicest"; "don't care" and "fastest" are other options
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
//Finished configuring OpenGL
return;
}
这是我的 loadTexture 函数(errorCode 在整个函数中保持为 0,并且没有任何内容打印到 stderr):
//Function to load textures from file. Needs to know the filename / relative location.
//Load textures from file
int loadTexture(char *filename)
{
GLuint returnValue = -1;
SDL_Surface *image;
void *raw;
int width, height, bpp;
Uint8 *srcPixel, *dstPixel;
Uint32 truePixel;
GLenum errorCode;
image = IMG_Load(filename);
if(!image)
{
fprintf(stderr, "Warning: Error loading image %s: %s\n", filename, IMG_GetError());
return -2;
}
if(image->format->BytesPerPixel < 2)
{
fprintf(stderr, "Warning: %s is a bad image, not true colour\n", filename);
return -3;
}
width = image->w;
height = image->h;
raw = (void *)malloc(width * height * 4);
dstPixel = (Uint8 *)raw;
SDL_LockSurface(image);
bpp = image->format->BytesPerPixel;
for(int i = height - 1; i >= 0; i--)
{
for(int j = 0; j < width; j++)
{
srcPixel = (Uint8 *)image->pixels + i * image->pitch + j * bpp;
switch(bpp)
{
case 1:
truePixel = *srcPixel;
break;
case 2:
truePixel = *(Uint16 *)srcPixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
truePixel = srcPixel[0] << 16 | srcPixel[1] << 8 | srcPixel[2];
else
truePixel = srcPixel[0] | srcPixel[1] << 8 | srcPixel[2] << 16;
break;
case 4:
truePixel = *(Uint32 *)srcPixel;
break;
default:
fprintf(stderr, "Warning: image BPP of %d in image %s unuseable\n", bpp, filename);
SDL_UnlockSurface(image);
SDL_FreeSurface(image);
free(raw);
return -4;
}
SDL_GetRGBA(truePixel, image->format, &(dstPixel[0]), &(dstPixel[1]), &(dstPixel[2]), &(dstPixel[3]));
dstPixel++;
dstPixel++;
dstPixel++;
dstPixel++;
}
}
SDL_UnlockSurface(image);
SDL_FreeSurface(image);
while(glGetError());
glGenTextures(1, &returnValue);
glBindTexture(GL_TEXTURE_2D, returnValue);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*_MIPMAP_LINEAR*/);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (Uint8 *)raw);
errorCode = glGetError();
if(errorCode)
{
if(errorCode == GL_OUT_OF_MEMORY)
fprintf(stderr, "Warning: Texture memory full while binding texture from image %s\n", filename);
else
fprintf(stderr, "OpenGL error while creating texture: %d", (int)errorCode);
glDeleteTextures(1, &returnValue);
free(raw);
return -5;
}
//gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (Uint8 *)raw);
errorCode = glGetError();
if(errorCode)
{
if(errorCode == GL_OUT_OF_MEMORY)
fprintf(stderr, "Warning: Texture memory full while building texture from image %s\n", filename);
else
fprintf(stderr, "OpenGL error while creating texture: %s", (int)errorCode);
glDeleteTextures(1, &returnValue);
free(raw);
return -6;
}
return returnValue;
}
最后,我的实际渲染代码。请注意,loadTexture 函数的返回值被复制到纹理数组的所有元素中(右、左、上、下、前、后(枚举))。
void cube::render(void)
{
float xMinOffset, xMaxOffset, yMinOffset, yMaxOffset, zMinOffset, zMaxOffset;
//getoffset(xMinOffset, xMaxOffset, yMinOffset, yMaxOffset, zMinOffset, zMaxOffset);
xMinOffset = yMinOffset = zMinOffset = 0.0f;
xMaxOffset = yMaxOffset = zMaxOffset = 1.0f;
//Positive x, or right
glBegin(GL_QUADS);
{
glColor3f(1.0f, 1.0f, 1.0f);
glNormal3f(1.0f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, texture[right]);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(xMaxOffset, yMinOffset, zMinOffset);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(xMaxOffset, yMinOffset, zMaxOffset);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(xMaxOffset, yMaxOffset, zMaxOffset);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(xMaxOffset, yMaxOffset, zMinOffset);
}
glEnd();
//Negative x, or left
glBegin(GL_QUADS);
{
glColor3f(1.0f, 1.0f, 1.0f);
glNormal3f(-1.0f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, texture[left]);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(xMinOffset, yMinOffset, zMinOffset);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(xMinOffset, yMinOffset, zMaxOffset);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(xMinOffset, yMaxOffset, zMaxOffset);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(xMinOffset, yMaxOffset, zMinOffset);
}
glEnd();
//Positive y, or top
glBegin(GL_QUADS);
{
glColor3f(1.0f, 1.0f, 1.0f);
glNormal3f(0.0f, 1.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, texture[top]);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(xMinOffset, yMaxOffset, zMinOffset);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(xMinOffset, yMaxOffset, zMaxOffset);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(xMaxOffset, yMaxOffset, zMaxOffset);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(xMaxOffset, yMaxOffset, zMinOffset);
}
glEnd();
//Negative y, or bottom
glBegin(GL_QUADS);
{
glColor3f(1.0f, 1.0f, 1.0f);
glNormal3f(0.0f, -1.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, texture[bottom]);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(xMinOffset, yMinOffset, zMinOffset);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(xMinOffset, yMinOffset, zMaxOffset);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(xMaxOffset, yMinOffset, zMaxOffset);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(xMaxOffset, yMinOffset, zMinOffset);
}
glEnd();
//Positive z, or front
glBegin(GL_QUADS);
{
glColor3f(1.0f, 1.0f, 1.0f);
glNormal3f(0.0f, 0.0f, 1.0f);
glBindTexture(GL_TEXTURE_2D, texture[front]);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(xMinOffset, yMinOffset, zMaxOffset);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(xMinOffset, yMaxOffset, zMaxOffset);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(xMaxOffset, yMaxOffset, zMaxOffset);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(xMaxOffset, yMinOffset, zMaxOffset);
}
glEnd();
//Negative z, or back
glBegin(GL_QUADS);
{
glColor3f(1.0f, 1.0f, 1.0f);
glNormal3f(0.0f, 0.0f, -1.0f);
glBindTexture(GL_TEXTURE_2D, texture[back]);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(xMinOffset, yMinOffset, zMinOffset);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(xMinOffset, yMaxOffset, zMinOffset);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(xMaxOffset, yMaxOffset, zMinOffset);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(xMaxOffset, yMinOffset, zMinOffset);
}
glEnd();
}
这里是渲染函数,以及其他一些与绘图相关的函数。请注意,initDisplayLists() 在初始化时被调用。
void redraw(void)
{
//Still has the data from the previous frame
//Clear the colour and depth buffers before rendering
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Load identity, purpose unknown
glLoadIdentity();
//Draw horizontal crosshair
glBegin(GL_LINES);
{
//White colour
glColor3f(1.0f, 1.0f, 1.0f);
//x, y, z
//Vertex2f would be ideal, but doesn't appear (min view distance for perspective?)
glVertex3f(-0.0001f, 0.0f, -0.01f);
glVertex3f(0.0001f, 0.0f, -0.01f);
}
glEnd();
//Draw vertical crosshair
glBegin(GL_LINES);
{
//Also white
glColor3f(1.0f, 1.0f, 1.0f);
//Again: x, y, z
glVertex3f(0.0f, -0.0001f, -0.01f);
glVertex3f(0.0f, 0.0001f, -0.01f);
}
glEnd();
//Rotate on the x axis (pitch)
glRotatef(se::pl0.rX, 1.0f, 0.0f, 0.0f);
//Rotate viewport on the y axis (yaw)
glRotatef(se::pl0.rY, 0.0f, 1.0f, 0.0f);
//Translate the world by the negative of our coordinates
//Camera one way = objects the other...
glTranslatef(-se::pl0.x, -se::pl0.y, -se::pl0.z);
glCallList(1);
//Show the screen we have been calculating, preparing the screen we were showing for drawing
SDL_GL_SwapBuffers();
return;
}
void initDisplayLists(void)
{
glGenLists(1);
cube block = cube();
glNewList(1, GL_COMPILE);
{
block.render();
}
glEndList();
return;
}