C++ 使用球体的OpenGL平截头体可见性测试:远平面不工作
我正在做一个程序来测试球体与平截体的交点,并能够确定球体的可见性。我将截锥体的剪裁平面提取到相机空间中,并检查相交。它适用于除远平面以外的所有平面,我不知道为什么。我一直把相机往后拉,但我的程序仍然声称球体是可见的,尽管它很久以前就被剪掉了。如果我走得够远,它最终会确定它是不可见的,但这是它离开平截头体后的一段距离 我在原点使用一个单位球体进行测试。我将OpenGL数学(GLM)库用于向量和矩阵数据结构及其内置的数学函数。以下是我的可见性函数代码:C++ 使用球体的OpenGL平截头体可见性测试:远平面不工作,c++,opengl,math,geometry,frustum,C++,Opengl,Math,Geometry,Frustum,我正在做一个程序来测试球体与平截体的交点,并能够确定球体的可见性。我将截锥体的剪裁平面提取到相机空间中,并检查相交。它适用于除远平面以外的所有平面,我不知道为什么。我一直把相机往后拉,但我的程序仍然声称球体是可见的,尽管它很久以前就被剪掉了。如果我走得够远,它最终会确定它是不可见的,但这是它离开平截头体后的一段距离 我在原点使用一个单位球体进行测试。我将OpenGL数学(GLM)库用于向量和矩阵数据结构及其内置的数学函数。以下是我的可见性函数代码: void visibilityTest(con
void visibilityTest(const struct MVP *mvp) {
static bool visLastTime = true;
bool visThisTime;
const glm::vec4 modelCenter_worldSpace = glm::vec4(0,0,0,1); //at origin
const int negRadius = -1; //unit sphere
//Get cam space model center
glm::vec4 modelCenter_cameraSpace = mvp->view * mvp->model * modelCenter_worldSpace;
//---------Get Frustum Planes--------
//extract projection matrix row vectors
//NOTE: since glm stores their mats in column-major order, we extract columns
glm::vec4 rowVec[4];
for(int i = 0; i < 4; i++) {
rowVec[i] = glm::vec4( mvp->projection[0][i], mvp->projection[1][i], mvp->projection[2][i], mvp->projection[3][i] );
}
//determine frustum clipping planes (in camera space)
glm::vec4 plane[6];
//NOTE: recall that indices start at zero. So M4 + M3 will be rowVec[3] + rowVec[2]
plane[0] = rowVec[3] + rowVec[2]; //near
plane[1] = rowVec[3] - rowVec[2]; //far
plane[2] = rowVec[3] + rowVec[0]; //left
plane[3] = rowVec[3] - rowVec[0]; //right
plane[4] = rowVec[3] + rowVec[1]; //bottom
plane[5] = rowVec[3] - rowVec[1]; //top
//extend view frustum by 1 all directions; near/far along local z, left/right among local x, bottom/top along local y
// -Ax' -By' -Cz' + D = D'
plane[0][3] -= plane[0][2]; // <x',y',z'> = <0,0,1>
plane[1][3] += plane[1][2]; // <0,0,-1>
plane[2][3] += plane[2][0]; // <-1,0,0>
plane[3][3] -= plane[3][0]; // <1,0,0>
plane[4][3] += plane[4][1]; // <0,-1,0>
plane[5][3] -= plane[5][1]; // <0,1,0>
//----------Determine Frustum-Sphere intersection--------
//if any of the dot products between model center and frustum plane is less than -r, then the object falls outside the view frustum
visThisTime = true;
for(int i = 0; i < 6; i++) {
if( glm::dot(plane[i], modelCenter_cameraSpace) < static_cast<float>(negRadius) ) {
visThisTime = false;
}
}
if(visThisTime != visLastTime) {
printf("Sphere is %s visible\n", (visThisTime) ? "" : "NOT " );
visLastTime = visThisTime;
}
}
及
平面[1][3]+=平面[1][2];//
我将平面设置为等于投影矩阵的第4行(或在本例中为列),即投影矩阵的第3行。然后我将远平面再延伸一个单位(由于球体的半径为1;D'=D-C(-1))
我已经检查了很多次这个代码,我不明白为什么它不应该工作。感谢您的帮助
编辑:
我不能回答我自己的问题,因为我没有代表,所以我会把它贴在这里。
问题是我没有规范化平面方程。这似乎对除远平面之外的任何剪辑平面都没有太大影响,所以我甚至没有考虑过(但这并没有减少错误)。正常化后,一切正常 //这让我相信,如果使用剪辑空间的传统定义,那么扩展的方向是错误的。这是近平面,在这一点上,平面方程应该在相机空间中,或者我已经读到了。所以我想把一个单位从负轴向下平移到屏幕上,但我确实尝试了一个正轴。不幸的是,同样的问题仍然存在。您对近平面和远平面(与摄影机的距离)使用的值是什么请记住深度缓冲区的位计数有限,并且它不是线性的(精度越高,越近越远),因此当您使用单位球体到距离摄影机100的距离时,深度值可能会关闭。。。如果有区别的话,试着降低近距离和远距离之间的差异。如果是,则使用线性深度缓冲(通过GLSL)或使用更多平锥渲染场景可能会获得更好的效果(对于视图0.1m-100 AU,我在astro引擎中为单个场景使用3个单独的投影矩阵)
plane[1] = rowVec[3] - rowVec[2]; //far
plane[1][3] += plane[1][2]; // <0,0,-1>