Tutorial - How to update a shader for OpenGL ES 3.0

With the release of iOS 7 and the introduction of the iPad Air, the iPad mini with retina display and the iPhone 5S Apple has brought OpenGL ES 3.0 to their mobile devices. So if you want to target OpenGL ES 3.0 there are already a lot of new devices out there that do support it. Nonetheless, it is important to keep in mind that only the aforementioned devices are capable of OpenGL ES 3.0 and not all devices that run iOS 7.

OpenGL ES 3.0 is fully backward compatible with OpenGL ES 2.0 which means that all your shaders targeted at OpenGL ES 2.0 keep running just fine. To use the new features provided by OpenGL ES 3.0 you need to use the new OpenGL Shading Language (GLSL 3.00) in your shader. The update of the language includes among other things new language constructs that give you access to the new features of OpenGL ES 3.0 (e.g., 3D textures) but it also makes changes to already existing features (e.g., the lookup function for a texture2D). For a quick overview of all (new) language constructs you can take a look at the OpenGL ES 3.0 Reference Card and compare it to the OpenGL ES 2.0 Reference Card.

The following is a tutorial that shows you how to update a simple shader that uses a 2D texture lookup from OpenGL ES 2.0 / GLSL 1.00 to OpenGL ES 3.0 / GLSL 3.00. It is based on the head shader included in Shaderific. You can see a short video demonstrating the shader at YouTube and the shader program can be downloaded here. This example should help you to update your existing shaders and start to include new OpenGL ES 3.0 specific functionality.

Enable GLSL 3.00

The first thing you need to do is to enable the new shading language version in both shader files. This is done by adding the following compiler directive at the beginning of the files:

    #version 300 es

Doing so on a device that does not support OpenGL ES 3.0 does result in the compile error:

    version '300' is not supported in line ??

A shader without the compiler directive is treated as targeting OpenGL ES 2.0 / GLSL 1.00. If you’re not sure about the capabilities of your device just go the settings menu of Shaderific. You can find information on the OpenGL version and GPU of your device under the menu item device capabilites.

Change vertex attribute qualifier

In GLSL 1.00 the attribute qualifier is used for per vertex input variables that store data like positions, normals or texture coordinates. In GLSL 3.00 these variables use the in qualifier.

OpenGL ES 2.0 / GLSL 1.00:

    attribute vec4 position;

OpenGL ES 3.0 / GLSL 3.00:

    in vec4 position;

Furthermore, there is another mandatory change regarding the naming of texture coordinates for shaders compiled with Shaderific. The default name for the attribute that holds texture coordinates for shaders using OpenGL ES 2.0 / GLSL 1.00 is defined by Shaderifc as follows:

    attribute vec2 texture;

In this specific case not only the attribute qualifier has to be changed to in but also the variable name has to be changed from texture to texCoord for OpenGL ES 3.0 / GLSL 3.00:

    in vec2 texCoord;

This is due to the fact that texture is now a reserved word in GLSL 3.00 that denotes the new texture lookup functions. The Shaderific-specific definition of the texture attribute and the newly introduced function name lead to a naming collision that was resolved with renaming the attribute.

Since the texture functions are named texture2D and textureCube in GLSL 1.00 there is no need to change the attribute name in shaders targeting OpenGL ES 2.0. Shaderific takes care of appropriately binding the texture coordinate data to the right variable depending on the GLSL version you are using in your shader.

Change qualifier varying

In GLSL 1.00 the varying qualifier is used to denote variables that hold data that is outputted by the vertex shader for each vertex. This can be a calculated color for each vertex as well as texture coordinates that are just output without any modification. The data is used by the graphics pipeline to interpolate values for each fragment and is provided to the fragment shader as input.

The definition of a varying in the vertex shader in OpenGL ES 2.0 / GLSL 1.00 looks as follows:

    varying vec2 textureCoordinate;

Since a varying is an output from the vertex shader's perspective the qualifier has to be changed to out in OpenGL ES 3.0 / GLSL 3.00:

    out vec2 textureCoordinate;

The corresponding definition of a varying in the fragment shader in OpenGL ES 2.0 / GLSL 1.00 looks the same as in the vertex shader:

    varying vec2 textureCoordinate;

Since a varying is an input from the fragments shader's perspective the qualifier has to be changed to in in OpenGL ES 3.0 / GLSL 3.00:

    in vec2 textureCoordinate;

This is all that has to be done regarding varyings.

Define the fragment color variable

In GLSL 1.00 there is a predefined output variable for the fragment color:

    mediump vec4 gl_FragColor;

This variable does not exist in GLSL 3.00 any more. For that reason the fragment shader has to define an appropriate variable for the color output:

    out vec4 fragmentColor;

The name of this variable is arbitrary as long as it does not collide with other variable definitions. An asignment to the variable has to be made in the fragment shader

Change texture lookup functions

The basic texture lookup functions in GLSL 1.00 are texture2D and textureCube to fetch texture data from a standard texture and a cubemap texture respectively:

    vec4 texture2D(sampler2D, vec2 coord);
    vec4 textureCube(samplerCube, vec3 coord;

These different functions do not longer exist in GLSL 3.00. They have been replaced by one function that covers both cases plus the new 3D texture variant by providing different input signatures:

    vec4 texture(sampler{2,3}D sampler, vec2 coord);
    vec4 texture(samplerCube sampler, vec3 coord);

After making all these changes you’re ready to go and your shader should look exactly the same beeing now compiled with GLSL 3.00. So it’s definetively time to add some new OpenGL ES 3.0 / GLSL 3.00 only features. An example of using a 3D noise texture in the fragment shader is part of the example shaders provided by Shaderific.