使用球体的OpenGL Frustum可见性测试:远程平面无法工作

时间:2013-09-11 00:32:01

标签: c++ opengl math geometry frustum

我正在做一个测试球体 - 平截头体交叉点的程序,并且能够确定球体的可见性。我正在将视锥体的剪裁平面提取到相机空间并检查交叉点。它适用于除了远飞机以外的所有飞机,我无法弄清楚原因。我一直把相机拉回去,但是我的程序仍然声称球体是可见的,尽管它很久以前就被剪掉了。如果我走得足够远,它最终会确定它不可见,但是它在离开平截头体之后有一段距离。

我在原点使用单位球体进行测试。我正在使用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))

我已多次查看此代码,但我不明白为什么它不起作用。任何帮助表示赞赏。

编辑: 我无法回答我自己的问题,因为我没有代表,所以我会在这里发布。 问题是我没有对平面方程进行归一化。对于除了远距离之外的任何剪辑平面,这似乎没有太大的区别,所以我甚至没有考虑它(但这并没有减少错误)。标准化后一切正常。

0 个答案:

没有答案