5
votes

I'm working on a small project using ARKit. I want to be able to add objects to my AR SceneView on tap, remove them with a double tap, and drag theme around with a pan or drag.

The initial tap to place objects is working fine, but I have some issues with the Node removal and the dragging.

The main issue with the removal and the dragging is that it is very difficult to actually 'hold' or click on the SCNNode. Most of the results end up not being on the SCNNode I've added.

The second issue is that the dragging is a bit buggy, the SCNNode doesn't really move as much as my finger does on the drag.

I've decided to create a project on github, which is linked here: https://github.com/theraad/ARAttempt

But I'll also post my code for removing objects and dragging objects here:

-(void)handleRemoveObject:(UITapGestureRecognizer *)recognizer {
    NSLog(@"Long Press Fired");
    CGPoint tapPoint = [recognizer locationInView:_sceneView];

    NSArray <SCNHitTestResult *> *result = [self.sceneView hitTest:tapPoint options:nil];

    if ([result count] == 0) {
        return;
    }
    SCNHitTestResult *hitResult = [result firstObject];
    if (hitResult.node) {
        [[hitResult.node parentNode] removeFromParentNode];
    }
}

-(void)moveObject:(UIPanGestureRecognizer *)recognizer {
    NSLog(@"Move object");
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        NSLog(@"Pan state began");
        CGPoint tapPoint = [recognizer locationInView:_sceneView];
        NSArray <SCNHitTestResult *> *result = [self.sceneView hitTest:tapPoint options:nil];

        if ([result count] == 0) {
            return;
        }
        SCNHitTestResult *hitResult = [result firstObject];
        if ([hitResult.node.name isEqualToString:@"candle"]) {
            movedObject = [hitResult node];
        } else if ([[hitResult.node parentNode].name isEqualToString:@"candle"]) {
            movedObject = [[[hitResult node] parentNode] parentNode] parentNode];
        }
        if (movedObject){
            NSLog(@"Holding an Object");
        }
    }
    if (recognizer.state == UIGestureRecognizerStateChanged) {
        NSLog(@"Pan State Changed");
        if (movedObject) {

            CGPoint tapPoint = [recognizer locationInView:_sceneView];
            NSArray <ARHitTestResult *> *hitResults = [_sceneView hitTest:tapPoint types:ARHitTestResultTypeFeaturePoint];
            ARHitTestResult *result = [hitResults lastObject];

            SCNMatrix4 matrix = SCNMatrix4FromMat4(result.worldTransform);
            SCNVector3 vector = SCNVector3Make(matrix.m41, matrix.m42, matrix.m43);

            [movedObject setPosition:vector];
            NSLog(@"Moving object position");
        }
    }
    if (recognizer.state == UIGestureRecognizerStateEnded) {
        NSLog(@"Done moving object homeie");
        movedObject = nil;
    }
}

Any help would be highly appreciated.

Thank you.

UPDATE:

So I found out that the difficulty with grabbing objects was because I was using: self.sceneView.debugOptions = ARSCNDebugOptionShowFeaturePoints; And when i would try to click on an object, it would most of the times be grabbing one of these feature points.

-(void)moveObject:(UIPanGestureRecognizer *)recognizer {
    NSLog(@"Move object");
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        NSLog(@"Pan state began");
        CGPoint tapPoint = [recognizer locationInView:_sceneView];
        NSArray <SCNHitTestResult *> *result = [self.sceneView hitTest:tapPoint options:nil];

        if ([result count] == 0) {
            return;
        }
        SCNHitTestResult *hitResult = [result firstObject];
        movedObject = [[[hitResult node] parentNode] parentNode] parentNode]; //This aspect varies based on the type of .SCN file that you have
        }
        if (movedObject){
            NSLog(@"Holding an Object");
        }
    }
    if (recognizer.state == UIGestureRecognizerStateChanged) {
        NSLog(@"Pan State Changed");
        if (movedObject) {

            CGPoint tapPoint = [recognizer locationInView:_sceneView];
            NSArray <ARHitTestResult *> *hitResults = [_sceneView hitTest:tapPoint types:ARHitTestResultTypeFeaturePoint];
            ARHitTestResult *result = [hitResults lastObject];

            SCNMatrix4 matrix = SCNMatrix4FromMat4(result.worldTransform);
            SCNVector3 vector = SCNVector3Make(matrix.m41, matrix.m42, matrix.m43);

            [movedObject setPosition:vector];
            NSLog(@"Moving object position");
        }
    }
    if (recognizer.state == UIGestureRecognizerStateEnded) {
        NSLog(@"Done moving object homeie");
        movedObject = nil;
    }
}

So the issue seems that instead of grabbing the whole object previously, I was still grabbing a child of this object, and when you attempt to drag a child it forces the movement to be laggy for some reason. So I had to do a bit of trial and error to realize that I had to move up parent levels to fix the issue.

Hope this helps.

1
In case you haven't already, you might want to have a look at Apple's sample project "Placing Virtual Objects in Augmented Reality" see stackoverflow.com/questions/45488881/… for the url of the project. This definitely covers the dragging on-screen part.PDK
What is "movedObject" ? I don't see the declaration. I'm trying to do this in swift and this is what I have so far: @objc func panGesture(sender: UIPanGestureRecognizer){ let sceneView = sender.view as! ARSCNView let pannedLocation = sender.location(in: sceneView) let hitTest = sceneView.hitTest(pannedLocation) if(sender.state == UIGestureRecognizerState.began){ if(!hitTest.isEmpty){ let sceneHitTestResult = hitTest.first! sceneView.scene.rootNode.chil = sceneHitTestResult.node.parent } }humbleCoder
movedObject is just a reference to an SCNNode that gets set in the state began if there is a hit and then gets updated in the state changed of the pan gesture. It's basically only used in this function.Alan
I'm using swift but checkout my answer to this thread for how to drag a SCNNode with an arbitrary amount of child nodes. The most basic thing that must be done is assigning a .categoryBitMask -value to the object you want to select and only hitTest for objects with that bitmask so you don't select any unwanted objects.A. Claesson
The git link is not working. Can you please provide code for understanding how placing of object works.aqsa arshad

1 Answers

0
votes

The solution for dragging the object was to set the movedObject to the [[[hitResult node] parentNode] parentNode] parentNode] and the drag became smoother.