OpenGL笔记

什么是OpenGL ES

OpenGL一种跨平台图形API,就是在不同软硬件平台中使用同样的接口绘制出同样效果。
OpenGL是给PC端使用的,移动端带不动,于是发展出OpenGl for Embedded System,简称OpenGL ES。它是OpenGL的一个子集。
不过Android还是专门为OpenGL提供了OpenGL包,并且提供了GLSurfaceView,GLU,GIUtilts等工具。
应用场景
游戏
视频播放器、视频编辑应用
相机、图片处理应用
对图像处理及时性要求比较高的应用
学习的版本
选2.0的版本,因为即使用户的手机是Android 4.3以上的版本,设备制造商也不一定实现了3.0API的接口。下图是官方统计的OpenGL版本支持情况。
开发方式
通过Android实现的Java接口调用OpenGL
C语言编写OpenGL代码,再通过JNI调用(跨平台开发时可以考虑)

基本概念:
OpenGL ES中,只提供了3种基本图形:点、线、三角形。而其他我们熟知的图形,都是基于这3种基本图形处理拼接合成的。

2.0版本渲染流程
OpenGL展示到屏幕上的流程
整体上,我将7个流程步骤拆解成了3大部分:

1、确定顶点的位置,通过这些顶点绘制出指定的图形
2、为图形上色,可以是纯色、渐变彩色或者是图片纹理
3、缓冲与展示:将上述的图形加载到帧缓冲区(FrameBuffer)中,再展示到屏幕上。
在这里插入图片描述
绘制三角形实例
在这里插入图片描述
基本概念
PipeLine:渲染管道, GPU 图形处理单元,相互独立,也就是渲染流程。
Shader:着色器、渲染器,用于描述如何绘制图形图像的具体环节。分为顶点着色器、片段着色器
GLSL : OpenGL编写着色器具体实现的编程语言,全称 OpenGL Shader Language

OpenGL顶点坐标系
在这里插入图片描述
与Android中的Canvas或者屏幕坐标体系不同,GL的坐标起始位置在view中心,(0,0)作为中心点,X坐标从左到右,Y坐标从下到上,在[-1,1]之间取值,再映射到view上。无论view是什么大小,什么形状,坐标范围都是不变的,都是[-1,1], 所以注意gl坐标系默认是方形,但是映射到view就不是了。然后超出[-1,1]范围的,将不会显示在view上。而如下图。
在这里插入图片描述

SurfaceView

SurfaceView和View主要区别是:
1、SurfaceView拥有自己的独立的绘图表面,并持有一个对应的Canvas,而View的绘图表面是宿主窗口的一部分,这是它名字的主要原因吧。原理上,SurfaceView会创建一个置于应用窗口之后的新窗口,所以它也可以看做一个比较特殊的窗口,SurfaceView相当于在Window上挖一个洞,它就是显示在这个洞里,其他的View是显示在Window上,所以View可以显示在 SurfaceView之上,也可以添加一些层在SurfaceView之上。不能放在下面? 好处:显然的一个好处是SurfaceView的窗口刷新的时候不需要重绘应用程序的整个窗口。
2、SurfaceView可以在非UI线程更新,它就可以主动更新界面,不用等到主线程调用再更新,进一步的,可以控制刷新频率,可以适用于对界面频繁刷新,对帧率要求高等场景。
3、SurfaceView底层有双缓存机制,绘图是不会出现闪烁问题。 闪烁问题是指反复局部刷屏带来的闪烁。游戏,视频等画面变化较频繁,前面还没有显示完,程序又请求重新绘制,这样屏幕就会不停地闪烁。

GLSurfaceView使用

先创建GLSurfaceView,再设置渲染器,通过setRender方法,setRender里面放入GLSurfaceView.Renderer类渲染绘制图像。

通过继承Renderer类里面三个方法,onSurfaceCreated初始化相关对象, onDrawFrame渲染绘制每一帧时调用到,onSurfaceChangedSurface尺寸改变时调用到。次创建GLSurfaceView时,会按顺序调用onSurfaceCreated、onSurfaceChanged、onDrawFrame这3个方法,然后每绘制一帧,都会不停地回调onDrawFrame方法。

然后GLSurfaceView负责触摸事件等逻辑的处理。

GLSurfaceView常用方法
setEGLContextClientVersion:设置OpenGL ES版本,2.0则设置2
onPause:暂停渲染,最好是在Activity、Fragment的onPause方法内调用,减少不必要的性能开销,避免不必要的崩溃
onResume:恢复渲染,用法类比onPause
setRenderMode:设置渲染模式 RENDERMODE_CONTINUOUSLY:不停地渲染 RENDERMODE_WHEN_DIRTY:只有调用了requestRender之后才会触发渲染回调onDrawFrame方法
requestRender: 请求渲染,由于是请求异步线程进行渲染,所以不是同步方法,调用后不会立刻就进行渲染。渲染会回调到Renderer接口的onDrawFrame方法。
queueEvent:插入一个Runnable任务到后台渲染线程上执行。相应的,渲染线程中可以通过Activity的runOnUIThread的方法来传递事件给主线程去执行

基本流程:
创建空gl程序、加载顶点和边代码并添加到程序中,连接和创建程序的可执行文件,启动程序,创建点的数据,获取点的输入句柄,通过点的句柄输入点数据并使能,执然后是边,然后绘制
其中有很多模板代码,理解然后封装调用即可。
详细见相关demo。

基础图形绘制API
/**

  • 使用顶点数据绘制图形
    */
    GLES20.glDrawArrays(int mode, int first, int count);
    基本上,很多场景下我们都使用这个方法来进行图形的绘制,这个方法通过调用GLES20.glVertexAttribPointer传递进去的顶点数据来绘制目标图形。相关参数作用如下

mode:绘制模式,控制绘制点、线段、三角形以及其具体的连接方式
first:从顶点数据读取数据的起点位置(以点作为单位,而非向量)
count:绘制的顶点数(以点作为单位,而非向量)

当前我们有个案例,按顺序有A、B、C、D、E、F一共6个点。
而mode的具体参数值如下:

参数 类型 作用 案例图形
GL_POINTS 点 绘制独立的点 A、B、C、D、E、F
GL_LINES 线段 每2个点构成一条线段 AB、CD、EF
GL_LINE_LOOP 线段 按顺序将所有的点连接起来,包括首位相连 AB、BC、CD、DE、EF、FA
GL_LINE_STRIP 线段 按顺序将所有的点连接起来,不包括首位相连 AB、BC、CD、ED、EF
GL_TRIANGLES 三角形 每3个点构成一个三角形 ABC、DEF
GL_TRIANGLE_STRIP 三角形 相邻3个点构成一个三角形,不包括首位两个点 ABC、BCD、CDE、DEF
GL_TRIANGLE_FAN 三角形 第一个点和之后所有相邻的2个点构成一个三角形 ABC、ACD、ADE、AEF

正交投影处理坐标系缩放问题:

OpenGL的坐标系长宽比是1:1,而实际View的长宽比是N:1,所以实际绘制出的y坐标会变成输入值的N倍,所以要在之前将y坐标处理成原来的1/N,Android中利用一个4阶矩阵对坐标进行缩放旋转等,进而实现y坐标缩放。
具体操作是:
设计的时候还是按照正常View尺寸设计,然后得到顶点坐标,然后创建一个缩放1/n的映射矩阵,在GLCL代码声明矩阵,让矩阵和坐标相乘,然后输入数据给矩阵,在surfaceview的onsizechange中输入矩阵数据,做变换, 其余部分保持不变即可。

原理上这种情况就相当于我们先缩小N倍,然后OpenGL内部放大N倍,等于不变。

渐变色

数据类型
attritude:一般用于各个顶点各不相同的量。如顶点位置、纹理坐标、法向量、颜色等等。
uniform:一般用于对于物体中所有顶点或者所有的片段都相同的量。比如光源位置、统一变换矩阵、颜色等。
varying:表示易变量,一般用于从顶点着色器传递到片段着色器的量。

varying变量在光栅化过程中计算每个片段具体颜色值,然后存储到片段着色器中。
glsl的代码如下
private static final String VERTEX_SHADER = “” +
“uniform mat4 u_Matrix;\n” +
“attribute vec4 a_Position;\n” +
// a_Color:从外部传递进来的每个顶点的颜色值
“attribute vec4 a_Color;\n” +
// v_Color:将每个顶点的颜色值传递给片段着色器
“varying vec4 v_Color;\n” +
“void main()\n” +
“{\n” +
" v_Color = a_Color;\n" +
" gl_PointSize = 30.0;\n" +
" gl_Position = u_Matrix * a_Position;\n" +
“}”;
private static final String FRAGMENT_SHADER = “” +
“precision mediump float;\n” +
// v_Color:从顶点着色器传递过来的颜色值
“varying vec4 v_Color;\n” +
“void main()\n” +
“{\n” +
" gl_FragColor = v_Color;\n" +
“}”;
然后将顶点数据传递给a_Position,将顶点颜色传递给a_Color,绘制和其它时候没有区别,直接绘制就能实现渐变色了。
这里是先把颜色传给顶点着色器,再传给顶点着色器中的varying量,最后再从顶点着色器中的varying量传递给片段着色器的varing量。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值