glUnproject之后的奇怪结果并重新绘制场景

时间:2011-08-21 15:45:02

标签: opengl graphics 3d

对于我正在编写的算法,我需要取消投影我的屏幕坐标并将它们重新投影到lightspace中。这样做如下:我从我的视点填充深度缓冲区(使用glLookAt),然后我将所有可见像素取消投影到世界空间。然后我将它们重新投射到光照空间。

我正在检查所有内容以确保我没有犯错(之后我还要做其他的事情),所以我从lightspace中绘制了新投影的像素。为了确保我得到了正确的结果,我假设我的光与我的眼睛在同一个位置。

Correct result http://img825.imageshack.us/img825/5971/correct.png

是原始场景。然后我取消投影并重绘它们,我得到了这个结果:

Incorrect result http://img268.imageshack.us/img268/4072/resultak.png

void getObjectCoords(){
std::vector<GLfloat> z(800*600, 0);
std::vector< Vertex > lightPoints;

GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLdouble posX, posY, posZ;

//Setting our original viewpoint for unprojecting
gluLookAt(4.0,4.0,15.0, 0.0,0.0,0.0,0.0,1.0,0.0);

//Getting Modelviewx, Projection and viewport matrix
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );

//Reset the modelview
glLoadIdentity();

//Get the depth coordinate of the original points
glReadPixels( 0, 0,800, 600,GL_DEPTH_COMPONENT,GL_FLOAT, &z[0] );

//Unprojecting X and Y.
int count = 0;
Vertex temp;
for( int X = 0; X < 800; ++X){
    for( int Y = 0; Y < 600; ++Y){ 
        gluUnProject( X, Y, z[X*600 + Y], modelview, projection, viewport, &posX, &posY, &posZ);
        if( z[X*600 + Y] < 1){
            ++count;
            temp.x = posX;
            temp.y = posY;
            temp.z = posZ;
            lightPoints.push_back(temp);
        }
    }
}
std::cout << count << " pixels closer to the viewpoint" << std::endl;

//Projecting the original points to lightspace
gluLookAt( 4.0, 4.0, 15.0, 0.0,0.0,0.0,0.0,1.0,0.0);

//We get the new modelview matrix
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );

//We reset the modelview matrix
glLoadIdentity();

GLdouble winX, winY, winZ;
//Projecting the points into lightspace and saving the sample points
for(vector<Vertex>::iterator vertex = lightPoints.begin(); vertex != lightPoints.end(); ++vertex){
    gluProject( vertex->x, vertex->y, vertex->z,modelview, projection, viewport, &winX, &winY, &winZ );
    temp.x = winX;
    temp.y = winY;
    temp.z = winZ;
    samplePoints.push_back(temp);
}

//std::cout << count << " pixels with depth greater or smaller than 1 " << std::endl;
// Duplicate code below is to draw the sample points

gluLookAt( 4.0, 4.0, 15.0, 0.0,0.0,0.0,0.0,1.0,0.0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

glBegin(GL_POINTS);

for(vector<Vertex>::iterator vertex = lightPoints.begin(); vertex != lightPoints.end(); ++vertex){
    glColor3f(0.0,1.0,0.0);
    glVertex3f(vertex->x, vertex->y, vertex->z);
}
glEnd();

}

在我看来,场景是站在一边的,虽然我不知道为什么。您还可以在不同高度部分地看到场景,如果这些都在我的图像完全相同的高度上(并且我有正确的结果)。

那么,它是什么原因并且如此分散? (有些东西告诉我这两件事可能会联系起来。)

编辑: 根据下面给出的建议,我开始尝试不同的pixelstore选项: GL_PACK_ALIGNEMENT似乎没有任何效果,我尝试了1,2,4和8。 GL_PACK_ROW_LENGTH在0处正确,它采用readpixels中指定的宽度。 看到我不想跳过任何东西,SKIP选项应保持为零。

1 个答案:

答案 0 :(得分:2)

这看起来您没有正确设置像素存储参数(步幅,对齐等),尤其是PACK参数。查看http://www.opengl.org/sdk/docs/man/xhtml/glPixelStore.xml的完整选项集。在您的情况下,您想要设置

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);

在致电 glReadPixels

之前

修改/更新

您的代码中还有另一个问题:您处理像素阵列的方式。你写了

gluUnProject( …, z[X*600 + Y], …)

这是错误的。每行(在您的情况下)是800像素宽,因此要前进一行,您必须偏移800个元素。因此,要解决(宽度,高度)线性阵列中的像素(x,y),必须编写

data[y*width + x]

或在你的情况下

z[Y*800 + X]

而不是硬编码800×600,你应该使用变量或命名常量;保持您的代码可维护。