概念

OpenGL(Open Graphics Library)是一个跨平台的高性能3D渲染API,OpenGL ES 2.0(Open Graphics Library Embedded System 2.0)是它的嵌入式平台2.0版本。

简单实现

在Activity里面,创建一个GLSurfaceView对象,然后当作Activity的布局,并实现一个Renderer接口,塞给GLSurfaceView,并对其做简单的配置。

const val TAG = "HelloPoints"class HelloPoints : Activity() {    private lateinit var glSurfaceView: GLSurfaceView    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        title = "Play with Points"        glSurfaceView = GLSurfaceView(this)       //GLSurfaceView作为布局        setContentView(glSurfaceView)        glSurfaceView.setEGLContextClientVersion(2)//OpenGL 2.0版本        //Renderer接口设置进入        glSurfaceView.setRenderer(PointsRender)        glSurfaceView.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY    }    override fun onResume() {        super.onResume()        glSurfaceView.onResume()    }    override fun onPause() {        super.onPause()        glSurfaceView.onPause()    }    companion object PointsRender : GLSurfaceView.Renderer {    /**         * shader语言跟C语言很像,它有一个主函数,也叫void main(){}。         * gl_Position是一个内置变量,用于指定顶点,它是一个点,三维空间的点,所以用一个四维向量来赋值。         * vec4是四维向量的类型,vec4()是它的构造方法。等等,三维空间,不是(x, y, z)三个吗?为什么用         * *vec4层呢?         * 四维是叫做齐次坐标,它的几何意义仍是三维,对于2D的话,第四位永远传1.0就可以了。         * 这里,是指定原点(0, 0, 0)作为顶点,就是说想在原点位置画一个点。gl_PointSize是另外一个内置变量,用于指定点的大小。         *         * 这个shader就是想在原点画一个尺寸为20的点。         */        private const val VERTEX_SHADER =                "void main() {\n" +                        "gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" +                        "gl_PointSize = 20.0;\n" +                        "}\n"        /**         * gl_FragColor是fragment shader的内置变量,         * 用于指定当前顶点的颜色,四个分量(r, g, b, a)。         * 这里是想指定为红色,不透明。         */                        private const val FRAGMENT_SHADER =                "void main() {\n" +                        "gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" +                        "}\n"       private var mGLProgram: Int = -1        /**         * 所有的GL API的调用都要在GLSurfaceView.Renderer的三个方法里面来call,         * 就是方法的调用栈必须从这几个方法开始         */        //初始化操作        override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {            GLES20.glClearColor(1f, 0f, 0f, 1f)//把背景,或者叫作画布,画成黑色,不透明//编译和链接shader程序            val vsh = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER)            // 告诉OpenGL,这一坨字串里面是vertex shader的源码。            GLES20.glShaderSource(vsh, VERTEX_SHADER)             GLES20.glCompileShader(vsh) // 编译vertex shader            val fsh = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER)            GLES20.glShaderSource(fsh, FRAGMENT_SHADER)            GLES20.glCompileShader(fsh)            mGLProgram = GLES20.glCreateProgram() // 创建shader program句柄            GLES20.glAttachShader(mGLProgram, vsh) // 把vertex shader添加到program            GLES20.glAttachShader(mGLProgram, fsh) // 把fragment shader添加到program            // 做链接,可以理解为把两种shader进行融合,做好投入使用的最后准备工作            GLES20.glLinkProgram(mGLProgram) // 让OpenGL来验证一下我们的shader program,并获取验证的状态            GLES20.glValidateProgram(mGLProgram)             val status = IntArray(1)            GLES20.glGetProgramiv(mGLProgram, GLES20.GL_VALIDATE_STATUS, status, 0) // 获取验证的状态            Log.d(TAG, "validate shader program: " + GLES20.glGetProgramInfoLog(mGLProgram))        }        //surface发生改变时调用,通常是size发生变化        override fun onSurfaceChanged(p0: GL10?, p1: Int, p2: Int) {            GLES20.glViewport(0, 0, p1, p2) // 参数是left, top, width, height        }        //而此方法是用来绘制每帧的,所以每次刷新都会被调一次,所有的绘制都发生在这里。        override fun onDrawFrame(p0: GL10?) {        // 清除颜色缓冲区,因为我们要开始新一帧的绘制了,所以先清理,以免有脏数据。            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)              // 告诉OpenGL,使用在onSurfaceCreated里面准备好了的shader program来渲染            GLES20.glUseProgram(mGLProgram)            //开始渲染,发送渲染点的指令, 第二个参数是offset,第三个参数是点的个数。            //目前只有一个点,所以是1。            GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1)        }    }}

几点说明:

说明1
所有的GL API的调用都要在GLSurfaceView.Renderer的三个方法里面来调用,就是方法的调用栈必须从这几个方法开始。在其他地方调用是没有效果的:
onSurfaceCreated
onSurfaceChanged
onDrawFrame

说明2
OpenGL的坐标系是所谓的右手坐标系
Android——初识OpenGL ES 2.0_第1张图片
说明3:shader
GL ES 2.0把渲染相关的操作用一个专门的叫作着色语言的程序来表达,全名叫作OpenGL ES Shading language,它是一个编程语言,与C语言非常类似**,能够直接操作矩阵和向量,运行在GPU之上专门用于图形渲染**。它又分为两种,一个叫做顶点着色器(vertex shader),指定几何形状的顶点位置和大小,另一个叫做片元着色器(fragment shader),后者用于指定每个顶点的着色。每个GL程序必须要有一个vertex shader和一个fragment shader,且它们是相互对应的。(相互对应,意思是vertex shader必须要有一个fragment shader,反之亦然,但并不一定是一一对应)。当然,也是可以复用的,比如同一个vertex shader,可能会多个fragment shader来表达不同的着色方案。

说明4:坐标值和颜色值
坐标正常的取值范围都是-1到1,且是float类型。
颜色值是0到1,也是float类型,0是空(无的意思,比如黑色,或者全透明),1是有(全的意思,比如白色,或者不透明)。

说明5
Renderer实例,渲染模式(render mode)分为两种,一个是GLSurfaceView主动刷新(continuously),不停的回调Renderer的onDrawFrame,另外一种叫做被动刷新(when dirty),就是当请求刷新时才调一次onDrawFrame。

原文参考

更多相关文章

  1. Android 页面自动跳转方法(比如进入app的广告,通过Timer计时器,通过
  2. android开源代码编译方法
  3. Activity中那些需要重写的方法
  4. Android为什么会有65536的方法数量限制
  5. Android Studio ——Android 使用Pull方法解析XML文件的方法
  6. 记录关于Gradle : Build Running的解决方法
  7. Android 开机震动的调用位置以及打开关闭方法
  8. Android中计算text文字大小的几个方法

随机推荐

  1. android Camera照相机技术(一)
  2. (二) RIL 层分析
  3. 我的Android 4 学习系列
  4. Android EditView用法小结
  5. Android:AIDL简单使用
  6. Android 相机实例
  7. Android:(12)显示控件使用
  8. 互联网(腾讯)p7安卓架构师近十年核心资料免
  9. Java、Android中的回调使用 Java回调方法
  10. 【eoeAndroid社区索引】android源码开发