纹理颜色未正确显示

时间:2011-04-15 09:00:07

标签: opengl textures

这是关于OpenGL中的照明和纹理的基本问题。我尝试在纯OpenGL应用程序中应用纹理,遗憾的是,颜色与纹理不同。这是纹理:

texture screenshot

以下是应用纹理后得到的结果:

textured teapot

我使用了Videotutorialrocks BMP Loader。如果我使用他们的BMP文件(即颜色与纹理文件相同),则此着色问题不存在。

以下是代码:

#include <windows.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include "imageloader.h"

using std::stringstream;
using std::cout;
using std::endl;
using std::ends;

using namespace std;

float lpos[4] = {1.0,0.0,0.0,0.0};
void *font = GLUT_BITMAP_8_BY_13;
float color[4] = {0.0, 1.0, 0.0, 1.0};
GLuint _textureId; //The id of the texture
float a = 0;
float eye_x = 5.0;
float eye_y = 5.0;
float eye_z = 5.0;

//Makes the image into a texture, and returns the id of the texture
GLuint loadTexture(Image* image) {
    GLuint textureId;
    glGenTextures(1, &textureId); //Make room for our texture
    glBindTexture(GL_TEXTURE_2D, textureId); //Tell OpenGL which texture to edit
    //Map the image to the texture
    glTexImage2D(GL_TEXTURE_2D,                //Always GL_TEXTURE_2D
                 0,                            //0 for now
                 GL_RGB,                       //Format OpenGL uses for image
                 image->width, image->height,  //Width and height
                 0,                            //The border of the image
                 GL_RGB, //GL_RGB, because pixels are stored in RGB format
                 GL_UNSIGNED_BYTE, //GL_UNSIGNED_BYTE, because pixels are stored
                                   //as unsigned numbers
                 image->pixels);               //The actual pixel data
    return textureId; //Returns the id of the texture
}


// write 2d text using GLUT
// The projection matrix must be set to orthogonal before call this function.
void drawString(const char *str, int x, int y, float color[4], void *font)
{
    glPushAttrib(GL_LIGHTING_BIT | GL_CURRENT_BIT); // lighting and color mask
    glDisable(GL_LIGHTING);     // need to disable lighting for proper text color
    glColor4fv(color);          // set text color
    glRasterPos2i(x, y);        // place text position

    // loop all characters in the string
    while(*str)
    {
        glutBitmapCharacter(font, *str);
        ++str;
    }

    glEnable(GL_LIGHTING);
    glPopAttrib();
}

void changeSize(int w, int h) {

    // Prevent a divide by zero, when window is too short. (you cant make a window of zero width).
    if(h == 0)
        h = 1;

    float ratio = 1.0* w / h;

    // Reset the coordinate system before modifying
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Set the viewport to be the entire window
    glViewport(0, 0, w, h);

    // Set the correct perspective.
    gluPerspective(45,ratio,1,100);
    glMatrixMode(GL_MODELVIEW);
}

void initRendering(){
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
    glEnable(GL_NORMALIZE);
    glEnable(GL_COLOR_MATERIAL);
    Image* image = loadBMP("vtr_6.bmp");
    _textureId = loadTexture(image);
    delete image;

}

void renderScene(void) {

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

   //Add ambient light
    //GLfloat ambientColor[] = {0.4f, 0.2f, 0.2f, 1.0f}; //Color(0.2, 0.2, 0.2)
    GLfloat ambientColor[] = {1.0f, 1.0f, 1.0f, 1.0f}; //Color(0.2, 0.2, 0.2)
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);

    //Add positioned light
    //GLfloat lightColor0[] = {0.5f, 0.5f, 0.5f, 1.0f}; //Color (0.5, 0.5, 0.5)
    GLfloat lightColor0[] = {1.0f, 1.0f, 1.0f, 1.0f}; //Color (0.5, 0.5, 0.5)
    GLfloat lightPos0[] = {4.0f, 0.0f, 8.0f, 1.0f}; //Positioned at (4, 0, 8)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);

    //Add directed light
    //GLfloat lightColor1[] = {0.7f, 0.2f, 0.1f, 1.0f}; //Color (0.5, 0.2, 0.2)
    GLfloat lightColor1[] = {1.0f, 1.0f, 1.0f, 1.0f};
    //Coming from the direction (-1, 0.5, 0.5)
    GLfloat lightPos1[] = {1.0f, 0.5f, 0.5f, 0.0f};
    glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1);
    glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, _textureId);
    //Bottom
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    gluLookAt(eye_x,eye_y,eye_z, 
              0.0,0.0,0.0,
              0.0f,1.0f,0.0f);      

    stringstream ss;
    ss << std::fixed << std::setprecision(2);

    ss << "Eye Position : x,y,z = (" << eye_x << ", " << eye_y << ", " << eye_z << ")" << ends;
    drawString(ss.str().c_str(), -6, 1, color, font);
    ss.str("");

    glRotatef(a,0,1,0);
    glutSolidTeapot(2);
    glDisable(GL_TEXTURE_2D);
    a+=0.1;

    glutSwapBuffers();
}



void processNormalKeys(unsigned char key, int x, int y) {
    switch ( key )
    {
    case 27:
        exit(0);
        break;
    case '1':
        eye_x += 0.1;
        break;
    case '2':
        eye_x -= 0.1;
        break;
    case '3' :
        eye_y += 0.1;
        break;
    case '4' :
        eye_y -= 0.1;
        break;
    case '5':
        eye_z += 0.1;;
        break;
    case '6':
        eye_z -= 0.1;
        break;
    case '0':
        eye_x = 5.0;
        eye_y = 5.0;
        eye_z = 5.0;
        break;
    }
}

#define printOpenGLError() printOglError(__FILE__, __LINE__)

int printOglError(char *file, int line)
{
    GLenum glErr;
    int    retCode = 0;

    glErr = glGetError();
    while (glErr != GL_NO_ERROR)
    {
        printf("glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));
        retCode = 1;
        glErr = glGetError();
    }
    return retCode;
}


int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(800,600);
    glutCreateWindow("OpenGL Teapot w/ lighting");
    initRendering();
    glutDisplayFunc(renderScene);

    glutReshapeFunc(changeSize);
    glutKeyboardFunc(processNormalKeys);

    glutIdleFunc(renderScene);

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.0,0.0,0.0,0.0);

    glutMainLoop();
    return 0;
}

以下是Image Loader的代码:

    #include <assert.h>
    #include <fstream>

    #include "imageloader.h"

    using namespace std;

    Image::Image(char* ps, int w, int h) : pixels(ps), width(w), height(h) {

    }

    Image::~Image() {
        delete[] pixels;
    }

    namespace {
        //Converts a four-character array to an integer, using little-endian form
        int toInt(const char* bytes) {
            return (int)(((unsigned char)bytes[3] << 24) |
                         ((unsigned char)bytes[2] << 16) |
                         ((unsigned char)bytes[1] << 8) |
                         (unsigned char)bytes[0]);
        }

        //Converts a two-character array to a short, using little-endian form
        short toShort(const char* bytes) {
            return (short)(((unsigned char)bytes[1] << 8) |
                           (unsigned char)bytes[0]);
        }

        //Reads the next four bytes as an integer, using little-endian form
        int readInt(ifstream &input) {
            char buffer[4];
            input.read(buffer, 4);
            return toInt(buffer);
        }

        //Reads the next two bytes as a short, using little-endian form
        short readShort(ifstream &input) {
            char buffer[2];
            input.read(buffer, 2);
            return toShort(buffer);
        }

        //Just like auto_ptr, but for arrays
        template<class T>
        class auto_array {
            private:
                T* array;
                mutable bool isReleased;
            public:
                explicit auto_array(T* array_ = NULL) :
                    array(array_), isReleased(false) {
                }

                auto_array(const auto_array<T> &aarray) {
                    array = aarray.array;
                    isReleased = aarray.isReleased;
                    aarray.isReleased = true;
                }

                ~auto_array() {
                    if (!isReleased && array != NULL) {
                        delete[] array;
                    }
                }

                T* get() const {
                    return array;
                }

                T &operator*() const {
                    return *array;
                }

                void operator=(const auto_array<T> &aarray) {
                    if (!isReleased && array != NULL) {
                        delete[] array;
                    }
                    array = aarray.array;
                    isReleased = aarray.isReleased;
                    aarray.isReleased = true;
                }

                T* operator->() const {
                    return array;
                }

                T* release() {
                    isReleased = true;
                    return array;
                }

                void reset(T* array_ = NULL) {
                    if (!isReleased && array != NULL) {
                        delete[] array;
                    }
                    array = array_;
                }

                T* operator+(int i) {
                    return array + i;
                }

                T &operator[](int i) {
                    return array[i];
                }
        };
    }

    Image* loadBMP(const char* filename) {
        ifstream input;
        input.open(filename, ifstream::binary);
        assert(!input.fail() || !"Could not find file");
        char buffer[2];
        input.read(buffer, 2);
        assert(buffer[0] == 'B' && buffer[1] == 'M' || !"Not a bitmap file");
        input.ignore(8);
        int dataOffset = readInt(input);

        //Read the header
        int headerSize = readInt(input);
        int width;
        int height;
        switch(headerSize) {
            case 40:
                //V3
                width = readInt(input);
                height = readInt(input);
                input.ignore(2);
                assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
                assert(readShort(input) == 0 || !"Image is compressed");
                break;
            case 12:
                //OS/2 V1
                width = readShort(input);
                height = readShort(input);
                input.ignore(2);
                assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
                break;
            case 64:
                //OS/2 V2
                assert(!"Can't load OS/2 V2 bitmaps");
                break;
            case 108:
                //Windows V4
                assert(!"Can't load Windows V4 bitmaps");
                break;
            case 124:
                //Windows V5
                assert(!"Can't load Windows V5 bitmaps");
                break;
            default:
                assert(!"Unknown bitmap format");
        }

        //Read the data
        int bytesPerRow = ((width * 3 + 3) / 4) * 4 - (width * 3 % 4);
        int size = bytesPerRow * height;
        auto_array<char> pixels(new char[size]);
        input.seekg(dataOffset, ios_base::beg);
        input.read(pixels.get(), size);

        //Get the data into the right format
        auto_array<char> pixels2(new char[width * height * 3]);
        for(int y = 0; y < height; y++) {
            for(int x = 0; x < width; x++) {
                for(int c = 0; c < 3; c++) {
                    pixels2[3 * (width * y + x) + c] =
                        pixels[bytesPerRow * y + 3 * x + (2 - c)];
                }
            }
        }

        input.close();
        return new Image(pixels2.release(), width, height);
    }

这是头文件:

#ifndef IMAGE_LOADER_H_INCLUDED
#define IMAGE_LOADER_H_INCLUDED

//Represents an image
class Image {
    public:
        Image(char* ps, int w, int h);
        ~Image();

        /* An array of the form (R1, G1, B1, R2, G2, B2, ...) indicating the
         * color of each pixel in image.  Color components range from 0 to 255.
         * The array starts the bottom-left pixel, then moves right to the end
         * of the row, then moves up to the next column, and so on.  This is the
         * format in which OpenGL likes images.
         */
        char* pixels;
        int width;
        int height;
};

//Reads a bitmap image from file.
Image* loadBMP(const char* filename);
#endif

我尝试用GL_BGR_EXT替换glTexImage2D的文件格式,但没有结果。有没有办法纠正纹理?

4 个答案:

答案 0 :(得分:2)

也许您的图片有alpha通道,需要GL_RGBA,而不是GL_RGB。

答案 1 :(得分:2)

尝试使用某种图像编辑软件(gimp,photoshop等)打开纹理,并将其保存为24色的BMP(我认为:每个r / b / g为8),并确保所有BMP设置都是正确的。它看起来确实是纹理格式的问题。有多种BMP格式。

答案 2 :(得分:1)

看看禁用灯光时会发生什么。

此页面还建议您使用:

glFrontFace(GL_CW);
glutSolidTeapot(size);
glFrontFace(GL_CCW);

http://pyopengl.sourceforge.net/documentation/manual/glutSolidTeapot.3GLUT.html

答案 3 :(得分:1)

在loadTexture函数中,在glTexImage2D中将第二个(格式)GL_RGB更改为GL_BGR。

如果您尝试加载PNG图像文件,也请添加Alpha。