Fun with SCNShadable

Posted on Friday, March 20, 2015 in iOS , Scene Kit , OpenGL 
by Eric Berna

Apple’s Scene Kit framework is a little under documented. I’ve been working with it trying to make a special effect by modifying the built in shaders for Scene Kit objects. Here are a few things I found out.

Scene Kit includes a SCNShadable protocol that defines the way to modify geometry and material objects with OpenGL Shading Language (GLSL) programs. One option is to totally replace the vertex and fragment shaders with an SCNProgram module. The other option is to insert snippets of code at specific points in the built in vertex and fragment shaders with shader modifiers.

I was having some difficulty understanding exactly what I could and could not do in these code snippets. I wanted to see the entire shader program, but I could not find these shaders in the documentation. I hope the reason Apple’s engineers have not documented this code is to leave themselves the option of changing it in the future. Fortunately Xcode is more than happy to show you this code; all you have to do is make a syntax error in your snippet. When the app fails to compile the shader it spews out the entire shader program to Xcode’s debug area console pane.

There are multiple versions of these shaders, depending upon how you setup a geometry or material. For example, changing the lighting mode for a material changes the lighting section of the fragment shader.

There are four named and fairly well documented insertion points for the shader snippets. These insertion points are within the shaders’ main() functions. Additionally, each snippet is analyzed for the existence of structures that should be inserted before the main() function definition. Apple documents how you can use the #pragma body directive to make your own function definitions. It also moves any uniform definitions to the declaration portion of the shader.

One of the four named insertion points, SCNShaderModifierEntryPointGeometry, results in code inserted into the vertex shader. The other three result in code inserted into the fragment shader. This means you can insert modifiers into both parts of the shader program.

For my project, I needed to pass some values from the vertex shader to the fragment shader. Apple’s documentation doesn’t mention using varying values, but after figuring out the above processing of shader modifiers I decided to just try adding them to the geometry and fragment entry points. It compiled and ran, and with some tests I made sure the varying values worked.

Fishy Thoughts:
"What's water?"