ARKit: Connecting a Shader to a Material.

I needed an image.

The following tutorial aims to reproduce the following video.

Ok.

So what exactly is happening here ?

We have an image tracking ARKit app, which presents a geometry at 0.1m.

The tutorials to do this are the following, I advise you to do them in the exact order they are presented.:

How to create an ARKit image recognition app that removes all objects on reset.

How to add an image to a plane on Maya.

How to make a cylinder in Maya

I advise you to do this ontop of the image of the EXACT dimensions.

How to add a Model to a Scene Node.

If you are looking to learn more about ARKit, this is the best I have written so far:

ARKit Theory: The Point Cloud, Image Recognition, AR Ready Images, True Scale, The Renderer and Nodes

Once you’re there, in the section where you add the children to the scene add this:

for child in scn!.rootNode.childNodes {
// MOVE YOUR CHILD 0.1M ABOVE THE TARGET
child.position = SCNVector3.init(0, 0.1, 0);
// CREATE A PROGRAM AND TIE IT TO A METAL SHADER FUNCTIONALITY
let program = SCNProgram()
program.fragmentFunctionName = "trianglequiltFragment"
program.vertexFunctionName = "trianglequiltVertex"
// CREATE A MATERIAL, ADD THE PROGRAM, AND ADD IT TO THE CHILD.
let shaderMaterial = SCNMaterial()
shaderMaterial.program = program;
shaderMaterial.diffuse.contents = UIColor.blue
shaderMaterial.locksAmbientWithDiffuse = true
child.geometry?.materials = [shaderMaterial];

node.addChildNode(child)
}

And then, create a shader.metal file in the same directory and add this code:

Thank you to my man Lock, for this piece of code.

#include <metal_stdlib>
using namespace metal;
#include <SceneKit/scn_metal>
struct myPlaneNodeBuffer {
float4x4 modelTransform;
float4x4 modelViewTransform;
float4x4 normalTransform;
float4x4 modelViewProjectionTransform;
float2x3 boundingBox;
};
typedef struct {
float3 position [[ attribute(SCNVertexSemanticPosition) ]];
float2 texCoords [[ attribute(SCNVertexSemanticTexcoord0) ]];
} VertexInput;
static float rand(float2 uv)
{
return fract(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453);
}
static float2 uv2tri(float2 uv)
{
float sx = uv.x - uv.y / 2;
float sxf = fract(sx);
float offs = step(fract(1 - uv.y), sxf);
return float2(floor(sx) * 2 + sxf + offs, uv.y);
}
struct SimpleVertexWithUV
{
float4 position [[position]];
float2 uv;
};
vertex SimpleVertexWithUV trianglequiltVertex(VertexInput in [[ stage_in ]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant myPlaneNodeBuffer& scn_node [[buffer(1)]])
{
SimpleVertexWithUV vert;
vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);
vert.uv = in.texCoords;
return vert;
}
fragment float4 trianglequiltFragment(SimpleVertexWithUV in [[stage_in]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant myPlaneNodeBuffer& scn_node [[buffer(1)]])
{
float4 fragColor;
float2 uv = in.uv*10;
float timer = scn_frame.time;
uv.y += timer;
float t = timer * 0.8;
float tc = floor(t);
float tp = smoothstep(0, 0.8, fract(t));
float2 r1 = float2(floor(uv.y), tc);
float2 r2 = float2(floor(uv.y), tc + 1);
float offs = mix(rand(r1), rand(r2), tp);
uv.x += offs * 8;
float2 p = uv2tri(uv);
float ph = rand(floor(p)) * 6.3 + p.y * 0.2;
float c = abs(sin(ph + timer));
fragColor = float4(c, c, c, 1);
return(fragColor);
}

Please leave any questions, in the comment section below.

Oscar