基本计算
向量之间的计算有 点积
、叉积
。
矩阵之间的计算有加减
、数乘
、矩阵间乘法
。
矩阵的缩放
在 OpenGL 中,我们用 4 维向量来表示 3 维空间的数据,其中多出来的 w 维适用于透视投影的,因此在缩放中 w 依然为 1,因为在 3 维空间中变换 w 值没有意义。
位移
这里就表现出了 w 分量的意义,如果没有 w 分量,上面的向量
(x, y, z)
就不能位移,这个坐标就只能表示方向向量。
旋转
一个向量在三维空间中旋转,主要受两个条件影响:1. 旋转角度;2. 旋转轴。
上面我们只能沿着某个单位轴进行旋转,但是更方便的情况是,我们希望能够沿着任意方向轴旋转,这个有点复杂了,待研究。
组合变换
矩阵可以进行组合,达到用一个矩阵就进行多种变换的效果。假设有顶点 (x, y, z)
,我们将其放大两倍,然后位移 (1, 2, 3)
,那么我们需要一个位移矩阵和一个缩放矩阵来完成这个事。
矩阵相乘不满足交换律,因此参加计算的矩阵位置顺序很重要。当矩阵相乘时,最右边的矩阵是第一个与向量计算的矩阵,因此上图中的矩阵乘法我们应该从右往左读。即先放大两倍,然后平移的。如果我们交换顺序,就会变为先平移,再放大,那么平移的量就也会被放大。
OpenGL 中相关 API
-
Matrix#setIdentityM(float[] sm, int smOffset)
,创建一个单位矩阵。其中第一个参数是创建出来的单位矩阵存储的地方,第二个参数是单位矩阵在sm
数组中的偏移量。生成的结果按照列优先存储。 -
Matrix#translateM(float[] m, int mOffset, float x, float y, float z)
,第一个参数是需要变换的矩阵,第二个参数是偏移量。后面三个分别是(x, y, z)
三个方向的位移量。 -
Matrix#rotateM(float[] m, int smOffset, float a, float x, float y, float z)
,a
表示旋转的角度,角度制(0º ~ 360º)。x
,y
,z
分别代表旋转的轴,如果x = 0
,y = 0
,z = 1
代表围绕z
轴旋转。 -
Matrix#scaleM(float[] m, int smOffset, float x, float y, float z)
,在某个轴方向进行缩放。
代码中的写法
- 定义模型矩阵:
private float[] modelMatrix = new float[16];
这里使用长度为 16 的 float
数组,这是因为我们上面已经解释了,这里使用的矩阵都是 4x4 的矩阵。
- 在
onSurfaceChanged()
中初始化模型矩阵:
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
glViewport(0, 0, width, height);
setIdentityM(modelMatrix, 0);
Matrix.translateM(modelMatrix, 0, 0.5f, 0, 0); // 沿 x 轴平移 0.5 个单位
// Matrix.rotateM(modelMatrix, 0, 90, 0f, 0, 1); // 沿 z 轴旋转 90º
// Matrix.scaleM(modelMatrix, 0, 0.5f, 1.0f, 0); // x 轴缩放 0.5 倍,y轴不变。注意这里 y 轴如果写 0.0f,就会把 y 轴直接缩放没了(0 倍)
}
- 在 Shader 中使用矩阵进行变换:
attribute vec4 a_Position;
uniform mat4 u_Matrix;
void main(){
gl_Position = u_Matrix * a_Position;
}
申明一个 uniform mat4
的 4x4 矩阵 u_Matrix
,按照上面的教程,我们左乘这个矩阵。
- 在
onSurfaceCreated()
中获得u_Matrix
在 GPU
中的地址,然后在onDrawFrame()
中使用这个模型矩阵:
uMatrixLocation = glGetUniformLocation(program, U_MATRIX);
...
glUniformMatrix4fv(uMatrixLocation, 1, false, modelMatrix, 0);
上面 glUniformMatrix4fv()
中第一个参数表示数据所要传输到 GPU 中的地址,第二个参数表示需要加载的数据数量(会按照 u_Matrix
类型进行加载),第三个表示内存中数据是列优先(false
)还是行优先(true
),第四个参数表示要传输到 GPU 中的内存数据,第五个参数表示 modelMatrix
的偏移量。
https://github.com/fightyz/OpenGLPlayground checkout 1fecc7a6cb2ec61fe45ee7e781e6a3cc74dad0a8