MysteryPancake MysteryPancake - 1 month ago 27
Swift Question

How to write OpenGL ES fragment shaders in XCode?

I'm trying to make my own shader to use as an SKShader for an SKSpriteNode, but I just don't know the proper way to do it. All I want is a way to write the shader code with autocompletion and to see the shader without having to wait ages for some huge program to compile it, but it seems to be more difficult than I thought.

I've already installed GLFW3 and a couple of other odd things since most tutorials suggest something like this for using OpenGL, but it seems to be more for OpenGL as a whole, rather than just one specific kind of shader.

TL;DR: Does anyone know a fast and simple way to write shaders to use as SKShaders in SpriteKit?

Answer

Use the SpriteKit Scene Editor in Xcode. When you associate a shader source file with a node in the inspector, the scene view immediately gives you a live preview of that shader in effect.

Then you can use Xcode's assistant editor pane to see and edit the source of the shader is associated with the currently selected node in the scene — complete with live preview of any animation in the shader (from the u_time input).

Xcode shader editing

That gets you syntax highlighting, but not autocomplete. Xcode's completion engine seems to be limited to its main compiler toolchain — getting it to support shaders in general is certainly a good thing to file a bug about.

Editing the shader source should update the live preview, but there seem to be at least some Xcode versions where you have to re-select the custom shader in the inspector for changes to take effect. (That's probably also worth filing a bug on...)


Shader code in the above example (courtesy Shadertoy via Endless Wave blog):

void main(void) {

    vec2 uv = v_tex_coord;

    uv.y += (cos((uv.y + (u_time * 0.04)) * 45.0) * 0.0019) +
    (cos((uv.y + (u_time * 0.5)) * 10.0) * 0.002);

    uv.x += (sin((uv.y + (u_time * 0.07)) * 15.0) * 0.0029) +
    (sin((uv.y + (u_time * 0.5)) * 15.0) * 0.002);

    gl_FragColor = texture2D(u_texture, uv);
}