Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Metal Shader with SceneKit SCNProgram

I'm looking for just a working Metal shader that works in SceneKit with SCNProgram.

Can someone show me the correct method declarations/how to hook this up?

let program = SCNProgram()
program.vertexFunctionName = "myVertex"
program.fragmentFunctionName = "myFragment"
material.program = program

and then the shader

//MyShader.metal

vertex something myVertex(something)
{
    return something;
}

fragment float4 myFragment(something)
{
    return something
}

I'm just looking for the most basic example please.

like image 851
Chris Avatar asked Jun 08 '16 09:06

Chris


People also ask

Does SceneKit use metal?

It's a low-level framework. Metal is implemented everywhere – in RealityKit, SceneKit, ARKit, CoreML, Vision, AVFoundation, etc.

What shader language does metal use?

The Metal Shading Language is a C++11-style programming language normally used for writing Metal performance shaders to run on the GPU.


2 Answers

@lock's answer above is great, so I wanted to expand on it by providing an example of texturing, as OP requested in the comments.

Here's how you'd configure your material to make use of the shaders and wire up the custom texture:

let program = SCNProgram()
program.fragmentFunctionName = "myFragment"
program.vertexFunctionName = "myVertex"

material.program = program

let image = UIImage(named: "diffuse")!
let imageProperty = SCNMaterialProperty(contents: image)
// The name you supply here should match the texture parameter name in the fragment shader
material.setValue(imageProperty, forKey: "diffuseTexture")

and here are the modified shaders that sample from the texture:

#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) ]];
    float2 texCoords [[ attribute(SCNVertexSemanticTexcoord0) ]];
} MyVertexInput;

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

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);
    vert.texCoords = in.texCoords;

    return vert;
}

fragment half4 myFragment(SimpleVertex in [[stage_in]],
                          texture2d<float, access::sample> diffuseTexture [[texture(0)]])
{
    constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat);
    float4 color = diffuseTexture.sample(sampler2d, in.texCoords);
    return half4(color);
}
like image 76
warrenm Avatar answered Sep 20 '22 23:09

warrenm


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...

like image 44
lock Avatar answered Sep 18 '22 23:09

lock