I've been trying to make a scene with scene kit in which an specified object is always in front of others, despite the fact that it's actually behind the other objects. A similar effect to this used in blender.
Apparently, blender uses GUI and a lot of math to transform otherwise 2D objects, but I need this effect in a SCNNode with a SCNGeometry, in other words, a 3D object currently locate in the scene.
I considered using category masks, but after reading Apple's documentation I've realized that doesn't work for the effect I'm looking for.
Does anyone know a way of doin this in SceneKit? Or better yet, is it even possible to do this?
Thank you all so much in advance, for now and all other help I've got from StackExchange!
As explained in my previous answer, the accepted answer isn't optimal and works properly only for billboards, huds and other generally flat objects (not necessarily entirely 2D). When using 3D objects and disabling reading from the depth buffer and objects like the one in the image in above, it won't render correctly from every angle. I.e a 3D object needs to read from the depth buffer to detect its own pixels and depth. That all said, I present the correct answer:
In short, render 2 additional passes. One for the control gizmo (DRAW_NODE), and one to mix it together with the scene by another pass (DRAW_QUAD, with a shader that uses the previous passes as inputs).
Following is the techique's scntec.plist contents:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>passes</key>
<dict>
<key>gizmoonly</key>
<dict>
<key>colorStates</key>
<dict>
<key>clear</key>
<true/>
<key>clearColor</key>
<string>0.5 0.5 0.5 0.0</string>
</dict>
<key>depthStates</key>
<dict>
<key>clear</key>
<true/>
</dict>
<key>inputs</key>
<dict>
<key>colorSampler</key>
<string>COLOR</string>
</dict>
<key>outputs</key>
<dict>
<key>color</key>
<string>gizmonode</string>
</dict>
<key>draw</key>
<string>DRAW_NODE</string>
<key>node</key>
<string>movegizmo</string>
</dict>
<key>quadscene</key>
<dict>
<key>colorStates</key>
<dict>
<key>clear</key>
<true/>
<key>clearColor</key>
<string>sceneBackground</string>
</dict>
<key>depthStates</key>
<dict>
<key>clear</key>
<true/>
</dict>
<key>inputs</key>
<dict>
<key>totalSceneO</key>
<string>COLOR</string>
<key>a_texcoord</key>
<string>a_texcoord-symbol</string>
<key>gizmoNodeO</key>
<string>gizmonode</string>
</dict>
<key>outputs</key>
<dict>
<key>color</key>
<string>COLOR</string>
</dict>
<key>draw</key>
<string>DRAW_QUAD</string>
<key>program</key>
<string>gizmo</string>
</dict>
</dict>
<key>sequence</key>
<array>
<string>gizmoonly</string>
<string>quadscene</string>
</array>
<key>targets</key>
<dict>
<key>totalscene</key>
<dict>
<key>type</key>
<string>color</string>
</dict>
<key>gizmonode</key>
<dict>
<key>type</key>
<string>color</string>
</dict>
</dict>
<key>symbols</key>
<dict>
<key>a_texcoord-symbol</key>
<dict>
<key>semantic</key>
<string>texcoord</string>
</dict>
<key>vertexSymbol</key>
<dict>
<key>semantic</key>
<string>vertex</string>
</dict>
</dict>
</dict>
</plist>
Following is the vertex shader for the second pass:
attribute vec4 a_position;
varying vec2 uv;
void main() {
gl_Position = a_position;
uv = (a_position.xy + 1.0) * 0.5;
}
The fragment shader for the second pass:
uniform sampler2D totalSceneO;
uniform sampler2D gizmoNodeO;
varying vec2 uv;
void main() {
vec4 t0 = texture2D(totalSceneO, uv);
vec4 t1 = texture2D(gizmoNodeO, uv);
gl_FragColor = (1.0 - t1.a) * t0 + t1.a * t1;
}
Swift code:
if let path = NSBundle.mainBundle().pathForResource("scntec", ofType: "plist") {
if let dico1 = NSDictionary(contentsOfFile: path) {
let dico = dico1 as! [String : AnyObject]
let technique = SCNTechnique(dictionary:dico)
scnView.technique = technique
}
}
Objective-C code:
NSURL *url = [[NSBundle mainBundle] URLForResource:@"scntec" withExtension:@"plist"];
SCNTechnique *technique = [SCNTechnique techniqueWithDictionary:[NSDictionary dictionaryWithContentsOfURL:url]];
self.myView.technique = technique;
Set the name for the gizmo node:
theGizmo.name = @"movegizmo";