设为首页 加入收藏

TOP

Opengl ES之矩阵变换(上)(一)
2023-07-23 13:29:32 】 浏览:55
Tags:Opengl

前言

说到矩阵变换,我们第一时间想到的就是大学时代的线性代数这些复杂的东西,突然有了一种令人从入门到放弃的念头,不慌,作为了一个应用层的CV工程师,
在实际应用中线性代数哪些复杂的计算根本不用我们自己去算,绝大部分情境下直接使用Matrix这个类或者glm这个库即可。

关于矩阵与向量的相关知识,矩阵的加减乘除等规则,这里就不展开细说,感兴趣的同学自行查阅线性代数即可,不过这些规则忘记了也没关系,反正有API可用。

我们知道在Opengl中有很多中坐标系,在Opengl中矩阵的一大作用就是将坐标从一个坐标系转换到另一个坐标系下,同时还可以通过矩阵实现一些形变的效果,
今天我们就使用矩阵的方式搭配Opengl ES实现平移、缩放、旋转等一些形变变换的效果。

通常来说在Opengl ES中的矩阵都是一个4X4的矩阵,也就是一个包含16个元素的一维数组。

下面以Matrix这个类介绍一下矩阵变换的一些常用方法。下面介绍的矩阵变换所参考的坐标系统都是一样的,均是下图这个:

单位矩阵

所谓的单位矩阵就是左上角到右下角对角线值均为1的矩阵,又成为单元矩阵。使用Matrix.setIdentityM方法可以将一个矩阵变为单位矩阵。

矩阵平移

矩阵平移所使用的方法是Matrix.translateM

需要注意的是在Opengl在顶点坐标的值是在-1到1之间,因此translateX的范围可以为-2到2。为什么呢?因为-1到1的距离是2,因此往最多可以往左移动2,同理,最多可以往右移动2。

矩阵旋转

矩阵旋转所使用的方法是Matrix.rotateM,其中第三个参数是表示选旋转的角度,后面的三个参数xyz代表的是绕那个轴旋转,绕那个轴旋转就把那个轴的参数设置成1,其他轴设置成0即可。

矩阵缩放

矩阵缩放所使用的方法是Matrix.scaleM

组合矩阵的写法

假如有以下形变步骤,先绕Z轴旋转90度,再向X轴平移0.5,最后X轴缩放0.9倍,那么最终这个形变矩阵该如何计算呢?是以下这个写法吗?

Matrix.rotateM(mvpMatrix, 0, 90, 0, 0, 1);
Matrix.translateM(mvpMatrix, 0, 0.5, 0, 0);
Matrix.scaleM(mvpMatrix, 0, 0.9, 1f, 0f);

不是的,组合矩阵的写法有一个规则,这个规则大家一定要记住:

在组合矩阵时,先进行缩放操作,然后是旋转,最后才是位移,但是写法需要反正写,也就是先写translateM,然后rotateM,最后scaleM

如果不这样写会发生什么呢?例如顺着写,先写scaleM,然后是rotateM,最后写translateM,测试时就会出现问题,旋转超过180度之后再移动,就会出现移动方向相反的情况。

因此以上例子正确的写法应该是这样子的:

Matrix.translateM(mvpMatrix, 0, 0.5, 0, 0);
Matrix.rotateM(mvpMatrix, 0, 90, 0, 0, 1);
Matrix.scaleM(mvpMatrix, 0, 0.9, 1f, 0f);

show me code

在Opengl ES中可以使用mat4来表示一个4X4的矩阵,我们将总的变换矩阵在CPU中计算好之后以uniform的形式传递到着色器中去。
在顶点着色器中将矩阵与顶点坐标相乘的结果作为新的顶点输出坐标即可完成矩阵变换。

以下是MatrixTransformOpengl.cpp的详细代码:

// 顶点着色器
static const char *ver = "#version 300 es\n"
                         "in vec4 aPosition;\n"
                         "in vec2 aTexCoord;\n"
                         "out vec2 TexCoord;\n"
                         "uniform mat4 mvpMatrix;\n"
                         "void main() {\n"
                         "  TexCoord = aTexCoord;\n"
                         "  gl_Position = mvpMatrix * aPosition;\n"
                         "}";

// 片元着色器
static const char *fragment = "#version 300 es\n"
                              "precision mediump float;\n"
                              "out vec4 FragColor;\n"
                              "in vec2 TexCoord;\n"
                              "uniform sampler2D ourTexture;\n"
                              "void main()\n"
                              "{\n"
                              "    FragColor = texture(ourTexture, TexCoord);\n"
                              "}";


// 使用绘制两个三角形组成一个矩形的形式(三角形带)
// 第一第二第三个点组成一个三角形,第二第三第四个点组成一个三角形
const static GLfloat VERTICES[] = {
        1.0f,-1.0f, // 右下
        1.0f,1.0f, // 右上
        -1.0f,-1.0f, // 左下
        -1.0f,1.0f // 左上
};

// 贴图纹理坐标(参考手机屏幕坐标系统,原点在左上角)
//由于对一个OpenGL纹理来说,它没有内在的方向性,因此我们可以使用不同的坐标把它定向到任何我们喜欢的方向上,然而大多数计算机图像都有一个默认的方向,它们通常被规定为y轴向下,X轴向右
const static GLfloat TEXTURE_COORD[] = {
        1.0f,1.0f, // 右下
        1.0f,0.0f, // 右上
        0.0f,1.0f, // 左下
        0.0f,0.0f // 左上
};

MatrixTransformOpengl::MatrixTransformOpengl():BaseOpengl() {
    initGlProgram(ver,fragment);
    positionHandle = glGetAttribLocation(program,"aPosition");
    textureHandle = glGetAttribLocation(program,"aTexCoord");
    textureSampler = glGetUniformLocation(program,"ourTexture");
    matrixHandle = glGetUniformLocation(program,"mvpMatrix");
}

MatrixTransformOpengl::~MatrixTransformOpengl() noexcept {
    LOGD("MatrixTransformOpengl析构函数");
}

void MatrixTransformOpengl::setMvpMatrix(float *mvp) {
    for (int i = 0; i < 16; ++i)
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇分析服务用多维度、多场景的用户.. 下一篇在线文本翻译能力新增14个直译模..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目