C++ 使用球体的OpenGL平截头体可见性测试:远平面不工作

C++ 使用球体的OpenGL平截头体可见性测试:远平面不工作,c++,opengl,math,geometry,frustum,C++,Opengl,Math,Geometry,Frustum,我正在做一个程序来测试球体与平截体的交点,并能够确定球体的可见性。我将截锥体的剪裁平面提取到相机空间中,并检查相交。它适用于除远平面以外的所有平面,我不知道为什么。我一直把相机往后拉,但我的程序仍然声称球体是可见的,尽管它很久以前就被剪掉了。如果我走得够远,它最终会确定它是不可见的,但这是它离开平截头体后的一段距离 我在原点使用一个单位球体进行测试。我将OpenGL数学(GLM)库用于向量和矩阵数据结构及其内置的数学函数。以下是我的可见性函数代码: void visibilityTest(con

我正在做一个程序来测试球体与平截体的交点,并能够确定球体的可见性。我将截锥体的剪裁平面提取到相机空间中,并检查相交。它适用于除远平面以外的所有平面,我不知道为什么。我一直把相机往后拉,但我的程序仍然声称球体是可见的,尽管它很久以前就被剪掉了。如果我走得够远,它最终会确定它是不可见的,但这是它离开平截头体后的一段距离

我在原点使用一个单位球体进行测试。我将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;
    }
} 

平面[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>