I'm attempting to see what shaders look like in Interface Builder using sprite kit, and would like to use some of the shaders at ShaderToy. To do it, I created a "shader.fsh" file, a scene file, and added a color sprite to the scene, giving it a custom shader (shader.fsh)

While very basic shaders seem to work:

void main() {
gl_FragColor = vec4(0.0,1.0,0.0,1.0);
}

Any attempt I make to convert shaders from ShaderToy cause Xcode to freeze up (spinning color ball) as soon as the attempt is made to render them.

Replacing the iXxxxx variables (iGlobalTime, iResolution) and fragCoord variables with their related variables (based on the suggestions here)

Replacing some of the variables (iGlobalTime)...

While changing mainImage to main() and swapping out the variables got it to work without error in TinyShading realtime tester app - the outcome is always the same in Xcode (spinning ball, freeze). Any advice here would be helpful as there is a surprisingly small amount of information currently available on the topic.

@salocinx - I'd given up on it. Are you having the same issues?
– BadPirateJun 21 '16 at 21:09

1

Not exactly the same issues... I tried to compile this one: shadertoy.com/view/MtB3zW as you suggested and I also read the linked pages. I also replaced every unknown field with corresponding counterparts and also changed main's signature accordingly. But I receive some "non-const reference cannot bind to vector element" errors. X-Code did not hang so far with simple shaders, but the shader matrix functions seem to be implemented differently than those of the WebGL shader language... Apple did it different than the rest of the world - once more ... ;-)
– salocinxJun 21 '16 at 23:28

2 Answers
2

I managed to get this working in SpriteKit using SKShader. I've been able to render every shader from ShaderToy that I've attempted so far. The only exception is that you must remove any code using iMouse, since there is no mouse in iOS. I did the following...

1) Change the mainImage function declaration in the ShaderToy to...

void main(void) {
...
}

The ShaderToy mainImage function has an input named fragCoord. In iOS, this is globally available as gl_FragCoord, so your main function no longer needs any inputs.

2) Do a replace all to change the following from their ShaderToy names to their iOS names...

fragCoord becomes gl_FragCoord

fragColor becomes gl_FragColor

iGlobalTime becomes u_time

Note: There are more that I haven't encountered yet. I'll update as I do

3) Providing iResolution is slightly more involved...

iResolution is the viewport size (in pixels), which translates to the sprite size in SpriteKit. This used to be available as u_sprite_size in iOS, but has been removed. Luckily, Apple provides a nice example of how to inject it into your shader using uniforms in their SKShader documentation.

However, as stated in Shader Inputs section of ShaderToy, the type of iResolution is vec3 (x, y and z) as opposed to u_sprite_size, which is vec2 (x and y). I am yet to see a single ShaderToy that uses the z value of iResolution. So, we can simply use a z value of zero. I modified the example in the Apple documentation to provide my shader an iResolution of type vec3 like so...

Play with Item 1: to increase the number of stars in the sky the smaller the number the more stars I like the number to be around 50 not too dense
Item 2: changes the randomness or how close together the stars will appear 1 = none, 0.1 = side by side around 0.75 gives a nice feel.

Item 3 is where most of the magic happens this is the size and pulse of the stars.

float t = 0.9

Changing 0.9, will increase the initial star sign up or down a nice value is 1.4 not too big not too small.

float t = 0.9 + 0.2

Changing the second value in this equation 0.2, will increase the pulse effect width of the stars proportionally to the original size I like with 1.4 a value of 1.2.

To add the shader to your swift project add a sprite to the scene the size of the screen then add the shader like this: