2011-04-15 112 views
3

這是關於OpenGL中的照明和紋理的基本問題。我嘗試在純OpenGL應用中應用紋理,不幸的是,顏色與紋理不同。這裏是質地:紋理顏色顯示不正確

texture screenshot

和這裏是我申請的紋理後得到:

textured teapot

我用Videotutorialrocks BMP裝載機。如果我使用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; 
} 

這裏是圖像裝載機代碼:

#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 

我試圖取代文件格式爲glTexImage2D與GL_BGR_EXT,但沒有結果。有什麼方法來糾正紋理?

回答

2

也許你的圖像有一個alpha通道,它需要GL_RGBA而不是GL_RGB。

+0

我也試過這個,但問題仍然存在。無論如何感謝^^ – snowball147 2011-04-15 12:33:01

1

看看禁用照明時會發生什麼。

而且這個頁面提示你應該使用:

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

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

+0

禁用照明後我沒有得到任何效果。但提供的鏈接給了我對這個代碼的另一個問題的答案:100%的CPU負載。無論如何謝謝:) – snowball147 2011-04-15 22:36:11

+0

你有沒有嘗試用glFrontFace圍繞像茶壺一樣的電話?我做過 – 2011-04-16 08:47:13

+0

,試過使用GL_CW和GL_CCW。沒有結果.. – snowball147 2011-04-18 06:04:04

2

嘗試用某種圖像編輯軟件(GIMP,PHOTOSHOP等)打開你的紋理,並將其保存爲一個BMP 24色位(我認爲:每個r/b/g都有8位),並確保所有的BMP設置都是正確的。它絕對看起來像是你的紋理格式的問題。有多種BMP格式。

+0

這就是我的想法。我嘗試使用GIMP,但GIMP沒有任何高級BMP保存設置,只需將圖像保存爲「Windows BMP」即可。我會嘗試使用其他圖像編輯軟件。目前,我沒有任何訪問photoshop。 – snowball147 2011-04-18 06:06:31

+0

真的。我的GIMP版本的確如此。確保在保存文件時,在下拉列表中選擇「.bmp位圖」。否則(愚蠢)它假定你沒有保存一個bmp,如果你選擇「。*所有文件」。 – 2011-04-18 06:31:13

1

在loadTexture函數中,在glTexImage2D中將第二個(格式)GL_RGB更改爲GL_BGR。

如果您嘗試加載PNG圖像文件,請添加Alpha。