-[SCNView hitTest:options:] doesn’t work correctly for orthographic projections

How frustrating it was to find this out.  Luckily, it didn’t take long to realise that there was a pattern to its madness.  It turns out it’s not taking into account the scale of the projection (as set by the camera node’s scale property).  So you can fudge the location appropriately to work around the bug, using code like:

- (void)mouseDown:(NSEvent*)theEvent {
    const NSPoint locationInView = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    const NSSize boundsSize = self.bounds.size;
    const NSPoint fudgedLocationInView = NSMakePoint((boundsSize.width / 2.0) + ((locationInView.x - (boundsSize.width / 2.0)) * self.pointOfView.scale.x),
                                                     (boundsSize.height / 2.0) + ((locationInView.y - (boundsSize.height / 2.0)) * self.pointOfView.scale.y));
    
    NSLog(@"Real location = {%f, %f}.  Bounds size = {%f, %f} and scale is %f, therefore translating perceived location to {%f, %f} in order to work around SceneKit bug (rdar://12890554)",
          locationInView.x, locationInView.y,
          boundsSize.width, boundsSize.height,
          self.pointOfView.scale.x,
          fudgedLocationInView.x, fudgedLocationInView.y);

    NSArray *clickedObjects = [self hitTest:fudgedLocationInView options:nil];

SCNView can have overlapping views, but only if layer-backed

In fact I’m pretty sure this behaviour dates back to NSOpenGLView and possibly others.  I suppose technically this has always been the case; that overlapping views weren’t supported at all before layer-backing.  But I had forgotten, so it took a little bit of experimenting to jog my memory.

It’s interesting that when not layer-backed, all that happens is that the SCNView draws over any overlapping views.  If its background colour is transparent you can actually see the views overlapping it.  In any case, they can receive events just fine.

Tangentially, that you can use translucency to reveal other views “underneath” your SCNView is interesting.  You could use it to present a relatively fixed backdrop for your 3D world, for example, rather than having to deal with actual SCNNodes and camera movement and all that.

+[SCNTransaction setCompletionBlock:] always invokes the block immediately

It’s supposed to invoke your block when all the animations in the current transaction have completed. It doesn’t; it runs it as soon as the transaction is committed. Le sigh.

It does appear to do it from the main runloop at least, as documented. So there is technically a delay, as a consequence of that scheduling. Not helpful though.

Update: turns out that you have to set the completion block before calling +[SCNTransaction begin].  Grrr.  Undocumented behaviour #bajillion+1.