【发布时间】:2015-01-26 17:48:58
【问题描述】:
阅读datenwolf's 2011 answer concerning tile-based render setup in 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
计算每个图块的截锥体的算法是:
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 个拼接在一起) - 图像中的不连续性是由我认为的后期处理引起的,所以这是我可能不得不在某个时候处理的另一个问题。
【问题讨论】:
-
我没有检查你的实现有什么问题,但我认为 datenwolf 的解决方案有不必要的复杂性。如果您使用某些投影矩阵(无论是正交还是透视)渲染某些场景,则生成的平截头体将最终以 [-1,1]^3 NDC 空间的同质表示形式结束。因此,如果您想要渲染全屏的某个图块,只需在 x 和 y 中 预乘 一些缩放和平移来选择您喜欢的任何 2D 子矩形(这将具有与在平截头体中改变 FOV 和不对称效果相同)。
-
我认为 NDC 发生在齐次除法之后,即乘以投影矩阵之后,所以我不知道它会如何工作。无论如何,我尝试了 WxH 比例预乘和各种不同的翻译,但我无法让它工作。数学是错误的。
-
我的建议适用于剪辑空间。我只为截头锥的 [-1,1] 范围引入了 NDC。关键是在应用投影矩阵后应用简单的平移和缩放(这意味着 pre 按照默认的 GL 约定乘以它)来缩放和移动 [-1,1] 的某些子矩形到完整的 [-1,1] 范围将完全让您在完整的视口中获得图像的那部分。
-
例如,如果你想要通过应用矩阵
P获得的图像的左上角,你可以简单地使用P' = S(2,2,1) * T(0.5, -0.5, 0) * P(S是一个比例矩阵,@ 987654333@一个翻译)作为P的替代品(不管P是什么投影,在任何情况下都会起作用)。所有这些都假设您使用 GL 的常用矩阵约定,因此顶点v的变换为v'=M * v。如果你使用v' = M *v,后乘修改是正确的方法。 -
啊,我只花了 2 天时间就“搞定”了。请将此添加为答案,以便我可以给您一些积分。我将编辑我的问题以显示结果。