I'm in the early stages of making a SceneKit shader modifier (for the geometry entry point) that displaces a plane's geometry according to a height-map texture. The plan is to use it for creating terrain.
In iOS (edit: the iOS Simulator) the shader works as it should, but does print this warning to the console:
SceneKit: error, modifier without code is invalid

When building for OS X however, the shader gets a fatal error, and the terrain geometry just displays as a pink rectangle.
This is the geometry shader modifier:
uniform sampler2D displacementMap;
const float intensity = 7.5;
# pragma body
vec4 displace = texture2D(displacementMap, _geometry.texcoords[0]);
_geometry.position.z += displace.r * intensity;
And this is how the shader is connected to the geometry. terrainScene is the height map, it is placed in both the diffuse contents, and the custom displacementMap sampler value in the shader modifier:
//displacement shader
let mat = SCNMaterial()
mat.diffuse.contents = terrainScene
var displacementShader: String?
guard let path = NSBundle.mainBundle().pathForResource("DisplaceGeometry", ofType: "shader") else {return}
do {
displacementShader = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding)
} catch {
return
}
mat.shaderModifiers = [SCNShaderModifierEntryPointGeometry: displacementShader!]
let noiseProperty = SCNMaterialProperty(contents: terrainScene!)
mat.setValue(noiseProperty, forKey: "displacementMap")
//geometry
let plane = SCNPlane(width: 80, height: 80)
plane.widthSegmentCount = 40
plane.heightSegmentCount = 40
plane.materials = [mat]
This is the beginning of the OS X error message:
SceneKit: error, modifier without code is invalid
2016-06-11 10:58:32.054 EndlessTerrainOSX[16923:5292387] SceneKit: error, Invalid shader modifier : no code provided
2016-06-11 10:58:32.640 EndlessTerrainOSX[16923:5292387] FATAL ERROR : failed loading compiling shader:
And the end of the error:
UserInfo={NSLocalizedDescription=Compilation failed:
<program source>:343:8: error: global variables must have a constant address space qualifier
float4 displace = displacementMap.sample(displacementMapSampler, _geometry.texcoords[0]);
^
<program source>:343:19: error: use of undeclared identifier 'displacementMap'
float4 displace = displacementMap.sample(displacementMapSampler, _geometry.texcoords[0]);
^
<program source>:343:42: error: use of undeclared identifier 'displacementMapSampler'
float4 displace = displacementMap.sample(displacementMapSampler, _geometry.texcoords[0]);
^
<program source>:344:1: error: unknown type name '_geometry'
_geometry.position.z += displace.r * intensity;
^
<program source>:344:10: error: cannot use dot operator on a type
_geometry.position.z += displace.r * intensity;
^
}
2016-06-11 10:58:32.646 EndlessTerrainOSX[16923:5292387] Shaders without a vertex function are not allowed
Does anyone know why it displays on iOS, but fails on OS X?
I'd suggest it may not be a iOS vs OSX issue, but related to one device using OpenGL and the other Metal.
The code in the error message is Metal, indicating that SceneKit has translated your code from GLSL to Metal. In my experience this doesn't work 100% of the time. In your case the simplest solution may be to force the SCNView to use OpenGL by passing in options when it's created. I believe there's also a dropdown in Interface Builder for this too.
If you wish to keep using Metal, and there are reasons why you would, read on.
When a shader modifier fails to compile the entire contents of the shader is dumped to stdout, this really helps the debugging process. If you scroll up to line 343 you will find that SceneKit has included the float4 displace = displacementMap.sample(...); method before the vertex shader. Being defined outside a function means that it is a global variable, hence requiring the constant address space modifier, but this isn't what you wanted at all... In this instance the translation from GLSL to Metal hasn't worked as you expected.
I note you're missing the #pragma arguments directive, this should be included above the uniform definition (refer to "Writing a Shader Modifier Snippet"), it may help. In my experience I think you'll have a tough time passing a texture into a Metal based shader modifier. I tried, failed, and wrote a SCNProgram to do it instead. Suggest forcing OpenGL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With