一、由最简单的GLSL ES程序开始

基于OpenGL ES 2.0 for Android。

自OpenGL ES 2.0开始,可编程着色器(Programmable Shader)开始逐渐替代1.x时代的部分固定功能图形API。它的出现使得OpenGL ES编程更加灵活和强大。OpenGL ES 2.0至今仍是最流行、最广泛、也是最可靠的移动端图形API。

最开始,可编程着色器采用一种混合开发的方式,这种方式存在着不直观、程序复杂的问题,对开发者很不友好。因此,混合开发方式并没有完全释放可编程着色器强大的可编程能量。后来,一种更加直观的GPU程序设计语言出现了,它就是GLSL(OpenGL Shading Language)。它的出现真正促进了OpenGL的发展和繁荣。

GLSL不仅仅是一门开发语言,它同样是一个GPU图形程序设计标准。它具有以下几种显而易见的好处:

  • 具有跨平台的特性,能够支持各种主流操作系统;
  • 所有支持OpenGL的GPU都可以支持GLSL开发的程序;
  • 不同的GPU厂商可以在统一标准下实现自己特定的优化。

程序的入口main函数

GLSL是基于C语言修改的编程语言。一个最简单的顶点着色器(Vertex Shader)是这样的:

void main() {
    gl_Position = vec4(0);
}

所有的GLSL实现的着色器都有一个类似于C语言入口函数的函数:void main(void),它同样是GLSL程序的入口函数。其中,参数类型void是可选的。

众所周知,一个类C程序从源代码到可执行文件通常需要经过编译和链接。GLSL也不例外,不过它的编译和链接方式从命令行/GUI变成了OpenGL ES的API。

一个编译并使用GLSL着色器程序的完整过程是这样的:

  1. 创建着色器对象(Shader Object),并获得对象引用
  2. 为着色器对象注入GLSL源代码,并编译GLSL源代码
  3. 创建一个GLSL程序对象(Program Object),并挂载着色器对象
  4. 链接GLSL程序
  5. 使用GLSL程序

在Android中,通常是这样一段代码。

//GLSL 顶点着色器源代码
val shaderCodeString = """
    void main() {
        glPosition = vec4(0);
    }
""".trimIndent()

//1,创建着色器对象(Shader Object),并获得对象引用
val shaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER)

//2,为着色器对象注入GLSL源代码,并编译GLSL源代码
GLES20.glShaderSource(shaderHandle, shaderCodeString)
GLES20.glCompileShader(shaderHandle)

//3,创建一个GLSL程序对象(Program Object),并挂载着色器对象
val program = GLES20.glCreateProgram()
GLES20.glAttachShader(program, shaderHandle)

//4,链接GLSL程序
GLES20.glLinkProgram(program)

//5,使用GLSL程序
GLES20.glUseProgram(program)

尽管这是一个完整的GLSL程序使用流程,但是这样做的结果是程序运行到第四步,链接GLSL程序(GLES20.glLinkProgram(program)),就已经出错了。

那么,如何获取到整个过程中的的错误信息呢?GLES方法glGetError()可以获得函数执行的错误代码,当然这种方式只能获得一些简单的信息。我们可以通过它定位到出错的函数,然后去查阅OpenGL ES官方文档了解函数的报错信息和正确用法。另外,glGetProgramInfoLog(int program)可以获取GLSL程序编译过程中较为详细的日志。例如,上面例子中,我们可以在步骤4执行后得到如下日志信息:

Link failed because of missing fragment shader.

日志显示,链接过程失败了,原因是缺少片元着色器。要知道OpenGL ES的着色器有两大类:顶点着色器、片元着色器(Fragment Shader)。这两类着色器必须成对且仅有一对出现在一个GLSL程序中才能够链接通过。一个正确的GLSL程序应当创建一个顶点着色器和一个片元着色器并挂载到同一个GLSL程序对象,之后再链接,使用。

下面看一看重新整理后的流程:

  1. 创建并编译一个顶点着色器对象
  2. 创建并编译一个片元着色器对象
  3. 创建一个GLSL程序对象,并挂载1,2中创建的着色器对象,然后链接GLSL程序对象
  4. 使用3中的GLSL程序对象
fun loadProgram(vertexCode: String, fragmentCode: String): Int  {
    //1. 创建并编译一个顶点着色器对象
    val vertexHandle = loadShader(GLES20.GL_VERTEX_SHADER, vertexCode)
    //2. 创建并编译一个片元着色器对象 
    val fragmentHandle =loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentCode)
    //3. 创建一个GLSL程序对象,并挂载1,2中创建的着色器对象,然后链接GLSL程序对象
    return linkProgram(vertexHandle, fragmentHandle)
}

fun loadShader(type: Int, code: String): Int {
    val shader = GLES20.glCreateShader(type)
    GLES20.glShaderSource(shader, code)
    GLES20.glCompileShader(shader)
    return shader
}

fun linkProgram(vertexShader: Int, fragmentShader: Int): Int {
    val program = GLES20.glCreateProgram()
    GLES20.glAttachShader(program, vertexShader)
    GLES20.glAttachShader(program, fragmentShader)
    GLES20.glLinkProgram(program)
    return program
}

虽然整个流程十分简单,但是新手由于对API不熟悉,仍可能出错。因此学会使用诸如glGetError()glGetProgramInfoLog(int)glGetShaderInfoLog(int)等调试工具很重要。一个好的习惯是开发阶段每一次API调用都打印日志,这能够帮助新手快速定位问题,节约时间。同时,尽量实现封装,减少重复代码出错率。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容