faceIndex
looks promising, but will not actually get something you're likely to consider useful. The "faces" counted by that property are the tessellation of the mesh, so a cube won't be a collection of six quads, it'll be twelve triangles. (Or more: in some cases, even a flat-sided cube will be tessellated with more than one quad / two triangles per side. If you're using SCNBox
you control these with widthSegmentCount
etc.)
Instead — especially if your cube is an SCNBox
— the easiest solution might be to leverage this interesting behavior of that class:
You can assign up to six SCNMaterial
instances to a box—one for each side—with its materials
property. The SCNBox
class automatically creates SCNGeometryElement
objects as needed to handle the number of materials.
So, if you assign six materials, you'll get one for each side:
let front = SCNMaterial()
let right = SCNMaterial()
let back = SCNMaterial()
let left = SCNMaterial()
let top = SCNMaterial()
let bottom = SCNMaterial()
cube.materials = [ front, right, back, left, top, bottom ]
And in so doing, your SCNBox
will have six geometry elements — one for each material, which corresponds to one for each side.
Now, you can use hit testing to find out which geometry element was clicked:
if let result = hitResults.first {
let node = result.node
// Find the material for the clicked element
// (Indices match between the geometryElements and materials arrays)
let material = node.geometry!.materials[result.geometryIndex]
// Do something with that material, for example:
let highlight = CABasicAnimation(keyPath: "diffuse.contents")
highlight.toValue = NSColor.redColor()
highlight.duration = 1.0
highlight.autoreverses = true
highlight.removedOnCompletion = true
material.addAnimation(highlight, forKey: nil)
}
Or if you're not highlighting and want to use the face index for logic, here's the beginning of something you could use for that:
enum CubeFace: Int {
case Front, Right, Back, Left, Top, Bottom
}
// when processing hit test result:
print("hit face: \(CubeFace(rawValue: result.geometryIndex))")