I have an app developed as a SceneKit AR app. It has been fine for a long time but in XCode 13 the shader now fails to compile and results in the dreaded purple shader of death in-app.
It was modified from the simple mesh shader included in Apple's original ARKit example app.
#include <metal_stdlib>
#include <simd/simd.h>
#pragma body
#pragma transparent
uniform simd_float2 worldDimensions;
const float numTiles = 40.0;
const float tilePercent = 1.0 / numTiles;
const float edgeThickness = (1.0 / numTiles) * 0.05;
The first error I get now is the following:
[SceneKit] Error: FATAL ERROR : failed compiling shader:
Error Domain=MTLLibraryErrorDomain Code=3 "program_source:3179:50: error: unknown type name 'simd_float2'
, constant simd_float2& worldDimensions
If I change this from simd_float2
to float2
then the error explodes into the larger cascade of:
[SceneKit] Error: FATAL ERROR : failed compiling shader:
Error Domain=MTLLibraryErrorDomain Code=3 "program_source:992:1: error: use of class template 'uniform' requires template arguments
uniform float2 worldDimensions;
^
/System/Library/PrivateFrameworks/GPUCompiler.framework/Libraries/lib/clang/31001.325/include/metal/metal_uniform:16:8: note: template is declared here
struct uniform;
^
program_source:992:15: error: expected ';' after top level declarator
uniform float2 worldDimensions;
At this point I'm unable to see anything in the XCode changelogs etc. that offer any assistance as to what has changed in the spec. Any help gratefully appreciated.
The entire shader:
#include <metal_stdlib>
#include <simd/simd.h>
#pragma body
#pragma transparent
uniform float2 worldDimensions;
const float numTiles = 40.0;
const float tilePercent = 1.0 / numTiles;
const float edgeThickness = (1.0 / numTiles) * 0.05;
const simd_float2 cm10 = worldDimensions * 10.0;
float u = _surface.diffuseTexcoord.x * (1.0 + edgeThickness);
float v = _surface.diffuseTexcoord.y * (1.0 + edgeThickness);
const float2 thicknessMajor = float2(0.005, 0.005) / worldDimensions;
const float2 thicknessMinor = float2(0.005, 0.005) / worldDimensions;
bool onMeter = (fmod(u, 1.0 / worldDimensions.x) < thicknessMajor.x) || (fmod(v, 1.0 / worldDimensions.y) < thicknessMajor.y);
onMeter = onMeter || (u > 1.0 - thicknessMajor.x) || (v > 1.0 - thicknessMajor.y);
bool onCM = (fmod(u, 1.0 / cm10.x) < thicknessMinor.x) || (fmod(v, 1.0 / cm10.y) < thicknessMinor.y);
float4 defaultColor = _surface.diffuse;
float alpha = onMeter ? 0.7 : 0.1;
float4 outColor = float4(defaultColor.xyz, 1.0);
_surface.diffuse = float4(outColor.xyz, alpha);
_surface.transparent = float4(1.0, 1.0, 1.0, alpha);
if (!onCM && !onMeter)
discard_fragment();
Okay it looks like things have changed a bit, and a little reading of the original instructions at: https://developer.apple.com/documentation/scenekit/scnshadable#1654834 have cleared things up for me.
In short, my float2 should be described as:
#pragma arguments
float2 worldDimensions;
and after that the
#pragma body
#pragma transparent
The shader now works fine again.
Also, the SIMD files are presumably empty because they are deprecated in favor of just using the float2, float4 Metal types directly.