2 Replies
      Latest reply on Jan 18, 2018 2:05 AM by YoanGJ
      YoanGJ Level 1 Level 1 (0 points)

        I'm making an app where the user can create some flat shapes by positioning some points on a 3D space with ARKit, but it seems that the part where I create the UIBezierPath using these points is problematic.

         

         

        In my app, the user starts by positioning a virtual transparent wall in AR at the same place that his device by pressing a button:

         

         

                guard let currentFrame = sceneView.session.currentFrame else {
                    return
                }
               
                let imagePlane = SCNPlane(width: sceneView.bounds.width, height: sceneView.bounds.height)
                imagePlane.firstMaterial?.diffuse.contents = UIColor.black
                imagePlane.firstMaterial?.lightingModel = .constant
               
                var windowNode = SCNNode()
                windowNode.geometry = imagePlane
                sceneView.scene.rootNode.addChildNode(windowNode)
               
                windowNode.simdTransform = currentFrame.camera.transform
                windowNode.opacity = 0.1
        

         

         

        Then, the user place some points (some sphere nodes) on that wall to determine the shape of the flat object that he wants to create by pressing a button. If the user points back to the first sphere node created I close the shape, create a node of it and place it at the same position that the wall:

         

         

                let hitTestResult = sceneView.hitTest(self.view.center, options: nil)
               
                if let firstHit = hitTestResult.first {
                    if firstHit.node == windowNode {
                        let x = Double(firstHit.worldCoordinates.x)
                        let y = Double(firstHit.worldCoordinates.y)
                        let pointCoordinates = CGPoint(x: x , y: y)
                       
                        let sphere = SCNSphere(radius: 0.02)
                        sphere.firstMaterial?.diffuse.contents = UIColor.white
                        sphere.firstMaterial?.lightingModel = .constant
                       
                        let sphereNode = SCNNode(geometry: sphere)
                        sceneView.scene.rootNode.addChildNode(sphereNode)
                        sphereNode.worldPosition = firstHit.worldCoordinates
                       
                        if points.isEmpty {
                            windowPath.move(to: pointCoordinates)
                        } else {
                            windowPath.addLine(to: pointCoordinates)
                        }
                       
                        points.append(sphereNode)
                       
                        if undoButton.alpha == 0 {
                            undoButton.alpha = 1
                        }
                    } else if firstHit.node == points.first {
                        windowPath.close()
                        let windowShape = SCNShape(path: windowPath, extrusionDepth: 0)
                        windowShape.firstMaterial?.diffuse.contents = UIColor.white
                        windowShape.firstMaterial?.lightingModel = .constant
                        let tintedWindow = SCNNode(geometry: windowShape)
                       
                        let worldPosition = windowNode.worldPosition
        
        
                        tintedWindow.worldPosition = worldPosition
                        sceneView.scene.rootNode.addChildNode(tintedWindow)
                       
                        //removing all the sphere nodes from points and reinitializing the UIBezierPath windowPath
                        removeAllPoints()
                    }
                }
        

         

        That code works when I create a first invisible wall and a first shape, but when I create a second wall, when I'm done to draw my shape, the shape appears to be deformed and not at the right place like really not at the right place at all. So I think that I'm missing something with the coordinates of my UIBezierPath points but what ?

        • Re: Create UIBezierPath shape in 3D world ARKit
          YoanGJ Level 1 Level 1 (0 points)

          Ok so after several tests, it seems that it depends on the orientation of the device at the launch of the AR session. When the device, at launch,  faces the first wall that the user will create, the shape is created and places as expected. But if the user for exemple launch the app with his device pointed in one direction, then do a rotation of 90 degrees on himself, place the first wall and create his shape, the shape will be deformed and not at the right place.

           

          So it seems that it's a problem of 3D coordinates but I still don't figure it out...

            • Re: Create UIBezierPath shape in 3D world ARKit
              YoanGJ Level 1 Level 1 (0 points)

              I just found the problem ! I was just using the wrong vectors and coordinates... I've never been a math/geometry guy haha

               

              So instead of using:

              let x = Double(firstHit.worldCoordinates.x) 
              let y = Double(firstHit.worldCoordinates.y)
              

               

              I now use:

              let x = Double(firstHit.localCoordinates.x)
              let y = Double(firstHit.localCoordinates.y)
              

               

              And instead of using:

              let worldPosition = windowNode.worldPosition
              

               

              I now use:

              let worldPosition = windowNode.transform
              

               

              That's why the position of my shape node was depending of the initialisation of the AR session, I was working with world coordinates, seems obvious to me now.