Reputation: 698
I've setup SceneView with ARFaceTrackingConfiguration session, and Imade a dummy 3D Model in Scene assets.
The model is imported in the sceneView but it's moving accordingly with camera movement, what I need is to fix the models position at the center of the sceneView.
The image below demonstrates what I'm trying to achieve.
So the 3D Model should not move based on camera movement.
@IBOutlet var sceneView: ARSCNView!
let scene = SCNScene(named: "art.scnassets/TEST.scn")!
var contentNode: SCNNode?
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
sceneView.scene = self.scene
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARFaceTrackingConfiguration()
configuration.isLightEstimationEnabled = true
// Run the view's session
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
guard let faceAnchor = anchor as? ARFaceAnchor else { return nil }
let faceGeometry = ARSCNFaceGeometry(device: sceneView.device!)!
self.contentNode = SCNNode(geometry: faceGeometry)
return self.contentNode
}
Upvotes: 4
Views: 2293
Reputation: 698
So here is the answer to my own question.
firstly to place an object in the middle of the sceneView statically, which means you don't want the object to move when camera is moving, you need to set its position to the current facing position of the camera.
To Get the current location of the camera we need to access pointOfView value.
pointOfView
contains the current location and orientation of the cameraView
One use-case is when we need to add nodes in front of the camera.
The location and orientation are encoded inside of the pointOfView
into a transformMatrices SCNMatrix4
.
From Apple documentation:
Image below shows the matrix configurations for some of the more common transformations you can make. Multiplying any coordinate by the identity transform returns the exact same coordinate. For other transformations, how the coordinate is modified depends entirely on which matrix components you change. For example, to translate along the x-axis only, you would supply a nonzero value for the tx component of the translation matrix and leave the ty and tz values to 0. For rotations, you would provide the appropriate sine and cosine values of the target rotation angle. Matrix configurations for
Pheeeew...!
Now grab the pointOfView
in your class body not in ARSCNViewDelegate
methods if you do it in renderer(_nodeFor:)
method then your object will follow the face geometry:
guard let pointOfView = self.sceneView.pointOfView else { return }
and then you can position your object in the middle of the screen by:
DispatchQueue.main.async {
pointOfView.addChildNode(yourNode)
}
So now the object is centered in front of the camera and it will not move accordingly with camera movement.
then for moving the object by tilting the head up/down we need to implement ARSCNViewDelegate
and call the:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?
this method asks the delegate to provide a SceneKit node corresponding to a newly added anchor which in my scenario i'm interested in FaceAnchor.
i've assigned a face geometry to the faceAnchor with 0 transparency because i don't need that being visible its just for tracking the face position via that node, when the face is moved the didUpdate
method will be called and then we can update the nodes or what so ever in didUpdate
method because it's getting called whenever the targeted node is moved.
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let faceAnchor = anchor as? ARFaceAnchor else { return }
let faceTransform = faceAnchor.transform
let positionY = faceLocation.columns.2.y
let positionX = faceLocation.columns.2.x
let horizentalLine = Int(positionY * 100)
self.horizentalNode.eulerAngles = SCNVector3(horizentalLine.degreeToRadians, 0, 0)
So as i said before inside each node/anchor there is a property called transform which is a matrix encoding the position, orientation, and scale of the anchor relative to the world coordinate space of the AR session the anchor is placed in.
in short: This has something to do with 3 dimensional metrics.
if found out that y and x value in column number 2 is the horizontal and vertical movement of the head, the little math there + degreeToRadians
extension is just to convert the value for eulerAngles
rotation matrices.
Upvotes: 4