Friday, February 20, 2015

Fragment Shaders with SpriteKit

Introduction

With the introduction of iOS8, SpriteKit received some awesome new features. One of those great new features was the support for fragment shaders (aka pixel shaders).

A shader allows one to manipulate the drawing behavior of how things are drawn onto the screen. Shaders runs at a GPU (Graphics Processing Unit) level and as a result it puts less load on the CPU (Central Processing Unit). This approach provides a great performance bump and makes for real interesting and creative results - don't just take my word for it, be inspired and go check out what you can do with shaders at www.shadertoy.com

SpriteKit's fragment shaders are based on the OpenGL ES 2.0 shader language which resembles a C-Style syntax. Fragment shaders in particular operates on a per-pixel basis, allowing one to manipulate pixels before they are presented to the viewer.

SpriteKit now provides us with a SKShader object that can be assigned to SKScene, SKSpriteNode, SKShapeNode, SKEmitterNode and SKEffectNode objects.

The official Apple SKShader Class Reference do highlight some good practices that one has to adhere to when dealing with SKShaders for more information, take a look under the references section.


Creating a fragment shader in XCode

Assuming that you've already created a basic SpriteKit project within XCode, you now need to create your very first shader by following these steps:
  • From within XCode.
  • Select the Utilities Panel on the right side.
  • Select the Show the File Template Library at the bottom of the Utilities Panel.
  • Drag and drop an empty document into your project archive on the left. This will open up a create file wizard.
  • Provide a filename for your shader and give it the extension of .fsh - use something  like MyFirstShader.fsh.
  • Copy the code from the MyFirstShader.fsh code example below into the shader file you just created.
In the example code above, we have a fragment shader in its simplest form. Just like most C applications the main() function serves as the main entry point for our shader code. The void indicates that the main function will not be providing a return value. The gl_FragColor represents the current fragment color that will be modified by the shader. Finally the vec4(r,g,b,a) function creates a four valued vector commonly used in shaders to represent a color in the form of RGBA values.

RGBA is short for Red, Green, Blue and Alpha. These values represents the primary colors used in computer graphics. Similar to how a painter would mix different colors of paint together on a color palette, these primary colors are mixed together at different strengths which ultimately can represent virtually any color from the visible color spectrum. Alpha is a special case and is used to control the transparency of the color. When dealing with shaders these color strengths range from 0.0 to 1.0.

Here's some RGBA color examples using vec4(r,g,b,a):
  • vec4(1.0, 1.0, 1.0, 1.0) will produce the color white with no transparency.
  • vec4(0.0, 0.0, 0.0, 0.5) will produce the color black with a 50% transparency.
  • vec4(1.0, 0.0, 0.0, 0.2) will produce the color red with a 20% transparency.
  • vec4(0.0, 0.0, 1.0, 0.0) will produce the color blue, but completely transparent.


Using fragment shaders in SpriteKit

Now that you've seen how easy it is to create a fragment shader, using the shader in SpriteKit is just as simple. Copy the code below into your SpriteKit scene.


In the example code above we're creating an instance of MyFirstShader by loading it from file. We then create a simple sprite and then we simply assign MyFirstShader to the sprite's shader property. Real simple, right? :)


References