LibGDX图形模块之着色器

如果你想使用OpenGL ES 2.0,你应该知道一些着色器的基础知识。 Libgdx附带了一个标准着色器,它将通过SpriteBatch处理渲染内容。 但是,如果要在Opengl ES 2.0中渲染网格,您将必须自己提供一个有效的着色器。 基本上在Opengl ES 2.0中,一切都是用着色器渲染的。 这就是为什么它被称为可编程管道。 在着色器中徘徊的想法可能会吓倒一些使用ES 2.0的人,但是值得仔细去阅读,因为着色器允许您做一些非常不可思议的事情。 而理解基础实际上是很直观的。

What are shaders?

OpenGL中的着色器是用C语言编写的小程序,称为GLSL,它在GPU上运行,并处理渲染事物所需的数据。 着色器可以简单地被视为GPU上的处理阶段。 它接收一组输入,您可以执行一组操作,最后将其重新发送出去。 想像这样的功能参数和返回值。 通常在OpenGL ES 2.0中呈现某些内容时,数据将首先通过顶点着色器发送,然后通过Fragment着色器发送。

顶点着色器

顾名思义,顶点着色器负责对顶点执行操作。 更具体地说,程序的每次执行都在一个顶点上运行。 这是一个重要的理解。 在顶点着色器中所做的一切只发生在一个顶点上。
这是一个简单的顶点着色器:

attribute vec4 a_position;

uniform mat4 u_projectionViewMatrix;

void main(){
    gl_Position =  u_projectionViewMatrix * a_position;
} 

那看起来不错,现在呢? 首先你有一个名为a_position的顶点属性。 这个属性是一个vec4,这意味着它是一个4维的向量。 在该样本中,它保存顶点的位置信息。
接下来你有u_projectionViewMatrix。 这是一个保存视图和投影变换数据的4x4矩阵。 如果这些术语对你来说模糊,我建议您阅读这些主题.理解它是非常有用的。
在main方法中,我们对顶点执行操作。 在这种情况下,着色器所有顶点位置与矩阵相乘并将其分配给gl_Position。 gl_Position是OpenGL中预定义的关键字,不能用于其他任何东西,只能通过处理的顶点。

Fragment shaders

片段着色器以与顶点着色器作用非常相似。 但是不是在顶点上处理它,而是为每个片段处理它一次。 为了简单起见,将片段看作一个像素。 现在您可能会注意到这是一个非常显着的区别。
假设三角形覆盖300像素的区域。 这个三角形的顶点着色器将被执行3次。 片段着色器虽然可执行300次。 所以当编写着色器时,请牢记这一点。 在片段着色器中所做的一切都将呈指数级增加!
这是一个非常基本的片段着色器:

void main(){
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

这个片段着色器将简单地渲染每个片段的颜色为纯红色。 gl_FragColor是另一个预定义的关键字。 它用于输出片段的最终颜色。 注意我们如何使用vec4(x,y,z,w)来定义着色器内的向量。 在这种情况下,矢量用于定义片段的颜色。

一个简单的Shader程序

现在我们对着色器的作用和工作原理有一个基本的了解,让我们在libgdx中创建一个Demo。 这是通过ShaderProgram类完成的。 ShaderProgram由顶点着色器和片段着色器组成。 您可以从文件加载,也可以传入字符串,并将着色器代码保存在java文件中。
这是着色器的设置:

String vertexShader = "attribute vec4 a_position;    \n" + 
                      "attribute vec4 a_color;\n" +
                      "attribute vec2 a_texCoord0;\n" + 
                      "uniform mat4 u_projTrans;\n" + 
                      "varying vec4 v_color;" + 
                      "varying vec2 v_texCoords;" + 
                      "void main()                  \n" + 
                      "{                            \n" + 
                      "   v_color = vec4(1, 1, 1, 1); \n" + 
                      "   v_texCoords = a_texCoord0; \n" + 
                      "   gl_Position =  u_projTrans * a_position;  \n"      + 
                      "}                            \n" ;
String fragmentShader = "#ifdef GL_ES\n" +
                        "precision mediump float;\n" + 
                        "#endif\n" + 
                        "varying vec4 v_color;\n" + 
                        "varying vec2 v_texCoords;\n" + 
                        "uniform sampler2D u_texture;\n" + 
                        "void main()                                  \n" + 
                        "{                                            \n" + 
                        "  gl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n" +
                        "}";

这是相当标准的使用位置属性,颜色属性和纹理坐标属性的着色器设置。

这是libgdx自己的库中的属性列表,用于那些希望轻松地将着色器附加到SpriteBatchs和libgdx的其他部分的库中:
a_position
a_normal
a_color
a_texCoord, requires a number at the end, i.e. a_texCoord0, a_texCoord1, etc...
a_tangent
a_binormal
要创建ShaderProgram,我们执行以下操作:

ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader);

您可以通过shader.isCompiled()确保着色器正确编译。 编译日志可以使用shader.getLog()发出。
我们还创建一个匹配的网格并加载纹理:

mesh = new Mesh(true, 4, 6, VertexAttribute.Position(), VertexAttribute.ColorUnpacked(), VertexAttribute.TexCoords(0));
mesh.setVertices(new float[] 
{-0.5f, -0.5f, 0, 1, 1, 1, 1, 0, 1,
0.5f, -0.5f, 0, 1, 1, 1, 1, 1, 1,
0.5f, 0.5f, 0, 1, 1, 1, 1, 1, 0,
-0.5f, 0.5f, 0, 1, 1, 1, 1, 0, 0});
mesh.setIndices(new short[] {0, 1, 2, 2, 3, 0});
texture = new Texture(Gdx.files.internal("data/bobrgb888-32x32.png"));

在render方法中,我们简单地调用shader.begin()并传递uniforms ,然后使用着色器渲染网格:

texture.bind();
shader.begin();
shader.setUniformMatrix("u_projTrans", matrix);
shader.setUniformi("u_texture", 0);
mesh.render(shader, GL20.GL_TRIANGLES);
shader.end();

就是这样!
OpenGL ES 2.0中的着色器的好处是,您可以使用一个巨大的着色器库。 在WebGL中完成的任何事情都可以轻松地移植到手机上运行。 去做个实验吧!

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

推荐阅读更多精彩内容