本文主要讲解如何在使用Metal渲染的时候,实现画面的旋转/翻转功能。
在讲旋转和翻转前先理解两个坐标系统,Metal的NDC (Normalized Device Coordinate) 坐标系统,和纹理坐标。
Metal的NDC是一个原点在中心,边长为2个单位长度的正方体:
对于2D视频渲染,NDC坐标系统就是原点在中心,边长为2个单位长度的正方形。
对于2D纹理来说,其坐标原点在左上角,是边长为1个单位长度的正方形:
我们要实现旋转和翻转有两种方法:
- 对纹理坐标进行变换
- 也可以在顶点函数中对NDC顶点坐标进行变换
从我们的上层需求来看,旋转都是绕画面中心点进行旋转,翻转也是绕画面居中的水平线(X轴)和垂直线(Y轴)进行翻转,如果对纹理进行操作,原点不在中心,虽然绕任意点做旋转,任意轴做翻转都能实现,但是计算会复杂很多。简化一些的话,我们可以先将坐标原点平移到(0.5, 0.5)的中心再基于原点做转换,最后再把坐标原点平移回去,最开始的一个版本就是这样实现的。
但NDC坐标系统,其原点本身就在中心,旋转翻转操作会方便很多,因此现在的实现中我们都是对NDC坐标(顶点坐标)进行操作。
翻转的实现
水平翻转就是绕NDC坐标系Y轴进行翻转,点(x, y, 1)绕Y转翻转后为(-x, y, 1),变换矩阵为:
matrix_float3x3 const GHorizontalFlipMatrix = {
(simd_float3){-1, 0, 0},
(simd_float3){0, 1, 0},
(simd_float3){0, 0, 1}
};
垂直翻转就是绕NDC坐标系X轴进行翻转,点(x, y, 1)绕X轴翻转后为(x, -y, 1),变换矩阵为:
matrix_float3x3 const GVerticalFlipMatrix = {
(simd_float3){1, 0, 0},
(simd_float3){0, -1, 0},
(simd_float3){0, 0, 1}
};
平面中一点绕另一点旋转
如图所示,a点绕o点旋转angle角度后(逆时针旋转)到b点的坐标?假设o点为原点,则有计算公式:
b.x = a.x*cos(angle) - a.y*sin(angle)
b.y = a.x*sin(angle) + a.y*cos(angle)
其中顺时针为负,逆时针为正,角度angle为弧度值。
在我们实现中只两个旋转角度,顺时针90度和逆时针90度,所有的旋转都是这两个旋转通过不断的组合最后叠加的结果。
这里需要注意的是,我们现在旋转的是NDC中的顶点坐标,因此与用户视角来说的的旋转图形(纹理)方向是相反的。
用户期望的画面顺时针旋转90度,也就是顶点坐标逆时针旋转90度(PI/2),cos(PI/2) = 0, sin(PI/2) = 1, 代入公式b点坐标为:
b.x = -a.y
b.y = a.x
变换矩阵如下:
matrix_float3x3 const GClockwiseMatrix = {
(simd_float3){0, 1, 0},
(simd_float3){-1, 0, 0},
(simd_float3){0, 0, 1}
};
同样用户期望的画面逆时针旋转90度,即顶点坐标顺时针旋转90度(-PI/2),cos(-PI/2) = 0, sin(-PI/2) = -1, 代入公式b点坐标为:
b.x = a.y
b.y = -a.x
变换矩阵如下:
matrix_float3x3 const GAntiClockwiseMatrix = {
(simd_float3){0, -1, 0},
(simd_float3){1, 0, 0},
(simd_float3){0, 0, 1}
};
matrix_float3x3 const GIdentityMatrix = {
(simd_float3){1, 0, 0},
(simd_float3){0, 1, 0},
(simd_float3){0, 0, 1}
}
每进行旋转/翻转操作后,就是在当前的变换矩阵基础(最开始是标准矩阵)上再乘上相应的翻转/旋转变换矩阵。
旋转存储
typedef union {
struct {
uint32_t m11:2;
uint32_t m12:2;
uint32_t m13:2;
uint32_t m21:2;
uint32_t m22:2;
uint32_t m23:2;
uint32_t m31:2;
uint32_t m32:2;
uint32_t m33:2;
uint32_t reserved:14;
} matrix;
uint32_t value;
} QLVCompactTranslateMatrix;
一些视频本身会有旋转/翻转的属性,如果产品需要对此情况要求进行自动纠正显示则如何处理?