Using a Metal Shader in Scenekit

Metal shader in SceneKit to outline an object

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

SceneKit Metal shader using ``clip_distance``

The clip distances will be linearly interpolated across the primitive and the portion of the primitive with interpolated distances less than 0.0 will be clipped. (gl_ClipDistance)

For the frontier of clipped fragments to be exactly at z = 1.5 you need make sure that the interpolated clip distance is exactly at 0.0 when z = 1.5 and then positive or negative on each side.

out.clip_distance = (1.5 - in.position.z);

Metal Shader with SceneKit SCNProgram

I clipped out all the 'unnecessary' stuff, this is about as basic as it gets and pretty much what my first Metal shader was.

Next I'd start looking into wiring up the other vertex attributes (colour, normals), and maybe do some basic lighting calculations.

#include <metal_stdlib>
using namespace metal;
#include <SceneKit/scn_metal>

struct MyNodeBuffer {
float4x4 modelTransform;
float4x4 modelViewTransform;
float4x4 normalTransform;
float4x4 modelViewProjectionTransform;
};

typedef struct {
float3 position [[ attribute(SCNVertexSemanticPosition) ]];
} MyVertexInput;

struct SimpleVertex
{
float4 position [[position]];
};

vertex SimpleVertex myVertex(MyVertexInput in [[ stage_in ]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant MyNodeBuffer& scn_node [[buffer(1)]])
{
SimpleVertex vert;
vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);

return vert;
}

fragment half4 myFragment(SimpleVertex in [[stage_in]])
{
half4 color;
color = half4(1.0 ,0.0 ,0.0, 1.0);

return color;
}

Apologies for any typos, edited it down on my phone...

Using a Metal shader in SceneKit

AAPLCelShader.metal is a complete vertex/rastex/fragment implementation, which is not what shaderModifiers are: source code that will be injected into already-complete shaders.

Instead, you can create an SCNProgram, using the vertex and fragment functions in AAPLCelShader.metal. What's nice about Metal, versus GLSL, is that you can use names of Metal functions, instead of source code strings, which is easier to work with, and results in having the functions compiled before runtime, which GLSL doesn't support. (This is still not as good as it should be, where Swift would recognize the Metal functions as correctly-typed, refactorable, namespaced closures.) Of course, while GLSL SCNPrograms will be converted to Metal, for compatible hardware, Metal SCNPrograms will not be translated for obsolete devices.

As for mapping from SceneKit to the rastex's (incorrectly-named ColorInOut) members:

float4 position [[position]];
float shine;
float3 normal_cameraspace;
float3 eye_direction_cameraspace;
float3 light_direction_cameraspace;

…I unfortunately do not have an answer for you yet.

Metal shader stage_in

Based on this Metal Shading Language Specification:

clip_distance attribute data types should be either float or float[n], n - must be known at compile time. You should change your shader logic to the corresponding requirements.



Related Topics



Leave a reply



Submit