glReadPixels()返回0

时间:2014-04-25 07:09:04

标签: c++ opengl

我在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;
}

1 个答案:

答案 0 :(得分:2)

罗杰罗兰指出你正在从屏幕的错误部分读书。在将y坐标传递到glReadPixels()

之前,需要先翻转它

其他事项:

  1. 您不需要erasetank()erasebullet(),只需清除每一帧的屏幕
  2. glClear()和您的矩阵内容放入显示回调中是个好主意
  3. 明确glutInitDisplayMode()是个好主意
  4. 没有真正的理由不使用GLUT_DOUBLE
  5. 使用glutTimerFunc()代替sleep()
  6. 所有在一起:

    #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;
    }