OpenGL(3) —— OpenGL 的矩阵变换

基本计算

向量之间的计算有 点积叉积
矩阵之间的计算有加减数乘矩阵间乘法

矩阵的缩放

矩阵缩放

OpenGL 中,我们用 4 维向量来表示 3 维空间的数据,其中多出来的 w 维适用于透视投影的,因此在缩放中 w 依然为 1,因为在 3 维空间中变换 w 值没有意义。

位移

位移矩阵

这里就表现出了 w 分量的意义,如果没有 w 分量,上面的向量 (x, y, z) 就不能位移,这个坐标就只能表示方向向量。

旋转

一个向量在三维空间中旋转,主要受两个条件影响:1. 旋转角度;2. 旋转轴。


沿 x 轴旋转
沿 y 轴旋转
沿 z 轴旋转

上面我们只能沿着某个单位轴进行旋转,但是更方便的情况是,我们希望能够沿着任意方向轴旋转,这个有点复杂了,待研究。

组合变换

矩阵可以进行组合,达到用一个矩阵就进行多种变换的效果。假设有顶点 (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),在某个轴方向进行缩放。

代码中的写法

  1. 定义模型矩阵:
private float[] modelMatrix = new float[16];

这里使用长度为 16 的 float 数组,这是因为我们上面已经解释了,这里使用的矩阵都是 4x4 的矩阵。

  1. 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 倍)
}
  1. Shader 中使用矩阵进行变换:
attribute vec4 a_Position;
uniform mat4 u_Matrix;

void main(){

    gl_Position = u_Matrix * a_Position;
}

申明一个 uniform mat4 的 4x4 矩阵 u_Matrix,按照上面的教程,我们左乘这个矩阵。

  1. onSurfaceCreated() 中获得 u_MatrixGPU
    中的地址,然后在 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容