无论您使用固定或可编程着色器管道,常见的顶点管道都包含此矩阵乘法(自定义编码或幕后):
Projection * Modelview * Position
很多教程都会注意对象的旋转等项目应该进入Modelview
矩阵。
我创建了一个基于度数的标准旋转矩阵函数,然后将度数参数添加到90的正确倍数,以说明屏幕的自动旋转方向。的工作原理。
对于不同的屏幕尺寸(屏幕的不同像素宽度和高度),我还可以在其中考虑Scale
乘数,以便Modelview
矩阵可能包含很多这些。
但是我所确定的是一个更冗长的矩阵数学,因为我对这些东西不熟悉,我会很感激这是否很聪明的反馈。
除了缩放和旋转等对象操作外,我还为屏幕缩放和屏幕方向添加了独立的矩阵。我最终得到了这个:
Projection * ScreenRotation * ScreenScale * Translate * Rotate * Scale * Position
其中一些是可互换的顺序,例如我可以切换Rotate
和Scale
。
这为我提供了更精细的控制和代码隔离,因此我可以专注于对象的旋转,而无需同时考虑屏幕的方向,例如。
这是适当组织矩阵数学的常用或可接受的策略吗?它似乎工作得很好,但这种冗长有任何陷阱吗?
答案 0 :(得分: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
屏幕比例和旋转可以并且应该直接应用于Projection矩阵,不需要额外的矩阵。关键的理解是,您可以将每个线性变换链组合成单个矩阵。出于实际原因,您希望将屏幕像素方面缩放应用为链中的最后一步,并将屏幕旋转应用为链中的倒数第二步。
因此,您可以构建投影矩阵,而不是在着色器中,而是在显示例程框架设置代码中。假设您正在使用我的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
然后设置为投影矩阵均匀。