Search code examples
c++swiftopenglglslscenekit

GLSL + Scenekit: Function definition not allowed


I'm trying to create a vertex shader in Scenekit. The shader is successfully added to the geometry of the SCNNode, however it displays purple because I get an error. I added the shaders to the geometry using SCNShaderModifiers and know that they are successfully found and attached.

The exact error messages I recieved is:

2020-08-31 21:26:53.977977-0700 Azure[69834:3664712] [SceneKit] Error: FATAL ERROR : failed compiling shader:
Error Domain=MTLLibraryErrorDomain Code=3 "Compilation failed: 

program_source:2901:97: error: function definition is not allowed here
float2 wavedx(float2 position, float2 direction, float speed, float frequency, float timeshift) {
                                                                                                ^
program_source:2908:49: error: function definition is not allowed here
float getwaves(float2 position, int iterations) {
                                                ^
" UserInfo={NSLocalizedDescription=Compilation failed: 

program_source:2901:97: error: function definition is not allowed here
float2 wavedx(float2 position, float2 direction, float speed, float frequency, float timeshift) {
                                                                                                ^
program_source:2908:49: error: function definition is not allowed here
float getwaves(float2 position, int iterations) {
                                                ^
}

However, when I am not using methods, the shader works perfectly. To test this I used a regular sinusoidal shader. The following example worked:

uniform float Amplitude = 0.1;
_geometry.position.z += sin(u_time + _geometry.position.x);

The code I was trying to get to work was this, which has functions:

float Time = u_time;
float DRAG_MULT = 0.048;

vec2 wavedx(vec2 position, vec2 direction, float speed, float frequency, float timeshift) {
    float x = dot(direction, position) * frequency + timeshift * speed;
    float wave = exp(sin(x) - 1.0);
    float dx = wave * cos(x);
    return vec2(wave, -dx);
}

float getwaves(vec2 position, int iterations) {
    
    float iter = 0.0;
    float phase = 6.0;
    float speed = 2.0;
    float weight = 1.0;
    float w = 0.0;
    float ws = 0.0;
    
    for(int i = 0; i < iterations; i++){
        vec2 p = vec2(sin(iter), cos(iter));
        vec2 res = wavedx(position, p, speed, phase, Time);
        position += normalize(p) * res.y * weight * DRAG_MULT;
        w += res.x * weight;
        iter += 12.0;
        ws += weight;
        weight = mix(weight, 0.0, 0.2);
        phase *= 1.18;
        speed *= 1.07;
    }
    return w / ws;
}

I have no idea what's going wrong here. These are all standalone GLSL snippets. Thanks!


Solution

  • I added the shaders to the geometry using SCNShaderModifiers and know that they are successfully found and attached.

    If you use SCNShaderModifiers, you also have to adhere to their documentation:

    1. Custom global functions. If your shader modifier benefits from factoring common code into functions, place their definitions here. If you include custom functions in your snippet, you must place the #pragma body directive between your function definitions and the main body of the snippet.