目录

一、Android中的OpenGL ES(v2.0)

EGL和OpenGL的关系

创建C++项目并导入OpenGL库

二、EGL创建流程

自定义SurfaceView并测试EGL环境

EGL线程创建

三、OpenGL渲染流程

加载流程

四、OpenGL坐标系

五、绘制纹理

OpenGL ES绘制纹理过程

六、矩阵

OpenGL空间坐标系


一、Android中的OpenGL ES(v2.0)

1、java层实现

2、java + C++实现

3、C++层实现

安卓 opengl设置镜像 安卓调用opengl_着色器

ES 其实应该算是封装了,不然怎么有一个libEGL.so ,再有libGLESv2.so 这些库呢?

EGL和OpenGL的关系

安卓 opengl设置镜像 安卓调用opengl_安卓 opengl设置镜像_02

注:上面的关系不仅限于Android平台,IOS、Windows等其他平台也是一样的!

如上图 EGL 就是 surface 和 openGL的桥梁。

创建C++项目并导入OpenGL库

1、可以使用NDK

安卓 opengl设置镜像 安卓调用opengl_EGL_03

2、在CMakeLists.txt中导入OpenGL 相关的库

导入方式:

安卓 opengl设置镜像 安卓调用opengl_安卓 opengl设置镜像_04

其作用:

 EGL          : EGL环境相关的库

GLESv2    :OpenGL ES 2.0的库

android      : ANativeWindow 相关库

二、EGL创建流程

1、得到默认的显示设备(就是窗口) -- eglGetDisplay

2、初始化默认显示设备 -- eglInitialize

3、设置显示设备的属性

4、从系统中获取对应属性的配置 -- eglChooseConfig

5、创建EglContext -- eglCreateContext

6、创建渲染的Surface -- eglCreateWindowSurface

7、绑定EglContext和Surface到显示设备中 -- eglMakeCurrent

8、刷新数据,显示渲染场景 -- eglSwapBuffers,这个函数的作用就是sureface里面的数据提交到显示设备上去。

int WlEglHelper::initEgl(EGLNativeWindowType window) {

    //1、得到默认的显示设备(就是窗口)
    mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if(mEglDisplay == EGL_NO_DISPLAY)
    {
        LOGE("eglGetDisplay error");
        return -1;
    }
    //2、初始化默认显示设备
    EGLint *version = new EGLint[2];
    if(!eglInitialize(mEglDisplay, &version[0], &version[1]))
    {
        LOGE("eglInitialize error");
        return -1;
    }

    //3、设置显示设备的属性
    const EGLint attribs[] = {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, 8,
            EGL_STENCIL_SIZE, 8,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_NONE
    };

    EGLint num_config;
    if(!eglChooseConfig(mEglDisplay, attribs, NULL, 1, &num_config))
    {
        LOGE("eglChooseConfig  error 1");
        return -1;
    }

    //4、从系统中获取对应属性的配置
    if(!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_config, &num_config))
    {
        LOGE("eglChooseConfig  error 2");
        return -1;
    }

    //5、创建EglContext
    int attrib_list[] = {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_NONE
    };

    mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list);

    if(mEglContext == EGL_NO_CONTEXT)
    {
        LOGE("eglCreateContext  error");
        return -1;
    }

    //6、创建渲染的Surface
    mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);
    if(mEglSurface == EGL_NO_SURFACE)
    {
        LOGE("eglCreateWindowSurface  error");
        return -1;
    }

    //7、绑定EglContext和Surface到显示设备中
    if(!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext))
    {
        LOGE("eglMakeCurrent  error");
        return -1;
    }
    LOGD("egl init success! ");
    return 0;
}

int WlEglHelper::swapBuffers() {

    if(mEglDisplay != EGL_NO_DISPLAY && mEglSurface != EGL_NO_SURFACE)
    {    //刷新数据,显示渲染场景 -- eglSwapBuffers
        if(eglSwapBuffers(mEglDisplay, mEglSurface))
        {
            return 0;
        }
    }
    return -1;
}

重要变量:

1、EGLDisplay  -- 显示设备  

2、EGLSurface – 后端显示的surface(缓冲)

3、EGLContext – egl上下文

4、EGLConfig – egl配置

自定义SurfaceView并测试EGL环境

1、继承SurfaceView

2、得到surface

3、实例化EGL环境

4、在surface上面绘制颜色(OpenGL清屏)

EGL线程创建

 

安卓 opengl设置镜像 安卓调用opengl_着色器_05

                                                                                                                                          

surfaceCreate 只会掉用一次,surfaceChange 会在改变窗口大小的时候被调用,surfaceDraw 每次绘制的时候会调用。

三、OpenGL渲染流程

安卓 opengl设置镜像 安卓调用opengl_安卓 opengl设置镜像_06

v_shader 、f_shader :是着色器语言,就是字符串哈。v_shader 定点着色器,图像要在屏幕绘制的一个坐标;f_shader 纹理着色器。

OpenGL加载shader

vertex/fragment->加载->编译->链接->program

vertex_shader:

attribute vec2 a_position;
void main(){ 
    gl_Position = a_position;
}

注: attribute 关键字 只能在vertex中使用 , vec4表示包含四个浮点型的数据类型

gl_Position 是OpenGL里面内置的一个变量。表示定点的坐标。

 

片元着色器或者叫做纹理着色器  fragment_shader:

precision mediump float;

void main(){
    gl_FragColor = vec4(1f,0f,0f,1f);//红、绿、蓝、α
}

注: lowp:低精度

       mediump:中等精度

      highp:高等精度

加载流程

1、创建shader(着色器:顶点或片元)     int shader =glCreateShader(shaderType);

2、加载shader源码并编译shader     glShaderSource(shader, source);     glCompileShader(shader);

3、创建一个渲染程序:     int program =glCreateProgram();

4、将着色器程序添加到渲染程序中:     glAttachShader(program, vertexShader);

5、链接源程序:     glLinkProgram(program);

四、OpenGL坐标系

安卓 opengl设置镜像 安卓调用opengl_着色器_07

以屏幕中心为原点

安卓 opengl设置镜像 安卓调用opengl_EGL_08

以屏幕左下角为原点

安卓 opengl设置镜像 安卓调用opengl_安卓 opengl设置镜像_09

绘制三角形

嵌入式的OpenGL 把绘制四边形去掉的,但是可以通过绘制三角形来绘制四边形。

绘制四边形可以用下面的定点:

float vertexs[] = {
        1,-1,
        1,1,
        -1,-1,
        -1,1

};

中间两个点一定是两个三角形的共工边,才能绘制出来四边形。

 

五、绘制纹理

了解纹理坐标:

安卓 opengl设置镜像 安卓调用opengl_EGL_10

纹理坐标系,和屏幕坐标系一样。不管图像的大小,都会映射到0--1 的范围内

安卓 opengl设置镜像 安卓调用opengl_显示设备_11

顶点着色器:vertex_shader.glsl

attribute vec4 v_Position;
attribute vec2 f_Position;
varying vec2 ft_Position;
void main() {
    ft_Position = f_Position;
    gl_Position = v_Position;
}
注: attribute 只能在vertex中使用
        varying 用于vertex和fragment之间传递值

纹理着色器:

precision mediump float;
varying vec2 ft_Position;
uniform sampler2D sTexture;
void main() {
    gl_FragColor=texture2D(sTexture, ft_Position);
}

注: uniform 用于在application中向vertex和fragment中传递值。

OpenGL ES绘制纹理过程

1、加载shader和生成program过程不变

2、创建和绑定纹理:     glGenTextures(1, &textureId);     glBindTexture(GL_TEXTURE_2D, textureid);

3、设置环绕和过滤方式 环绕(超出纹理坐标范围):(s==x t==y GL_REPEAT 重复)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);

安卓 opengl设置镜像 安卓调用opengl_着色器_12

过滤(纹理像素映射到坐标点):(缩小、放大:GL_LINEAR线性)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);

安卓 opengl设置镜像 安卓调用opengl_安卓 opengl设置镜像_13

4、设置图片(byte[] data)     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

5、绑定顶点坐标和纹理坐标

6、绘制图形

 

图像在缩放、平移的时候会用到矩阵,我们接下来学一下矩阵:

六、矩阵

初始化矩阵

单位矩阵:

vec4(x,y,z,w)

float matrix[16]={

1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1

}

参考资料: https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/

在定点着色器添加 矩阵变量

attribute vec4 v_Position;
attribute vec2 f_Position;
varying vec2 ft_Position;
uniform mat4 u_Matrix;
void main() {
    ft_Position = f_Position;
    gl_Position = v_Position * u_Matrix;
}

uniform mat4 u_Matrix;

使用

1、初始化     --  单位矩阵

2、操作

3、glUniformMatrix4fv(u_matrix, 1, GL_FALSE, matrix);

OpenGL空间坐标系

右手坐标系:手掌对着自己,大拇指指向+x,是指直线+y,-z就垂直穿过手心。

安卓 opengl设置镜像 安卓调用opengl_显示设备_14

旋转:,旋转一般都是沿着z轴旋转

安卓 opengl设置镜像 安卓调用opengl_显示设备_15

角度转弧度: 弧度 = 角度 * (PI / 180.0f)

缩放:

缩放的话,一般都是沿着x,y轴进行缩放。即S3可以不写

安卓 opengl设置镜像 安卓调用opengl_着色器_16

平移:

安卓 opengl设置镜像 安卓调用opengl_显示设备_17

投影矩阵-正交投影:

理解:比如我们的图片  宽:高   =  517:685  而手机的屏幕 宽:高 = 720 :1280  ,那么我们要把图片合理放在屏幕,避免失真,就需要正交投影。在视频4:3 16:9播放比价常用。

 

安卓 opengl设置镜像 安卓调用opengl_着色器_18

 

1、2D图像绘制

2、会把图像缩放到一个矩形区域内

3、控制图像长宽比不变

orthoM(float left, float right, float bottom, float top)

公式:

安卓 opengl设置镜像 安卓调用opengl_EGL_19

 

动态纹理的实现:

动态纹理一般用在视屏上面的水印等等

onDraw回调 中 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);