Rob Sanders
Rob Sanders

Reputation: 5347

SceneKit detect touch in given area

I'm trying to detect a touch within a given area using SceneKit. It's fairly trivial to do this with one geometry (you just perform a hit test on the scene view) however, I have a custom area defined by an array of SCNNodes (SCNVector3s).

I create my custom area like so:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (!self.isMakingLine) {
        [super touchesBegan:touches withEvent:event];
    } else {
        self.vectors = [[NSMutableArray alloc] init];
        NSArray <SCNHitTestResult *> *res = [self.sceneView hitTest:[[touches anyObject] locationInView:self.sceneView] options:@{SCNHitTestFirstFoundOnlyKey : @YES}];
        if (res.count) {
            SCNHitTestResult *result = res.lastObject;
            if (result.node == self.sphereNode) {
                SCNNode *n = [SCNNode nodeWithGeometry:[SCNBox boxWithWidth:0.01 height:0.01 length:0.01 chamferRadius:0]];
                n.geometry.firstMaterial.diffuse.contents = [UIColor greenColor];
                n.position = result.localCoordinates;
                [self.sphereNode addChildNode:n];
                [self.vectors addObject:n];
            }
        }
    }
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (!self.isMakingLine) {
        [super touchesMoved:touches withEvent:event];
    } else {
        NSArray <SCNHitTestResult *> *res = [self.sceneView hitTest:[[touches anyObject] locationInView:self.sceneView] options:@{SCNHitTestFirstFoundOnlyKey : @YES}];
        if (res.count) {
            SCNHitTestResult *result = res.lastObject;
            if (result.node == self.sphereNode) {
                SCNNode *n = [SCNNode nodeWithGeometry:[SCNBox boxWithWidth:0.01 height:0.01 length:0.01 chamferRadius:0]];
                n.geometry.firstMaterial.diffuse.contents = [UIColor greenColor];
                n.position = result.localCoordinates;
                [self.sphereNode addChildNode:n];
                [self.vectors addObject:n];
            }
        }
    }
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (!self.isMakingLine) {
        [super touchesEnded:touches withEvent:event];
    } else {
        NSArray <SCNHitTestResult *> *res = [self.sceneView hitTest:[[touches anyObject] locationInView:self.sceneView] options:@{SCNHitTestFirstFoundOnlyKey : @YES}];
        if (res.count) {
            SCNHitTestResult *result = res.lastObject;
            if (result.node == self.sphereNode) {
                SCNNode *n = [SCNNode nodeWithGeometry:[SCNBox boxWithWidth:0.01 height:0.01 length:0.01 chamferRadius:0]];
                n.geometry.firstMaterial.diffuse.contents = [UIColor greenColor];
                n.position = result.localCoordinates;
                [self.sphereNode addChildNode:n];
                [self.vectors addObject:n];
                self.isMakingLine = NO;
            }
        }
    }
}

So given my array of SCNBoxes how can I detect if another point falls in the middle of them?

Upvotes: 2

Views: 1226

Answers (1)

lock
lock

Reputation: 2897

SCNView conforms to the SCNSceneRenderer protocol and this provides a method projectPoint:(SCNVector3)point that takes a point within your 3D scene and projects it to 2D view coordinates.

I'd try projecting the position of your box nodes into 2D view coordinates, then check if your 2D touch coordinates are within this 2D shape. There's another SO question that will help with this.

Upvotes: 4

Related Questions