用于平铺渲染的OpenGL矩阵设置

时间:2015-01-26 17:48:58

标签: opengl matrix tile

阅读datenwolf's 2011 answer concerning tile-based render setup in OpenGL后,我试图实施他的解决方案。源图像看起来像这样(800 x 600)

Original image

使用2x2图块生成的图像,每个图块的每个图块为800 x 600,如下所示。

Resulting 4 images joined together

正如你所看到的那样,他们并不完全匹配,尽管我可以看到一些有趣的事情发生了。我确定我在某个地方犯了一个小错误,但我看不太清楚。

我正在做4次传球:

w, h are 2,2 (2x2 tiles)    
x, y are (0,0) (1,0) (0,1) and (1,1) in each of the 4 passes    
MyFov is 1.30899692 (75 degrees)
MyWindowWidth, MyWindowHeight are 800, 600
MyNearPlane, MyFarPlane are 0.1, 200.0

计算每个图块的平截头体的算法是:

auto aspect = static_cast<float>(MyWindowWidth) / static_cast<float>(MyWindowHeight);
auto right = -0.5f * Math::Tan(MyFov) * MyShaderData.Camera_NearPlane;
auto left = -right;
auto top = aspect * right;
auto bottom = -top;
auto shift_X = (right - left) / static_cast<float>(w);
auto shift_Y = (top - bottom) / static_cast<float>(h);
auto frustum = Math::Frustum(left   + shift_X * static_cast<float>(x),
                             left   + shift_X * static_cast<float>(x + 1), 
                             bottom + shift_Y * static_cast<float>(y),
                             bottom + shift_Y * static_cast<float>(y + 1),
                             MyShaderData.Camera_NearPlane,
                             MyShaderData.Camera_FarPlane);

,其中Math :: Frustum是:

template<class T>
Matrix4x4<T> Frustum(T left, T right, T bottom, T top, T nearPlane, T farPlane)
{
    Matrix4x4<T> r(InitialiseAs::InitialiseZero);

    r.m11 = (static_cast<T>(2) * nearPlane) / (right - left);
    r.m22 = (static_cast<T>(2) * nearPlane) / (top - bottom);
    r.m31 = (right + left) / (right - left);
    r.m32 = (top + bottom) / (top - bottom);
    r.m33 = -(farPlane + nearPlane) / (farPlane - nearPlane);
    r.m34 =   static_cast<T>(-1);
    r.m43 = -(static_cast<T>(2) * farPlane * nearPlane) / (farPlane - nearPlane);

    return r;
}

为了完整起见,我的Matrx4x4布局是:

struct
{
    T m11, m12, m13, m14;
    T m21, m22, m23, m24;
    T m31, m32, m33, m34;
    T m41, m42, m43, m44;
};

有人可以发现我的错误吗?

修改

所以derhass向我解释 - 一种更简单的做事方式是简单地缩放和翻译投影矩阵。为了测试,我修改了我的翻译矩阵,按比例放大了2倍,如下所示(更改每个图块的平移):

auto scale = Math::Scale(2.f, 2.f, 1.f);
auto translate = Math::Translate(0.5f, 0.5f, 0.f);
auto projection = Math::Perspective(MyFov,
                                    static_cast<float>(MyWindowWidth) / static_cast<float>(MyWindowHeight),
                                    MyShaderData.Camera_NearPlane,
                                    MyShaderData.Camera_FarPlane);          

MyShaderData.Camera_Projection = scale * translate * projection;

结果图像在下方(拼接4在一起) - 图像中的不连续性是由我认为的后期处理引起的,所以这是我可能需要在某个时刻处理的另一个问题。

Resulting image

1 个答案:

答案 0 :(得分:3)

这不是这个问题的真正答案,但它可能是您在此尝试解决的有用的替代方法。在我看来,datenwolf在他对你所指的stackoverflow question的回答中的解决方案更加复杂,需要它。所以我在这里提出我的选择。

Forword:我假设标准的OpenGL矩阵约定,因此使用矩阵M的顶点变换完成为v'= M *v(就像固定功能管道一样)。

当使用某个投影矩阵P渲染场景时,您可以通过在投影矩阵之后应用缩放和变换操作来提取所述场景的任何轴对齐的子矩形。应用

关键是观察体积被定义为NDC空间中的[-1,1] ^ 3立方体。剪辑空间(P将数据转换为)只是该卷的同质表示。由于典型的4x4转换矩阵都在同质空间中工作,我们根本不需要关心w,只需定义转换就像我们在NDC空间中一样。

由于您只需要一些2D平铺,z应保持原样,并且只需要xy中的某些比例和翻译。将转换AB组合成单个矩阵C作为C=A*B时,遵循上述约定会导致首先应用B,并{{1 last(since A)。因此,要在投影之后修改结果,我们必须预先 - 将一些转换成为C*v == A*B*v == A*(B*v),我们就完成了:

P

P'=S(sx,sy,1) * T(tx,ty,0) * P 的构造将适用于任何有效的投影矩阵P',无论它是透视还是正交变换。在正交情况下,这样做非常清楚。在透视的情况下,这实际上修改了视野,也将视锥体转换为非对称视角。

如果要将图片平铺为Pm段的网格。很明显,nsx=m。正如我使用sy=n订单(按选择),S * T在比例尺之前应用,因此对于每个图块,T只是将图块中心移动到新图块的向量中心(将是起源)。由于NDC空间宽2个单位且高,对于图块(tx,ty),转换为

x,y