美文网首页LibGDX
LibGDX图形模块之着色器

LibGDX图形模块之着色器

作者: 天神Deity | 来源:发表于2017-09-24 23:33 被阅读15次

    如果你想使用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中完成的任何事情都可以轻松地移植到手机上运行。 去做个实验吧!

    相关文章

      网友评论

        本文标题:LibGDX图形模块之着色器

        本文链接:https://www.haomeiwen.com/subject/kqilextx.html