C++ Opengl将纹理应用于对象时颜色错误

C++ Opengl将纹理应用于对象时颜色错误,c++,opengl,C++,Opengl,因此,当涉及到将ppm纹理应用于四边形时,我的工作很粗糙。我的问题是颜色不正确 这是一些从水星到木星的行星 唯一正确的颜色是地球 我在线下载了纹理JPEG,然后从linux命令行转换它们 jpegtopnm Mercury.jpg > Mercury.ppm 我这样做是为了你在上面看到的所有图像 一开始颜色都颠倒了,所以我换了 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ImgWidth, ImgHeight, 0, GL_RGB,

因此,当涉及到将ppm纹理应用于四边形时,我的工作很粗糙。我的问题是颜色不正确

这是一些从水星到木星的行星

唯一正确的颜色是地球

我在线下载了纹理JPEG,然后从linux命令行转换它们

jpegtopnm Mercury.jpg > Mercury.ppm
我这样做是为了你在上面看到的所有图像

一开始颜色都颠倒了,所以我换了

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

这修正了反转的颜色r而不是b。。。发射型计算机断层扫描仪。现在我被困在这里。。如何校正纹理以显示行星的正确颜色

这是mercury纹理文件

下面是处理纹理的代码

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
     }

我发现很难弄明白为什么这些颜色是明亮的绿色而不是每个行星的实际颜色。。看来这个节目对布朗有问题。。有什么想法吗?

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

在上面的代码中,您扫描的是图像维度,而不是maxval。不能保证maxval与图像尺寸在同一条线上

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

曼恩ppm提供的P6收割台和有效载荷的准确定义如下:

用于标识文件类型的幻数。ppm图像的幻数是两个字符P6

空白、制表符、CRs、LFs

一种宽度,格式为十进制ASCII字符

空白

高度,同样以ASCII十进制表示

空白

最大颜色值Maxval,同样以ASCII十进制表示。必须小于65536

换行符或其他单个空白字符

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

从a到maxval行前的下一行末尾的字符是注释,将被忽略

这意味着,而不是使用FFET和sSCANF,坦白地说,通常是更好的解析思路,尤其是面向线的输入,你应该考虑使用FGECC和一个小型状态机来保证你对任何可能遇到的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;
} 

如果您修改get_ppm_integer以仅返回EOF上的值,我相信如果您需要支持P3文件体中的字节,该函数也可以正确地读取这些字节。

P6 ppm文件头中有3个数字:宽度、高度和最大值。宽度和高度表示图像的尺寸,最大值表示图像的动态范围

在上面的代码中,您扫描的是图像维度,而不是maxval。不能保证maxval与图像尺寸在同一条线上

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

曼恩ppm提供的P6收割台和有效载荷的准确定义如下:

用于标识文件类型的幻数。ppm图像的幻数是两个字符P6

空白、制表符、CRs、LFs

一种宽度,格式为十进制ASCII字符

空白

高度,同样以ASCII十进制表示

空白

最大颜色值Maxval,同样以ASCII十进制表示。必须小于65536

换行符或其他单个空白字符

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

从a到maxval行前的下一行末尾的字符是注释,将被忽略

这意味着,而不是使用FFET和sSCANF,坦白地说,通常是更好的解析思路,尤其是面向线的输入,你应该考虑使用FGECC和一个小型状态机来保证你对任何可能遇到的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;
} 
若您修改get_ppm_integer以只返回EOF上的值,我相信函数w
如果您需要支持P3文件,我也可以正确读取P3文件正文中的字节。

您确定您的文件都是P6,对吗?行上有一个尺寸为255的maxval第三个数字?我不知道GLubyte是什么,但我知道一个带有maxval的P6这不是我问题的解决方案,但它确实解决了我的问题。我做了一些打印语句来获取标题信息,以便为您截屏。。我发现我没有从混合中提取255,所以它将255存储在我字节中的某个位置,所以它弄乱了颜色。。我把它拔出来,把bgr换成rgb,它工作得很好!那我就写一个答案-完成。我在一天中处理了一些PNM文件,因此遇到了几种可能的边缘条件:-你确定你的文件都是P6,对吗?行上有一个尺寸为255的maxval第三个数字?我不知道GLubyte是什么,但我知道一个带有maxval的P6这不是我问题的解决方案,但它确实解决了我的问题。我做了一些打印语句来获取标题信息,以便为您截屏。。我发现我没有从混合中提取255,所以它将255存储在我字节中的某个位置,所以它弄乱了颜色。。我把它拔出来,把bgr换成rgb,它工作得很好!那我就写一个答案-完成。我在一天中处理了一些PNM文件,因此遇到了几种可能的边缘条件:-添加了一个小错误修复程序,用于处理标题中包含123comment的情况,我不是100%确定它是否合法,但似乎可以,至少对于maxval之前的值是这样。添加了一个小错误修复程序,用于处理标题中包含123comment的情况,我不是100%确定它是否合法,但似乎可以,至少对于maxval之前的值。
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.