对于我正在编写的算法,我需要取消投影我的屏幕坐标并将它们重新投影到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选项应保持为零。
答案 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,你应该使用变量或命名常量;保持您的代码可维护。