SpriteKit shaders

In todays competitive market mobile games need to be highly “polished” in order to be successful. One important aspect of making a game “polished” is adding subtle little animations that make the visuals interesting and engaging, providing extra eye candy for the user. The game I am currently working on has an under water theme, with a cartoon style. I thought it would be great to have the backgrounds of the scene have a gentle under water distortion look, so that it looks more alive and less static. This is a perfect job for a custom shader.

Introducing SKShader

In iOS8, Apple introduced the SpriteKit SKShader class, which has support for OpenGL ES fragment shaders. Shaders are little programs that run on GPU. In the case of a fragment shader, the shader program gets called for each pixel rendered allowing you to customize the color drawn for the pixel. This can be used for creating interesting visual effects.

Shaders are written in a C-like language called GLSL. Creating a shader from scratch can be challenging if you have never done it before. Fortunately there are some good websites such as www.shadertoy.com where people share their shader implementations. The shaders found there can be a great learning resource, or a good starting point for your own shader. For the effect I was looking for I found a simple water shader at https://www.shadertoy.com/view/ldXGz7.

Note that a lot of the shaders on shadertoy.com are complex shaders written for open GL not open GL ES, and may be to complex for an iPhone. But some of the simple shaders are good candidates.

Using shaders from www.shadertoy.com

Shaders rely on predefined variables to get information about the current texture, pixel location, etc. These variable names differ from OpenGL and OpenGL ES, plus Apple has a few of its own predefined variables (the complete list is available here: SKShader Class Reference). Therefore the variable names in shaders found on shadertoy.com may need to be converted to their SKShader equivalent name. Here some of the common conversions I noticed:

www.shadertoy.com SKShader
GlobalTime u_time
iResolution u_sprite_size
fragCoord gl_FragCoord
fragColor gl_FragColor
iChannelX u_texture
fragCoord.xy / iResolution.xy v_tex_coord (Apple provides the normalized texture coordinates in v_tex_coord. You don't need to calculate it)

The original source for the wave shader I found on shadertoy.com is:

After converting the source to work with SKShader we get:

Applying shaders to SpriteKite images

Now that we have source for our shader we need to apply it to an image in our SpriteKit app. A shader can be added to any SKSpriteNode, SKShapeNode, SKEffectNode, SKEmitterNode, or SKScene. In the case of my game I want to apply the shader to a SKSpriteNode that displays the background underwater ocean scene, so that it has a wavy appearance. Apple has made it pretty easy to apply a shader:

  1. Create a text file with extension type “.fsh” that contains your shader source. Add that file to your xcode project. For my example I created a file called “wave.fsh” and added it to my project.
  2. Create an instance of a SKShader, specifying the file name of the shader source:
  3. Set the shader property of your SKSpriteNode to your SKShader:

Thats it. Now the SKSpriteNode backgroundImage will be rendered using the shader.

Here is the test example that I came up that shows the shader in action:

This scene has a few layers of nodes. First there is the background SKSpriteNode that contains most of the plants and the blue background. Next is an emitter node for the bubbles. On top of that is another SKSpriteNode that contains the rocks and sand. And on top of everything else is the fish. The background SKSpriteNode and the rock/sand SKSpriteNode both have the shader applied. The fish and the bubbles do not. All of this renders at 60.0fps on my iPad Air.

Hopefully this quick introduction to using shaders in SpriteKit ecourages you to add shaders to you SpriteKit app. I would be interested in seeing what shaders you come up with. Feel free to share your thoughts in the comments below.

This entry was posted in Game Programming and tagged , .

Leave a Reply

Your email address will not be published. Required fields are marked *