3
votes

I'm playing around and trying to implement Metal shader in SceneKit that will outline an object.

The idea is to draw an outline (or silhouette) similar to this image found in this blogpost (the blogpost doesn't contain any code):

silhouette

I'm new to SceneKit and Metal shaders so I'm able just to draw some geometry and write simple vertex or fragment shader. I'm curious how can I achieve this kind of effect? Is it done in multiple passes?

Cheers!

1
That's more than a silhouette. That looks more like some form of "edge detection", which is a term you can search for to find lots of info.Ken Thomases

1 Answers

10
votes

The basic idea here is to clone the "selected" node and its geometry, then use a custom vertex and fragment shader to "push" the geometry out along the vertex normals, drawing only the back faces of the cloned geometry with a solid color.

I wrote a small sample project to demonstrate this and posted it here.

The core Swift code looks like this:

let outlineProgram = SCNProgram()
outlineProgram.vertexFunctionName = "outline_vertex"
outlineProgram.fragmentFunctionName = "outline_fragment"

let outlineNode = duplicateNode(node)
scene.rootNode.addChildNode(outlineNode)
outlineNode.geometry?.firstMaterial?.program = outlineProgram
outlineNode.geometry?.firstMaterial?.cullMode = .front

The portion of the vertex shader responsible for pushing vertices along their normal looks like this:

const float extrusionMagnitude = 0.05;
float3 modelPosition = in.position + normalize(in.normal) * extrusionMagnitude;

From there, you just apply your typical model-view-projection matrix and return a flat color from the fragment shader.

Screenshot