我在Windows平台上使用gl和过剩
我的问题是glReadPixels返回全0。我想这与我初始化窗口的方式有关,因此它无法获得正确的像素值。
这是我初始化窗口的方式:
glutInit(&argc, argv);
glutInitWindowSize(800,600);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 800, 600, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.375, 0.375, 0);
glClearColor(0, 0, 0, 1.0);
有了这个,我得到所有0:
修改
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x-20, y-20);
glVertex2i(x-20, y+20);
glVertex2i(x+20, y+20);
glVertex2i(x+20, y-20);
glEnd();
unsigned char pixel[4];
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
在我glClear之后,我确实渲染了一些形状,在(x,y)然后我使用glReadPixels来获得(x,y)的颜色,但它返回0。我尝试在整个屏幕上使用glReadPixels,它也会返回0。
编辑2:
所以,为了更清楚我的问题,这里是代码: 我只是不知道问题的根源在哪里,所以我在这里粘贴了所有代码。这是Jonathan S. Habour撰写的“Game Programming All in One”一书中的坦克计划。本书使用Allegro库,我尝试转换为openGL。在updatebullet程序的“寻找命中”中,我打印出敌人坦克的坐标和该像素的颜色,但我得到的只是0。
#include <GL/glut.h>
#include <stdlib.h>
#include <iostream.h>
#include <windows.h>
//define tank structure
struct tagTank
{
int x,y;
int dir,speed;
} tanks[2];
struct tagBullet
{
int x,y;
int alive;
int xspd,yspd;
} bullets[2];
void setuptanks()
{
tanks[0].x = 30;
tanks[0].y = 40;
tanks[0].dir = 1;
tanks[0].speed = 5;
tanks[1].x = 800 - 30;
tanks[1].y = 600 - 30;
tanks[1].dir = 3;
tanks[1].speed = 5;
}
void drawtank(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
int dir = tanks[num].dir;
//draw tank body
glColor3f(1.0, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-20, y-20);
glVertex2i(x-20, y+20);
glVertex2i(x+20, y+20);
glVertex2i(x+20, y-20);
glEnd();
glColor3f(0.5, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 0.5);
glBegin(GL_QUADS);
glVertex2i(x-10, y-10);
glVertex2i(x-10, y+10);
glVertex2i(x+10, y+10);
glVertex2i(x+10, y-10);
glEnd();
//draw the turret based on direction
glColor3f(1.0, 1.0, 1.0);
switch (dir)
{
case 0:
glBegin(GL_QUADS);
glVertex2i(x-2, y-30);
glVertex2i(x-2, y);
glVertex2i(x+2, y);
glVertex2i(x+2, y-30);
glEnd();
break;
case 1:
glBegin(GL_QUADS);
glVertex2i(x, y-2);
glVertex2i(x, y+2);
glVertex2i(x+30, y+2);
glVertex2i(x+30, y-2);
glEnd();
break;
case 2:
glBegin(GL_QUADS);
glVertex2i(x-2, y);
glVertex2i(x-2, y+30);
glVertex2i(x+2, y+30);
glVertex2i(x+2, y);
glEnd();
break;
case 3:
glBegin(GL_QUADS);
glVertex2i(x-30, y-2);
glVertex2i(x-30, y+2);
glVertex2i(x, y+2);
glVertex2i(x, y-2);
glEnd();
break;
}
}
void erasetank(int num)
{
//calculate box to encompass the tank
int left = tanks[num].x - 30;
int top = tanks[num].y - 30;
int right = tanks[num].x + 30;
int bottom = tanks[num].y + 30;
//erase the tank
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(left, top);
glVertex2i(left, bottom);
glVertex2i(right, bottom);
glVertex2i(right, top);
glEnd();
}
void movetank(int num)
{
int dir = tanks[num].dir;
int speed = tanks[num].speed;
//update tank position based on direction
switch(dir)
{
case 0:
tanks[num].y -= speed;
break;
case 1:
tanks[num].x += speed;
break;
case 2:
tanks[num].y += speed;
break;
case 3:
tanks[num].x -= speed;
break;
}
//keep tank inside the screen
if (tanks[num].x > 800-30)
{
tanks[num].x = 800-30;
tanks[num].speed = 0;
}
else if (tanks[num].x < 30)
{
tanks[num].x = 30;
tanks[num].speed = 0;
}
else if (tanks[num].y > 600-30)
{
tanks[num].y = 600-30;
tanks[num].speed = 0;
}
else if (tanks[num].y < 30)
{
tanks[num].y = 30;
tanks[num].speed = 0;
}
else tanks[num].speed = 5;
}
void explode(int num, int x, int y)
{
int n;
//retrieve location of enemy tank
int tx = tanks[!num].x;
int ty = tanks[!num].y;
//is bullet inside the boundary of the enemy tank?
if (x > tx-30 && x < tx+30 && y > ty-30 && y < ty+30)
setuptanks();
//draw some random circles for the "explosion"
for (n = 0; n < 10; n++)
{
glColor3f((rand() % 101)/100.0, (rand() % 101)/100.0, (rand() % 101)/100.0);
glBegin(GL_QUADS);
glVertex2i(x-16, y-16);
glVertex2i(x-16, y+16);
glVertex2i(x+16, y+16);
glVertex2i(x+16, y-16);
glEnd();
//Sleep(10);
}
//clear the area of debris
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x-16, y-16);
glVertex2i(x-16, y+16);
glVertex2i(x+16, y+16);
glVertex2i(x+16, y-16);
glEnd();
}
void updatebullet(int num)
{
int x = bullets[num].x;
int y = bullets[num].y;
if (bullets[num].alive)
{
//erase bullet
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x-2, y-2);
glVertex2i(x-2, y+2);
glVertex2i(x+2, y+2);
glVertex2i(x+2, y-2);
glEnd();
//move bullet
bullets[num].x += bullets[num].xspd;
bullets[num].y += bullets[num].yspd;
x = bullets[num].x;
y = bullets[num].y;
//stay within the screen
if (x < 5 || x > 800 || y < 20 || y > 600)
{
bullets[num].alive = 0;
return;
}
//look for a hit
unsigned char pixel[4];
glReadPixels(tanks[!num].x, tanks[!num].y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
cout << tanks[!num].x << ", " << tanks[!num].y << " | " << (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << endl;
if ((int)pixel[0] || (int)pixel[1] || (int)pixel[2])
{
bullets[num].alive = 0;
explode(num, x, y);
return;
}
//draw bullet
x = bullets[num].x;
y = bullets[num].y;
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-2, y-2);
glVertex2i(x-2, y+2);
glVertex2i(x+2, y+2);
glVertex2i(x+2, y-2);
glEnd();
}
}
void fireweapon(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
//ready to fire again?
if (!bullets[num].alive)
{
bullets[num].alive = 1;
//fire bullet in direction tank is facing
switch (tanks[num].dir)
{
//north
case 0:
bullets[num].x = x;
bullets[num].y = y-30;
bullets[num].xspd = 0;
bullets[num].yspd = -20;
break;
//east
case 1:
bullets[num].x = x+30;
bullets[num].y = y;
bullets[num].xspd = 20;
bullets[num].yspd = 0;
break;
//south
case 2:
bullets[num].x = x;
bullets[num].y = y+30;
bullets[num].xspd = 0;
bullets[num].yspd = 20;
break;
//west
case 3:
bullets[num].x = x-30;
bullets[num].y = y;
bullets[num].xspd = -20;
bullets[num].yspd = 0;
break;
}
}
}
void up(int num)
{
tanks[num].dir = 0;
}
void down(int num)
{
tanks[num].dir = 2;
}
void left(int num)
{
tanks[num].dir = 3;
}
void right(int num)
{
tanks[num].dir = 1;
}
static void display(void)
{
erasetank(0);
erasetank(1);
movetank(0);
movetank(1);
drawtank(0);
drawtank(1);
updatebullet(0);
updatebullet(1);
glFlush();
Sleep(50);
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
exit(0);
break;
case 'a':
left(1);
break;
case 'd':
right(1);
break;
case 'w':
up(1);
break;
case 's':
down(1);
break;
case 32:
fireweapon(1);
break;
case 13:
fireweapon(0);
break;
}
glutPostRedisplay();
}
static void specialkey(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT:
left(0);
break;
case GLUT_KEY_RIGHT:
right(0);
break;
case GLUT_KEY_UP:
up(0);
break;
case GLUT_KEY_DOWN:
down(0);
break;
}
glutPostRedisplay();
}
static void idle(void)
{
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(800,600);
glutInitWindowPosition(10,10);
glutCreateWindow("Tanks");
glClear(GL_COLOR_BUFFER_BIT);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutSpecialFunc(specialkey);
glutIdleFunc(idle);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 800, 600, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.375, 0.375, 0);
glClearColor(0, 0, 0, 1.0);
setuptanks();
glutMainLoop();
return EXIT_SUCCESS;
}
答案 0 :(得分:2)
罗杰罗兰指出你正在从屏幕的错误部分读书。在将y坐标传递到glReadPixels()
其他事项:
erasetank()
或erasebullet()
,只需清除每一帧的屏幕glClear()
和您的矩阵内容放入显示回调中是个好主意glutInitDisplayMode()
是个好主意GLUT_DOUBLE
glutTimerFunc()
代替sleep()
所有在一起:
#include <GL/glut.h>
#include <iostream>
using namespace std;
//define tank structure
struct tagTank
{
int x,y;
int dir,speed;
} tanks[2];
struct tagBullet
{
int x,y;
int alive;
int xspd,yspd;
} bullets[2];
void setuptanks()
{
tanks[0].x = 30;
tanks[0].y = 40;
tanks[0].dir = 1;
tanks[0].speed = 5;
tanks[1].x = 800 - 30;
tanks[1].y = 600 - 30;
tanks[1].dir = 3;
tanks[1].speed = 5;
}
void drawtank(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
int dir = tanks[num].dir;
//draw tank body
glColor3f(1.0, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-20, y-20);
glVertex2i(x-20, y+20);
glVertex2i(x+20, y+20);
glVertex2i(x+20, y-20);
glEnd();
glColor3f(0.5, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 0.5);
glBegin(GL_QUADS);
glVertex2i(x-10, y-10);
glVertex2i(x-10, y+10);
glVertex2i(x+10, y+10);
glVertex2i(x+10, y-10);
glEnd();
//draw the turret based on direction
glColor3f(1.0, 1.0, 1.0);
switch (dir)
{
case 0:
glBegin(GL_QUADS);
glVertex2i(x-2, y-30);
glVertex2i(x-2, y);
glVertex2i(x+2, y);
glVertex2i(x+2, y-30);
glEnd();
break;
case 1:
glBegin(GL_QUADS);
glVertex2i(x, y-2);
glVertex2i(x, y+2);
glVertex2i(x+30, y+2);
glVertex2i(x+30, y-2);
glEnd();
break;
case 2:
glBegin(GL_QUADS);
glVertex2i(x-2, y);
glVertex2i(x-2, y+30);
glVertex2i(x+2, y+30);
glVertex2i(x+2, y);
glEnd();
break;
case 3:
glBegin(GL_QUADS);
glVertex2i(x-30, y-2);
glVertex2i(x-30, y+2);
glVertex2i(x, y+2);
glVertex2i(x, y-2);
glEnd();
break;
}
}
void movetank(int num)
{
int dir = tanks[num].dir;
int speed = tanks[num].speed;
//update tank position based on direction
switch(dir)
{
case 0:
tanks[num].y -= speed;
break;
case 1:
tanks[num].x += speed;
break;
case 2:
tanks[num].y += speed;
break;
case 3:
tanks[num].x -= speed;
break;
}
//keep tank inside the screen
if (tanks[num].x > 800-30)
{
tanks[num].x = 800-30;
tanks[num].speed = 0;
}
else if (tanks[num].x < 30)
{
tanks[num].x = 30;
tanks[num].speed = 0;
}
else if (tanks[num].y > 600-30)
{
tanks[num].y = 600-30;
tanks[num].speed = 0;
}
else if (tanks[num].y < 30)
{
tanks[num].y = 30;
tanks[num].speed = 0;
}
else tanks[num].speed = 5;
}
void explode(int num, int x, int y)
{
int n;
//retrieve location of enemy tank
int tx = tanks[!num].x;
int ty = tanks[!num].y;
//is bullet inside the boundary of the enemy tank?
if (x > tx-30 && x < tx+30 && y > ty-30 && y < ty+30)
setuptanks();
//draw some random circles for the "explosion"
for (n = 0; n < 10; n++)
{
glColor3f((rand() % 101)/100.0, (rand() % 101)/100.0, (rand() % 101)/100.0);
glBegin(GL_QUADS);
glVertex2i(x-16, y-16);
glVertex2i(x-16, y+16);
glVertex2i(x+16, y+16);
glVertex2i(x+16, y-16);
glEnd();
}
}
void updatebullet(int num)
{
if (bullets[num].alive)
{
//move bullet
bullets[num].x += bullets[num].xspd;
bullets[num].y += bullets[num].yspd;
int x = bullets[num].x;
int y = bullets[num].y;
//stay within the screen
if (x < 5 || x > 800 || y < 20 || y > 600)
{
bullets[num].alive = 0;
return;
}
//look for a hit
unsigned char pixel[4];
int h = glutGet( GLUT_WINDOW_HEIGHT );
glReadPixels(x, h - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
cout << x << ", " << y << " | " << (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << endl;
if ((int)pixel[0] || (int)pixel[1] || (int)pixel[2])
{
bullets[num].alive = 0;
explode(num, x, y);
return;
}
//draw bullet
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-2, y-2);
glVertex2i(x-2, y+2);
glVertex2i(x+2, y+2);
glVertex2i(x+2, y-2);
glEnd();
}
}
void fireweapon(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
//ready to fire again?
if (!bullets[num].alive)
{
bullets[num].alive = 1;
//fire bullet in direction tank is facing
switch (tanks[num].dir)
{
//north
case 0:
bullets[num].x = x;
bullets[num].y = y-30;
bullets[num].xspd = 0;
bullets[num].yspd = -20;
break;
//east
case 1:
bullets[num].x = x+30;
bullets[num].y = y;
bullets[num].xspd = 20;
bullets[num].yspd = 0;
break;
//south
case 2:
bullets[num].x = x;
bullets[num].y = y+30;
bullets[num].xspd = 0;
bullets[num].yspd = 20;
break;
//west
case 3:
bullets[num].x = x-30;
bullets[num].y = y;
bullets[num].xspd = -20;
bullets[num].yspd = 0;
break;
}
}
}
void up(int num)
{
tanks[num].dir = 0;
}
void down(int num)
{
tanks[num].dir = 2;
}
void left(int num)
{
tanks[num].dir = 3;
}
void right(int num)
{
tanks[num].dir = 1;
}
static void display(void)
{
glClearColor(0, 0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
int w = glutGet( GLUT_WINDOW_WIDTH );
int h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375, 0.375, 0);
movetank(0);
movetank(1);
drawtank(0);
drawtank(1);
glFlush();
updatebullet(0);
updatebullet(1);
glutSwapBuffers();
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 : exit(0); break;
case 'a': left(1); break;
case 'd': right(1); break;
case 'w': up(1); break;
case 's': down(1); break;
case 32: fireweapon(1); break;
case 13: fireweapon(0); break;
}
}
static void specialkey(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT: left(0); break;
case GLUT_KEY_RIGHT: right(0); break;
case GLUT_KEY_UP: up(0); break;
case GLUT_KEY_DOWN: down(0); break;
}
}
void timer( int value )
{
glutTimerFunc( 50, timer, 0 );
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInitWindowSize(800,600);
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutCreateWindow("Tanks");
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutSpecialFunc(specialkey);
glutTimerFunc( 0, timer, 0 );
setuptanks();
glutMainLoop();
return EXIT_SUCCESS;
}