一、shader中为什么矩阵要反过来乘
首先我们写一个单位矩阵
1
0
0
0
0
1
0
0
0
0
1
0
0
0
0
1
\begin{matrix} 1 & 0 & 0 &0 \\ 0 & 1 & 0 &0\\ 0 & 0 & 1 &0\\ 0 & 0 & 0 &1 \end{matrix}
1000010000100001
其次我们写一个缩放2倍的缩放矩阵
2
0
0
0
0
2
0
0
0
0
2
0
0
0
0
1
\begin{matrix} 2 & 0 & 0 &0 \\ 0 & 2 & 0 &0\\ 0 & 0 & 2 &0\\ 0 & 0 & 0 &1 \end{matrix}
2000020000200001
再写一个平移(1,2,3)个单位的平移矩阵
1
0
0
1
0
1
0
2
0
0
1
3
0
0
0
1
\begin{matrix} 1 & 0 & 0 &1 \\ 0 & 1 & 0 &2\\ 0 & 0 & 1 &3\\ 0 & 0 & 0 &1 \end{matrix}
1000010000101231
因为我们的向量是,4行1列的,4X1矩阵。
x
y
z
1
\begin{matrix} x \\ y \\ z\\ 1 \end{matrix}
xyz1
根据我们的矩阵相乘的规则,向量只能放在最后面。
即 任意变换矩阵 乘以 向量矩阵。因此变换矩阵的相乘顺序也会有变化。
现在我们进行先缩放后平移的变换,观察两种矩阵相乘的顺序产生的结果
1、缩放矩阵 乘以 平移矩阵
再乘以我们的向量矩阵
可以看出,虽然我们的矩阵相乘是缩放矩阵 乘以 平移矩阵,但是结果却是先平移了(1,2,3)单位,然后再进行缩放2倍。与我们的需求不符合
2、平移矩阵 乘以 缩放矩阵
再乘以我们的向量矩阵
可以看出,这才是我们想要的结果,先缩放两倍再平移(1,2,3)单位
二、OpenGL矩阵列序储存,是什么意思?有什么影响?
1、是什么意思
首先我们简单了解一下GLSL里的数据类型
在这里插入图片描述
在矩阵变量中有mat2,mat3,mat4三种分析分别代表2x2矩阵,3x3矩阵,4x4矩阵。
在《OpenGL ES 2.0 Programming Guide》这本书中有如下介绍
在这里插入图片描述
矩阵是列优先的,
比如一个4x4矩阵
[
m
00
m
01
m
02
m
03
m
10
m
11
m
12
m
13
m
20
m
21
m
22
m
23
m
30
m
31
m
32
m
33
]
\left[ \begin{matrix} m00 & m01 & m02 &m03 \\ m10 & m11 & m12 &m13\\ m20 & m21 & m22 &m23\\ m30 & m31 & m32 &m33 \end{matrix} \right]
⎣⎢⎢⎡m00m10m20m30m01m11m21m31m02m12m22m32m03m13m23m33⎦⎥⎥⎤
在shader储存中就是
[
m
00
m
10
m
20
m
30
m
01
m
11
m
21
m
31
m
02
m
12
m
22
m
32
m
03
m
13
m
23
m
33
]
\left[ \begin{matrix} m00 & m10 & m20 &m30 \\ m01 & m11 & m21 &m31\\ m02 & m12 & m22 &m32\\ m03 & m13 & m23 &m33 \end{matrix} \right]
⎣⎢⎢⎡m00m01m02m03m10m11m12m13m20m21m22m23m30m31m32m33⎦⎥⎥⎤
矩阵是转置了的,但是矩阵的乘法却依旧是行*列(和行序一样)
2、有什么影响
2.1传参的影响
我们在传递矩阵数据给shader的时候一定要转置,如下
在OpenGL编程指南这本书中可以查到,正射投影矩阵如下
[
2
r
−
l
0
0
−
r
+
l
r
−
l
0
2
t
−
b
0
−
t
+
b
t
−
b
0
0
−
2
f
−
n
−
f
+
n
f
−
n
0
0
0
1
]
\left[ \begin{matrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l}\\ 0 &\frac{2}{t-b} &0 &-\frac{t+b}{t-b}\\ 0 &0 &-\frac{2}{f-n} &-\frac{f+n}{f-n}\\ 0 & 0 & 0 &1 \end{matrix} \right]
⎣⎢⎢⎡r−l20000t−b20000−f−n20−r−lr+l−t−bt+b−f−nf+n1⎦⎥⎥⎤
矩阵传入shader之前要转置,传入shader的时候一定要是列序!!!
在我代码中是这样写的
template <typename valType>
tmat4x4<valType> ortho
(
valType left,
valType right,
valType bottom,
valType top,
valType zNear,
valType zFar
)
{
tmat4x4<valType> res(1);//初始化为单位矩阵
res[0][0] = valType(2) / (right - left);
res[1][1] = valType(2) / (top - bottom);
res[2][2] = -valType(2) / (zFar - zNear);
res[0][3] = -(right + left) / (right - left);
res[1][3] = -(top + bottom) / (top - bottom);
res[2][3] = -(zFar + zNear) / (zFar - zNear);
return res;
}
CELL::matrix4 screenProj = CELL::ortho<float>(0, float(_width), 0, float(_height), -100.0f, 100);
matMVP = matMVP.transpose();//矩阵转置!!!
glUniformMatrix4fv(_shader._MVP, 1, GL_FALSE, matMVP.data());
void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
通过一致变量(uniform修饰的变量)引用将一致变量值传入渲染管线。
location : uniform的位置。
count : 需要加载数据的数组元素的数量或者需要修改的矩阵的数量。
transpose : 指明矩阵是列优先(column major)矩阵(GL_FALSE)还是行优先(row major)矩阵(GL_TRUE)。一定要用GL_FALSE;
value : 指向由count个元素的数组的指针
矩阵传入shader的时候一定要是列序!!!
2.2shader内部定义矩阵的影响
在OpenGL编程指南这本书中可以查到,平移矩阵如下
1
0
0
x
0
1
0
y
0
0
1
z
0
0
0
1
\begin{matrix} 1 & 0 & 0 &x \\ 0 & 1 & 0 &y\\ 0 & 0 & 1 &z\\ 0 & 0 & 0 &1 \end{matrix}
100001000010xyz1
但是在shder中我们去定义,由于列序储存我们就要定义成转置的矩阵
1
0
0
0
0
1
0
0
0
0
1
0
x
y
z
1
\begin{matrix} 1 & 0 & 0 &0 \\ 0 & 1 & 0 &0\\ 0 & 0 & 1 &0\\ x & y & z &1 \end{matrix}
100x010y001z0001
举例如下
precision lowp float;
uniform mat4 _MVP;
attribute vec2 _position;
attribute vec2 _uv;
attribute vec4 _color;
varying vec4 _outColor;
varying vec2 _outUV;
void main()
{
mat4 tran = mat4 ( 1.0, 0.0, 0.0, 0.0,
"0.0, 1.0, 0.0, 0,"
"0.0, 0.0, 1.0, 0.0,"
"0.0, -100.0,0.0, 1.0"//y轴下移100像素
);
vec4 pos = vec4(_position,0,1);
_outColor = _color;
_outUV = _uv;
gl_Position = _MVP * tran *pos ;
}
结果对比