我正在做一个测试球体 - 平截头体交叉点的程序,并且能够确定球体的可见性。我正在将视锥体的剪裁平面提取到相机空间并检查交叉点。它适用于除了远飞机以外的所有飞机,我无法弄清楚原因。我一直把相机拉回去,但是我的程序仍然声称球体是可见的,尽管它很久以前就被剪掉了。如果我走得足够远,它最终会确定它不可见,但是它在离开平截头体之后有一段距离。
我在原点使用单位球体进行测试。我正在使用OpenGL数学(GLM)库来处理矢量和矩阵数据结构以及它内置的数学函数。这是我的可见性功能代码:
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;
}
}
多边形似乎被远处平面正确地修剪,因此看起来投影矩阵设置得恰当,但计算使得它看起来像是飞机远远不够。也许我没有正确计算某些东西或者对所需的计算有根本的误解?
专门处理远剪裁平面的计算是:
plane[1] = rowVec[3] - rowVec[2]; //far
和
plane[1][3] += plane[1][2]; // <0,0,-1>
我将平面设置为等于投影矩阵的第4行(或在本例中为列) - 投影矩阵的第3行。然后我将远平面延伸到一个单位(由于球体的半径为1; D'= D - C(-1))
我已多次查看此代码,但我不明白为什么它不起作用。任何帮助表示赞赏。
编辑: 我无法回答我自己的问题,因为我没有代表,所以我会在这里发布。 问题是我没有对平面方程进行归一化。对于除了远距离之外的任何剪辑平面,这似乎没有太大的区别,所以我甚至没有考虑它(但这并没有减少错误)。标准化后一切正常。