0

无论您使用固定着色器管道还是可编程着色器管道,一个常见的顶点管道都包含此矩阵乘法(自定义编码或在幕后):

Projection * Modelview * Position

许多教程指出对象的旋转等项目应该进入Modelview矩阵。

我创建了一个基于度数的标准旋转矩阵函数,然后将 90 的适当倍数添加到度数参数中,以说明屏幕的自动旋转方向。作品。

对于不同的屏幕尺寸(屏幕的不同像素宽度和高度),我还可以在其中考虑一个Scale乘数,以便Modelview矩阵可以包含很多这些。

但是我决定的是一个更冗长的矩阵数学,因为我对这些东西不熟悉,我会很感激关于这是否聪明的反馈。

除了缩放和旋转等对象操作之外,我只需为屏幕尺寸缩放和屏幕方向添加独立矩阵。我最终得到了这个:

Projection * ScreenRotation * ScreenScale * Translate * Rotate * Scale * Position

我发现其中一些是可互换的顺序,例如Rotate并且Scale可以切换。

这为我提供了更精细的代码控制和隔离,例如,我可以只专注于对象的旋转,而无需同时考虑屏幕的方向。

这是适当组织矩阵数学的常见或可接受的策略吗?它似乎工作正常,但这种冗长是否有任何陷阱?

4

1 回答 1

3

这种冗长的主要问题是,如果在 GPU 上执行,它会浪费宝贵的计算周期。每个矩阵将作为统一提供,从而迫使 GPU 计算每个顶点,而它实际上是整个着色器中的常数。矩阵的好处是,单个矩阵可以容纳整个变换链,并且变换可以通过单个向量矩阵乘法来完成。

典型的段子

Projection · Modelview · Position

使用两个矩阵的原因在于,通常需要一个中间结果来Modelview · Position进行一些计算。从理论上讲,您可以将整个事情缩小到

ProjectionViewModel · Position

现在你提出这个矩阵表达式

投影 * ScreenRotation * ScreenScale * 平移 * 旋转 * 缩放 * 位置

呃……这整件事是不灵活的顶峰。你想要灵活性吗?这个东西是刚性的,如果你想对已经旋转的几何体应用一些不均匀的缩放怎么办。矩阵数学中的运算顺序很重要,您不能随意混合它们。假设您正在绘制一个球体

Rotate(45, 0, 0, 1) · Scale(1,2,1) · SphereVertex

看起来完全不同

Scale(1,2,1) · Rotate(45, 0, 0, 1) · SphereVertex

屏幕缩放和旋转可以而且应该直接应用于投影矩阵,不需要额外的矩阵。关键的理解是,您可以将每个线性变换链组合成一个矩阵。出于实际原因,您希望将屏幕像素纵横比应用作为链中的最后一步,并将屏幕旋转作为链中倒数第二步。

因此,您可以构建您的投影矩阵,而不是在着色器中,而是在您的显示例程框架设置代码中。假设你正在使用我的 linmath.h 它看起来像下面

mat4x4 projection;
mat4x4_set_identity(projection);
mat4x4_mul_scale_aniso(projection, …);
mat4x4_mul_rotate_Z(projection, …);
if(using_perspective)
    mat4x4_mul_frustum(projection, …);
else
    mat4x4_mul_ortho(projection, …);

然后将生成的矩阵projection设置为统一的投影矩阵。

于 2013-01-11T11:08:25.257 回答