1

我有一些转换矩阵的代码,并添加了一些处理 Frustum 和 Perspective 的函数。

问题是,当我调用透视图时,一切看起来好像我有一个非常大的视野(在屏幕中间还可以,而在边缘非常拉伸)。当我增加近值时,这种效果会更糟。

    void Frustum(T left, T right, T bottom, T top, T zNear, T zFar)
    {
        m[0][0]=2.0f*zNear/(right-left);
        m[1][0]=0.0f;
        m[2][0]=(right+left)/(right-left);
        m[3][0]=0.0f;
        m[0][1]=0.0f;
        m[1][1]=2.0f*zNear/(top-bottom);
        m[2][1]=(top+bottom)/(top-bottom);
        m[3][1]=0.0f;
        m[0][2]=0.0f;
        m[1][2]=0.0f;
        m[2][2]=-(zFar+zNear)/(zFar-zNear);
        m[3][2]=-2.0f*zFar*zNear/(zFar-zNear);
        m[0][3]=0.0f;
        m[1][3]=0.0f;
        m[2][3]=-1.0f;
        m[3][3]=0.0f;
    }

    void Perspective(T fovy,T aspectRatio,T zNear,T zFar)
    {
        T xmin,xmax,ymin,ymax;
        ymax= zNear* tan(fovy*Math<T>::PI/360.0);
        ymin= -ymax;
        xmin= ymin*aspectRatio;
        xmax= ymax*aspectRatio;
        Frustum(xmin,xmax,ymin,ymax,zNear,zFar);
    }

T 是一个浮点数或双精度类,因为该类是模板化的(对于测试,我只使用了浮点数)。

我使用的测试值是fovy="60" znear="1.0" zfar="1000.0",当我将它们更改为fovy="60" znear="10.0" zfar="1000.0"它时会变得更糟。

请注意,矩阵是 DirectX 样式,但我在 OpenGL 中使用它们,因此我更改了着色器中的乘法顺序。

你们看到我的代码有什么问题吗?

谢谢

4

3 回答 3

2

问题是当我开始使用转置的矩阵(DirectX 风格)时,我想我还必须转置平截头体数学,这不是一个好主意。

这就是 Frustum 函数的样子:

    void Frustum(T left, T right, T bottom, T top, T zNear, T zFar)
    {
        T zDelta = (zFar-zNear);
        T dir = (right-left);
        T height = (top-bottom);
        T zNear2 = 2*zNear;

        m[0][0]=2.0f*zNear/dir;
        m[0][1]=0.0f;
        m[0][2]=(right+left)/dir;
        m[0][3]=0.0f;
        m[1][0]=0.0f;
        m[1][1]=zNear2/height;
        m[1][2]=(top+bottom)/height;
        m[1][3]=0.0f;
        m[2][0]=0.0f;
        m[2][1]=0.0f;
        m[2][2]=-(zFar+zNear)/zDelta;
        m[2][3]=-zNear2*zFar/zDelta;
        m[3][0]=0.0f;
        m[3][1]=0.0f;
        m[3][2]=-1.0f;
        m[3][3]=0.0f;
    }
于 2012-07-20T08:44:33.720 回答
1

计算

z_delta=(zfar-znear);//used two times!
direction=(right-left);//used two times!
height=(top-bottom);//used two times!
znear_2=2.0f*znear; //used 3 times!

只有一次!然后在任何你想要的地方使用它

而且,除法非常昂贵,您可以预先计算除法并将其存储在数组中,您只需要在执行中从数组中获取预先计算的元素。

例如:如果顶部和底部范围很小,那么您可以在一个小数组中表示计算(实际上它是一个除法器和一个除法器的映射)

于 2012-07-19T09:20:31.460 回答
0

我认为问题在于Perspective():计算时ymax,你不应该乘以zNear。从数学上讲,您投影到单位距离的平面上,而不是zNear平面上;那个价值在那里没有生意。

尝试只是设置ymax= tan(fovy*Math<T>::PI/360.0)。仍然不能保证它是正确的,但这应该更加理智......

于 2012-07-19T18:21:52.563 回答