Search code examples
sprite-kitglslshaderfragment-shader

Why is the texture created by this fragment shader one solid color when it should have a multicolored design pattern with waves running through it?


I have an OpenGL fragment shader .fsh file with the following code

constant float M_PI  = 3.141592653589793;
constant float M_2PI =  6.283185307179586;

constant vec3 c1a = vec3(0.0, 0.0, 0.0);
constant vec3 c1b = vec3(0.9, 0.0, 0.4);
constant vec3 c2a = vec3(0.0, 0.5, 0.9);
constant vec3 c2b = vec3(0.0, 0.0, 0.0);

void main() {
    vec2 point = (0.5 * u_sprite_size - gl_FragCoord.xy) / u_sprite_size;
    float angle = atan(point.y, point.x);
    float turn = (angle + M_PI) / M_2PI;
    float radius = sqrt(point.x * point.x + point.y * point.y);
    
    float sine_kf = 19.0;
    float ka_wave_rate = 0.94;
    float ka_wave = sin(ka_wave_rate * u_time);
    float sine_ka = 0.35 * ka_wave;
    float sine2_ka = 0.47 * sin(0.87 * u_time);
    float turn_t = turn + -0.0 * u_time + sine_ka * sin(sine_kf * radius) + sine2_ka * sin(8.0 * angle);
    bool turn_bit = mod(10.0 * turn_t, 2.0) < 1.0;
    
    float blend_k = pow((ka_wave + 1.0) * 0.5, 1.0);
    vec3 c;
    if(turn_bit) {
        c = blend_k * c1a + (1.0 -blend_k) * c1b;
    } else {
        c = blend_k * c2a + (1.0 -blend_k) * c2b;
    }
    c *= 1.0 + 1.0 * radius;
    
    gl_FragColor = vec4(c, 1.0);
}

The problem is it isn't displaying or returning the expected appearance

Here is an example of what is happening:image of the shader being applied to doors in a project

However the expected result of the preceeding code is the following, this is what i expect to happen: image of what the applied shader is intended to look like

to add more context, here is how the objects are initialized in SpriteKit/Swift

override func didMove(to view: SKView) {
    doorShader = SKShader(fileNamed: "shader.fsh")
    leftDoor = SKSpriteNode(imageNamed: "wrong_door")
    leftDoor.shader = doorShader //<-- shader is non-null at assignment
    addChild(leftDoor)
}

Solution

  • Since your shader outputs the cyan color present in the door pattern, it looks like it is executed.

    You are either missing the bit where you supply the u_sprite_size uniform to the shader, or you pass it as (0,0), so that the first line vec2 point = ... results in a wrong value for all fragments.

    (for testing I converted the shader to Metal and tried it, it correctly generates the pattern, but only if you pass u_sprite_size correctly)

    you need to do something like this:

    let u_sprite_size = SKUniform(name: "u_sprite_size", float: 256.0);
    let shader = SKShader(source: "...", uniforms: [u_sprite_size]);