Rob*_*son 5 opengl matrix tile
在阅读了datenwolf 2011 年关于 OpenGL 中基于图块的渲染设置的答案后,我尝试实现他的解决方案。源图像如下所示(800 x 600)

生成的图像具有 2x2 图块,每个图块大小为 800 x 600,如下所示。

正如你所看到的,它们并不完全匹配,尽管我可以看到发生了一些隐约有趣的事情。我确信我在某个地方犯了一个基本错误,但我看不出来。
我正在执行 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
Run Code Online (Sandbox Code Playgroud)
计算每个图块的截锥体的算法是:
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);
Run Code Online (Sandbox Code Playgroud)
,其中 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;
}
Run Code Online (Sandbox Code Playgroud)
为了完整起见,我的 Matrx4x4 布局是:
struct
{
T m11, m12, m13, m14;
T m21, m22, m23, m24;
T m31, m32, m33, m34;
T m41, m42, m43, m44;
};
Run Code Online (Sandbox Code Playgroud)
有人能发现我的错误吗?
编辑:
所以德哈斯向我解释了这一点 - 一种更简单的方法是简单地缩放和平移投影矩阵。为了进行测试,我修改了翻译矩阵,放大了 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;
Run Code Online (Sandbox Code Playgroud)
生成的图像如下(将 4 个拼接在一起) - 我认为图像中的不连续性是由后期处理引起的,所以这是我在某个时候可能必须处理的另一个问题。

这不是问题的真正答案,但它可能是您在此处尝试解决问题的有用替代方法。在我看来,datenwolf 在回答您所指的stackoverflow 问题时的解决方案比实际需要的更加复杂。所以我在这里提出我的替代方案。
前言:我假设标准 OpenGL 矩阵约定,以便使用矩阵M进行顶点变换v'= M *v(就像固定功能管道所做的那样)。
当使用某些投影矩阵渲染场景时,您可以在应用投影矩阵后P通过应用缩放和变换操作来提取所述场景的任何轴对齐子矩形。
关键点是观察体积被定义为NDC空间中的[-1,1]^3立方体。剪辑空间(将P数据转换成的空间)只是该体积的同质表示。由于典型的4x4变换矩阵都在同质空间中工作,因此我们根本不需要关心w,只需定义变换,就好像我们在 NDC 空间中一样。
由于您只需要一些 2D 平铺,z因此应保持原样,并且只需要x和中的一些缩放和平移。y当将变换A和组合B成单个矩阵C时C=A*B,遵循上述约定,这会导致B首先应用,A最后应用(自 以来C*v == A*B*v == A*(B*v))。因此,要修改投影后的结果,我们必须预乘一些变换,P然后就完成了:
P'=S(sx,sy,1) * T(tx,ty,0) * P
Run Code Online (Sandbox Code Playgroud)
的构造P'将适用于任何有效的投影矩阵P,无论它是透视变换还是正交变换。在正交情况下,它的作用是非常清楚的。在透视情况下,这实际上既改变了视野,也将视锥体转变为不对称的。
当您想要将图像平铺到m时间n段网格中时。很明显,sx=m和sy=n。正如我确实使用的S * T顺序(根据选择),T在比例之前应用,因此对于每个图块,(tx,ty)只是将图块中心移动到新中心(这将是原点)的向量。由于 NDC 空间的宽度和高度均为 2 个单位,因此对于图块 而言x,y,变换为
tx= - (-1 + 2/(2*m) + (2/m) * x)
ty= - (-1 + 2/(2*n) + (2/n) * y)
// ^ ^ ^
// | | |
// | | +- size of of each tile in NDC space
// | |
// | +- half the size (as the center offset)
// |
// +- left/bottom border of NDC space
Run Code Online (Sandbox Code Playgroud)