OpenGL ES 高级进阶:3.0 Shader新特性

7,575 阅读2分钟

大家好,这是我的OpenGL ES 高级进阶系列文章,在我的github上有一个与本系列文章对应的项目,欢迎关注,链接:github.com/kenneycode/…

今天给大家介绍OpenGL ES 3.0shader中一些新关键字的特性,我们与OpenGL ES 2.0shader作对比来看看这些新特性。

我们先来看看OpenGL ES 2.0的两个普通的vertex shaderfragment shader

// vertex shader
precision mediump float;
attribute vec4 a_position;
attribute vec2 a_textureCoordinate;
varying vec2 v_textureCoordinate;
void main() {
    v_textureCoordinate = a_textureCoordinate;
    gl_Position = a_position;
}

// fragment shader
precision mediump float;
attribute vec4 fragColor;
uniform sampler2D s_texture;
varying vec2 v_textureCoordinate;
void main() {
    gl_FragColor = texture2D(s_texture, v_textureCoordinate);
}

OpenGL ES 2.0中,我们想往一个shader参数中传递数据时,先要获取对应的location,例如,我们给a_position传递数据:

val location = GLES20.glGetAttribLocation(programId, "a_position")

// 启动对应位置的参数
// Enable the parameter of the location
GLES20.glEnableVertexAttribArray(location)

// 指定a_Position所使用的顶点数据
// Specify the vertex data of a_Position
GLES20.glVertexAttribPointer(location, VERTEX_COMPONENT_COUNT, GLES20.GL_FLOAT, false, 0, buffer)

而在OpenGL ES 3.0中,我们可以直接在shader中指定参数的location,而不需要像在OpenGL ES 2.0中那样通过API获取参数的location,我们来将上面两个shader改写成OpenGL ES 3.0的版本:

// vertex shader
#version 300 es
precision mediump float;
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_textureCoordinate;
out vec2 v_textureCoordinate;
void main() {
    v_textureCoordinate = a_textureCoordinate;
    gl_Position = a_position;
}

// fragment shader
#version 300 es
precision mediump float;
layout(location = 0) out vec4 fragColor;
layout(location = 0) uniform sampler2D s_texture;
in vec2 v_textureCoordinate;
void main() {
    fragColor = texture(s_texture, v_textureCoordinate);
}

首先需要在开头处标明shader版本#version 300 es, 我们可以看到,我们给参数加上了layout(location = x)这样的语句,例如给a_position加上了layout(location = 0),即指定它的location0,于是我们可以直接通过操作0location的参数来操作a_position

val LOCATION_ATTRIBUTE_POSITION = 0

// 启动对应位置的参数,这里直接使用LOCATION_ATTRIBUTE_POSITION,而无需像OpenGL 2.0那样需要先获取参数的location
// Enable the parameter of the location. Here we can simply use LOCATION_ATTRIBUTE_POSITION, while in OpenGL 2.0 we have to query the location of the parameter
GLES30.glEnableVertexAttribArray(LOCATION_ATTRIBUTE_POSITION)

// 指定a_position所使用的顶点数据
// Specify the data of a_position
GLES30.glVertexAttribPointer(LOCATION_ATTRIBUTE_POSITION, VERTEX_COMPONENT_COUNT, GLES30.GL_FLOAT, false, 0, vertexDataBuffer)

另外,我们还能看到之前的attributevarying关键写变成了inout,这比较容易理解,在OpenGL ES 2.0中,attribute就是输入,varying就是从vertex shaderfragment shader的输出,还可以看到,内置的gl_FragColor被我们改写成了一个out变量来代码fragment shader的输出,为何需要这样呢?gl_FragColor代表输出不就够了吗?为什么需要自己指定?这是因为在OpenGL ES 3.0中支持**多渲染目标(MRT)**这个新特性,即可以在fragment shader中指定多个输出,这个特性我后面也会介绍,欢迎关注。

代码在我githubOpenGLESPro项目中,本文对应的是SampleShader,项目链接:github.com/kenneycode/…

感谢阅读!