New in ios8 is the SCNTechnique. It’s a way to get your models to pass through a custom shader program. This is an added layer on top of an objects filters. For instance, you’re able to apply a Gaussian blur to a single node in a SceneKit scene, then pass the scene to a fragment shader to change the color of the scene.
Getting started I’m setting up a new ios game.
This will create the scene view that SceneKit uses to render it’s 3d objects to. I’ve named the project SCNTechnique, this will make it obvious what this project is being used for.
I’m also enabling the local source control, I think git is required for this to work. If you don’t have this then I suggest you use it. If you break something it’s useful to know what you changed.
In the project we’ll want to set up a new dictionary that’s used to reference and define data going to and from the SCNTechnique rendering pass. I’m adding an iOS property list. Selecting add new file to the project to open this choose a template for your new file dialog:
Then I’m naming it firstPass, it’ll add the plist file extension for me. A property list is an XML file which Xcode allows us to edit with a more friendly interface.
The file appears with Root as the only section of data. We need to populate this with a few things to turn it into something that can be used by SCNTechnique. There are three entries [sequence, passes, symbols] where sequence is an Array and passes and symbols are both Dictionaries. These are added with the plus icon, and the type is changed with a popup menu under the type column.
sequence defines what pass is rendered when. To be honest, I think this means that you can define multiple passes in a single SCNTechnique, but so far this seems to be quite buggy and I can’t seem to get more than one pass working. Passes defines what parameters are passed to and from the shader programs. We’ll get to shader programs in a moment. symbols defines what name and type the data is passed from your code into the shaders.
So shader programs, I couldn’t find any appropriate templates to start with for these, so I ended up picking iOS/Other/Empty template. Which isn’t much of a template… But it is necessary to ensure that the project is aware of your new file. I added two files, a firstProgram.vsh and a firstProgram.fsh.
These live in the project like so.
What is the fsh and vsh for? the fsh means fragment shader and the vsh means vertex shader. Basically these are common OpenGL type shader programs. To make the connection between these shader programs and SCNTechnique in your SceneKit scene you’ll need to add them to the firstPass.plist so back to defining the technique’s property list.
In the Sequence array we need to name a rendering pass in the passes list. This seems to be the entry point for the technique. I’m naming it renderingPass.
This tells the Technique where to start. The item 0 of the sequence needs to point to an entry in the passes item. Then in passes we are require to have 4 entries.
draw program inputs and outputs, draw is a string program is another string and inputs and outputs are both dictionaries.
draw needs to be set to DRAW_QUAD which is used to draw data piped into the shader program, we also have DRAW_NODE or DRAW_SCENE. Each is used for specific reasons, but for now we’ll use DRAW_QUAD. The program refers to the .vsh and .fsh files we created and added to the project a moment ago. (note: the case and underscore are important) Don’t add the .vsh or .fsh to the program, Technique knows what to do with the name. I’ll always look for both files, if one or the other are missing the Technique will fail and your app will stop when looking for the program.
It seems rather necessary that one of the inputs is COLOR which goes into a colorSampler. COLOR is an openGL data source and colorSampler will be available in the shader program with data coming from COLOR. the a_position is a variable which points to a_position-symbol. We will need to add this to the symbols section of the technique’s plist. So we’ll add that in next.
In the a_position we add a_position-symbol and in symbols create a_position-symbol as a dictionary and add semantic vertex string to create a link between your SCNTechnique and the program. I’m not exactly sure why we don’t need to do this for colorSampler, but that’s how it works.
now we should add our code to both the .vsh and .fsh to make this work. In the firstProgram.fsh I’ve added the following code:
uniform sampler2D colorSampler;
varying vec2 uv;
vec4 color = texture2D(colorSampler, uv);
gl_FragColor = color;
This isn’t objective-c it’s c, and the colorSampler here is being piped in from the plist which SCNTechnique is using to tunnel data through. gl_fragColor is the final output to the fragment shader.
In the vsh we need to add in the following code:
attribute vec4 a_position;
varying vec2 uv;
uv = (a_position.xy + 1.0) * 0.5;
gl_Position = a_position;
The gl_Position is the final output for the vertices in the vertex shader. With these two parts of the firstProgram in place and the firstPass.plist setup we can now use it in the GameViewController.m
// configure the view
scnView.backgroundColor = [UIColor blackColor];
url = [[NSBundle mainBundle] URLForResource:@"firstPass" withExtension:@"plist"];
SCNTechnique *firstTechnique = [SCNTechnique techniqueWithDictionary:[NSDictionary dictionaryWithContentsOfURL:url]];
scnView.technique = firstTechnique;
In the template code we follow after the scnView is setup in the scene. Then we create a NSURL *url; to fill with url = [[NSBundle mainBundoe] URLForResource:@”firstPass” withExtension:@”plist”]; this makes a url that points to the firstPass.plist that we created with all of the data used to connect our shader program with the SCNTechnique. The we use SCNTechnique *firstTechnique to load in that dictionary. Finally we assign scnView.technique to the SCNTechnique we created from the plist.
Horray, we’re drawing using a SCNTechnique, it doesn’t look like anything interesting is happening, but it’s really going through our shader program and not the usual scene.view. We can prove this by editing the shader program. We can draw the technique as red by changing the fsh to the following code.
uniform sampler2D colorSampler;
varying vec2 uv;
gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0);
This sets the gl_fragColor to red. And now the iPad draws the image as all red. I’m still working on more interesting things to do with all of this but if you’re familiar with openGL then you’ll be able to do quite a lot. I’m not that familiar with openGL myself, so I’m learning what I can while I can. Hope this tutorial helps.