An object that allows nodes to be rendered or filtered with a custom OpenGL ES fragment shader.
- iOS 8.0+
- macOS 10.10+
- tvOS 9.0+
- watchOS 2.0+
SKShader object holds a custom OpenGL ES fragment shader. Shader objects are used to customize the drawing behavior of many different kinds of nodes in SpriteKit.
To use a custom shader, create an
SKShader object and provide the source for the custom fragment shader. If your shader needs to provide uniform state to the shader, create one or more
SKUniform objects and associate them with the shader object. If your shader needs to provide per-node state to the shader, create one or more
SKAttribute objects and associate them with the relevant nodes. Then, assign the shader object to the
shader property of any sprites that need the custom behavior.
Compiling a shader and the uniform data associated with it can be expensive. Because of this, you should:
Initialize shader objects when your game launches, not while the game is running.
Avoid changing the shader’s source or changing the list of uniforms or attributes while your game is running. Either of these things recompiles the shader.
Share shader objects whenever possible. If multiple sprites need the same behavior, create one shader object and associate it with every sprite that needs that behavior. Do not create a separate shader for each sprite.
Creating a Custom Fragment Shader
Your fragment shader should be written in the OpenGL ES 2.0 shading language. SpriteKit automatically does the necessary work to make sure this shader compiles correctly in both iOS and macOS. The shader object compiles your shader by appending the source code you provide to a preamble created by SpriteKit. This preamble declares all of the standard SpriteKit variables and functions, including declarations for any uniforms you have associated with the shader object. Table 1 describes the SpriteKit symbols made available to your shader.
A sampler associated with the texture used to render the node.
The elapsed time in the simulation.
The coordinates used to access the texture. These are normalized so that the point (0.0,0.0) is in the bottom-left corner of the texture.
The premultiplied color value for the node being rendered.
A function that provides the default behavior used by SpriteKit.
Since the removal of
u_sprite_size, if your shader requires the size of the sprite in pixels, you are responsible for creating the necessary uniform or attribute. In the case where your existing shader code uses the deprecated
u_sprite_size and you don’t want to change it, the following code shows how you can define and set the value of of a
The preferred method would be to pass the size to the shader as an
SKAttribute. Using attributes rather than uniforms allows a single
SKShader to be shared between sprites with different sizes. The following code shows how you can pass the size of a sprite to a shader as an attribute.
Your shader should define a
main() function. This function must set the
gl_Frag variable to a color value to use in the blend stage; typically the color value you return in this variable should already be premultiplied by the fragment’s alpha value.
Listing 3 shows a very simple fragment shader that provides the default shading behavior.
Executing Shaders in Metal and OpenGL
On devices that support it, shader code in an
SKShader is implemented in Metal. On older devices, shader code is implemented in OpenGL. It's important to be mindful of this for debugging purposes because some issues may exhibit in one renderer but not the other. Listing 4 shows how you can display the active renderer in the bottom right hand corner of an
You can specify which renderer your device uses, for example, forcing a Metal enabled device to use OpenGL for debugging purposes, by adding a
Prefers key with a value of
true to your app's
Infoas shown in Figure 1.