因此,当涉及将ppm纹理应用于四边形时,我正在做大事。我的问题是颜色不正确。
这是从水银到木星的几个行星。
唯一正确的颜色是地球。
我在网上下载了纹理(jpegs),然后从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 ...等)。现在我被困在这里..如何纠正纹理以显示行星的正确颜色?
这是水银纹理文件
这是处理纹理的代码
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
}
我发现很难弄清楚为什么颜色是绿色的明亮颜色而不是每个星球的实际颜色..似乎该程序有褐色的问题..任何想法?
答案 0 :(得分:4)
P6 PPM文件的标题中有3个数字:宽度,高度和最大值。宽度和高度给出图像的尺寸,maxval给出图像的动态范围。
在上面的代码中,您扫描图像尺寸,但不扫描maxval。不保证maxval与图像尺寸在同一直线上。
因此,在您开始读取图像时,P6的maxval作为图像信息的一部分被读入,移动所有字节,并旋转明显的R,G和B值。
P6标头和有效载荷的确切定义如下(由man ppm
提供):
用于识别文件类型的“幻数”。 ppm图像的幻数是两个字符“P6”。
空白(空白,TAB,CR,LF)。
宽度,格式为十进制的ASCII字符。
空白。
高度,再次为ASCII十进制。
空白。
最大颜色值(Maxval),再次以ASCII十进制表示。必须小于65536。
换行符或其他单个空白字符。
宽度*高度像素的光栅,以正常的英语阅读顺序继续浏览图像。每个像素按顺序是红色,绿色和蓝色样本的三元组。每个样本用纯二进制表示1或2个字节。如果Maxval小于256,则为1个字节。否则,它是2个字节。最重要的字节是第一个。
从“#”到最后一行之前的下一行末尾的字符是注释,会被忽略。
这表明,而不是使用fgets
和sscanf
(老实说,通常是解析的更好主意,特别是使用面向行的输入),您应该考虑使用{{{ 1}}和一个小型状态机,以确保您对可能遇到的任何P6文件完全健壮。
这样的事情可能有用:
fgetc()
然后在你的代码中进一步向下:
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.
以仅在EOF上返回get_ppm_integer
,我相信如果您需要支持,该函数也可以正常读取value
文件正文中的字节那些。