2013-12-07 25 views
1

因此,当涉及将ppm纹理应用到四边形时,我有一些粗糙的内容。我的问题是颜色不“正确”。Opengl在将纹理应用到对象时出现错误的颜色

colors of a few planets

下面是对木星汞几个行星。

唯一正确的颜色是地球。

我下载的纹理在线(JPEG文件),然后从Linux命令行

jpegtopnm Mercury.jpg > Mercury.ppm 

我没有这一切,你在上面看到的图像的转换他们。

起初的颜色都倒,所以我改变

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ImgWidth, ImgHeight, 0, GL_RGB, 
       GL_UNSIGNED_BYTE, TexBits); 

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ImgWidth, ImgHeight, 0, GL_BGR, 
       GL_UNSIGNED_BYTE, TexBits); 

和固定的反转颜色(R,而不是b ... ECT)。现在我被困在这里了......如何纠正纹理以显示行星的正确颜色?

这里是水银纹理文件 enter image description here

这里是处理纹理

void read_file(const char * filename) 
{ 
    FILE *infile; 
    char buf[80]; 
    char string[256]; 
    unsigned char *texImage; 
    int i, temp; 
    GLubyte *sp; 
    if ((infile = fopen(filename, "rb")) == NULL) 
    { 
     printf("File open error\n"); 
     exit(1); 
    } 
    fgets(string, 256, infile); 


    fgets(string, 256, infile); 
    while (string[0] == '#') 
      fgets(string, 256, infile); 

    sscanf(string, "%d %d", &ImgWidth, &ImgHeight); 


    if (TexBits != 0) 
     free(TexBits); 

    TexBits = (GLubyte *) calloc(ImgWidth * ImgHeight * 3, sizeof(GLubyte)); 

    for (i = ImgHeight - 1; i >= 0; i--) 
    { 
     sp = TexBits + i * ImgWidth * 3; 
      fread (sp, sizeof(GLubyte), ImgWidth * 3, infile); 
    } 
    fclose(infile); 
} 
void bindTexture() 
{ 
    glGenTextures(10, texName); 

    glBindTexture(GL_TEXTURE_2D, texName[1]); 
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    read_file("Mercury.ppm"); 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ImgWidth, ImgHeight, 0, GL_BGR, 
       GL_UNSIGNED_BYTE, TexBits); 

    ///// rest of planets in order.. (same code for each of them) 
} 

void drawCircle(GLfloat size, GLfloat offset, GLint r) 
{ 
    quadratic=gluNewQuadric(); 

    gluQuadricDrawStyle(quadratic, GLU_FILL); 
    gluQuadricTexture(quadratic, GL_TRUE); 
    gluSphere(quadratic, size, r, r); 
} 

void display(void) 
{ 
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    /* mercury */ 
    glEnable(GL_TEXTURE_2D); 
    glBindTexture(GL_TEXTURE_2D, texName[1]); 
    glColor4f(1.0, 1.0, 1.0, 1.0); 
    DrawPlanet(-17.0f, -4.0f, -9.0f, zAxis, .7f, .3f, 25); 
    glBindTexture(GL_TEXTURE_2D, 0); 
    glDisable(GL_TEXTURE_2D); 


     // rest of code is similar to the one above 
    } 

我发现它很难搞清楚为什么颜色是鲜艳的颜色的绿色,而不是代码每个星球的实际颜色..看来,该计划是棕色问题..任何想法?

+1

你确定你的文件都是'P6',对吗?并有一个最大值(在维度线上的第三个数字)为255?我不知道'GLubyte'是什么,但我知道最大值<= 255的P6每个像素只有1个字节,所以如果'GLubyte'不是1个字节,这可能是一个问题。在任何情况下,P6中的像素顺序都是红色,绿色和蓝色。 –

+0

这不是我的问题的解决方案,但它确实解决了我的问题。我做了一些打印语句来获取标题信息,以便为您拍摄它的屏幕截图。我遇到过我没有将255从混音中拉出来,因此它将255中的一些存储在我的字节中它搞砸了颜色..我把它拉出来,并将bgr更改为rgb,它完美的工作! – DWolf

+0

然后我会写一个答案。 :-) –

回答

4

P6 PPM文件的标题中有3个数字:宽度,高度和最大值。宽度和高度给出图像的尺寸,而maxval给出图像的动态范围。

在上面的代码中,扫描图像尺寸,但不扫描maxval。 maxval不能保证与图像尺寸在同一行。

因此,在开始读取图像的位置,P6的maxval作为图像信息的一部分被读入,移动所有字节并旋转表观R,G和B值。

的P6头和有效负载的确切定义如下(的man ppm提供):

  • A“幻数”用于识别文件类型。 ppm图像的幻数是两个字符“P6”。

  • 空格(空白,TAB,CR,LF)。

  • 宽度,格式为十进制的ASCII字符。

  • 空白。

  • 高度,再次以ASCII十进制表示。

  • 空白。

  • 最大颜色值(Maxval),再次以ASCII十进制表示。必须小于65536.

  • 换行符或其他单个空格字符。

  • 宽度*高度像素的光栅,按正常英语阅读顺序在图像中进行。每个像素都是红色,绿色和蓝色样本的三元组。每个采样都以纯二进制表示1或2个字节。如果Maxval小于256,则为1个字节。否则,它是2个字节。最重要的字节是第一个。

  • 字符从“#”到最后一行之前的下一行,是注释并被忽略。

这表明,而不是使用fgetssscanf(其中,说实话,往往是分析好主意,尤其是面向行的输入),你应该考虑使用与fgetc()一环和一个小国机以确保您对任何可能遇到的P6文件都完全健壮。

这样的事情可能工作:

int get_pnm_header(FILE *f) 
{ 
    int ch; 

    if ((ch = fgetc(f)) != 'P') 
     return -1;     // not a PNM file 

    if ((ch = fgetc(f)) < '1' || ch > '6') 
     return -1;     // not a PNM file 

    return ch - '0'; 
} 

int get_ppm_integer(FILE *f) 
{ 
    int in_comment = 0; 
    int in_value = 0; 
    int value  = 0; 
    int ch; 

    while ((ch = fgetc(f)) != EOF) 
    { 
     if (ch == '#') 
      in_comment = 1; 

     if (in_comment) 
     { 
      in_comment = ch != '\n'; 
      continue; 
     } 

     if (isdigit(ch)) 
      in_value = 1; 

     if (in_value) 
     { 
      if (!isdigit(ch)) 
      { 
       if (!isspace(ch)) /* consume first WS after value */ 
        ungetc(ch, f); /* If not WS, put it back (might be '#' for a comment) */ 
       return value; 
      } 

      value = (value * 10) + ch - '0'; 
      continue; 
     } 

     if (!isspace(ch)) 
     { 
      fprintf(stderr, "Warning: unexpected character '%c' in P6 header\n", ch); 
     } 
    } 
    fprintf(stderr, "Warning: EOF encountered reading P6 header\n"); 
    return -1; 
} 

,然后在你的代码进一步下跌:

int pnm_type = get_pnm_header(infile); 

if (pnm_type != 6) 
    // report an error about unexpected file type 

ImgWidth = get_ppm_integer(infile); 
ImgHeight = get_ppm_integer(infile); 
ImgMaxval = get_ppm_integer(infile); 

if (ImgMaxval != 255) 
    // report an error about unsupported maxval 

int r = fread((void *)TexBits, 3, ImgHeight * ImgWidth, infile); 

if (r != ImgHeight * ImgWidth) 
    // report an error about a short file. 

如果修改get_ppm_integer只是在EOF返回value,相信功能也会正常工作正确读取P3文件正文中的字节,如果您需要支持这些文件。

+0

添加了一个小错误修复来处理在头部有'123#comment'的情况,我不是100%确定是合法的,但似乎可能是这样,至少对于maxval之前的值'。 –