如何在使用 ARFaceTrackingConfiguration 时将 SceneNode 始终定位在 sceneView 的中心
How to position SceneNode always at the center of the sceneView while using ARFaceTrackingConfiguration
我已经使用 ARFaceTrackingConfiguration 会话设置了 SceneView,并在场景资产中制作了一个虚拟 3D 模型。
模型导入到场景视图中,但它会随着相机的移动而相应移动,我需要的是将模型位置固定在场景视图的中心。
下图展示了我正在努力实现的目标。
因此 3D 模型不应根据相机移动而移动。
@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
}
所以这是我自己问题的答案。
首先静态的在sceneView中间放置一个物体,也就是说你不希望物体随着相机的移动而移动,你需要将它的位置设置为相机当前的朝向位置。
要获取相机的当前位置,我们需要访问 pointOfView 值。
pointOfView
包含cameraView的当前位置和方向
一个用例是当我们需要在相机前面添加节点时。
位置和方向在 pointOfView
内部编码为 transformMatrices SCNMatrix4
.
来自 Apple 文档:
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
呜呜……!
现在在 class 主体中获取 pointOfView
,而不是在 ARSCNViewDelegate
方法中,如果您在 renderer(_nodeFor:)
方法中执行此操作,那么您的对象将遵循面部几何形状:
guard let pointOfView = self.sceneView.pointOfView else { return }
然后您可以通过以下方式将对象放置在屏幕中间:
DispatchQueue.main.async {
pointOfView.addChildNode(yourNode)
}
所以现在对象在相机前面居中,它不会随着相机移动而相应移动。
然后为了通过倾斜头部移动对象 up/down 我们需要实现 ARSCNViewDelegate
并调用:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?
此方法要求代理提供一个与新添加的锚对应的 SceneKit 节点,在我的场景中我对 FaceAnchor 感兴趣。
我已经为 faceAnchor 分配了一个透明度为 0 的面部几何形状,因为我不需要可见它只是为了通过该节点跟踪面部位置,当面部移动时,将调用 didUpdate
方法然后我们可以在 didUpdate
方法中更新节点或任何其他内容,因为只要移动目标节点就会调用它。
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)
所以正如我之前所说,在每个 node/anchor 中有一个 属性 称为变换,它是一个矩阵,编码锚点相对于世界坐标的位置、方向和比例 space 放置锚点的 AR 会话。
简而言之:这与 3 维指标有关。
如果发现第 2 列中的 y 和 x 值是头部的水平和垂直运动,那里的小数学 + degreeToRadians
扩展只是将值转换为 eulerAngles
旋转矩阵。
我已经使用 ARFaceTrackingConfiguration 会话设置了 SceneView,并在场景资产中制作了一个虚拟 3D 模型。
模型导入到场景视图中,但它会随着相机的移动而相应移动,我需要的是将模型位置固定在场景视图的中心。
下图展示了我正在努力实现的目标。
因此 3D 模型不应根据相机移动而移动。
@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
}
所以这是我自己问题的答案。
首先静态的在sceneView中间放置一个物体,也就是说你不希望物体随着相机的移动而移动,你需要将它的位置设置为相机当前的朝向位置。
要获取相机的当前位置,我们需要访问 pointOfView 值。
pointOfView
包含cameraView的当前位置和方向
一个用例是当我们需要在相机前面添加节点时。
位置和方向在 pointOfView
内部编码为 transformMatrices SCNMatrix4
.
来自 Apple 文档:
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
呜呜……!
现在在 class 主体中获取 pointOfView
,而不是在 ARSCNViewDelegate
方法中,如果您在 renderer(_nodeFor:)
方法中执行此操作,那么您的对象将遵循面部几何形状:
guard let pointOfView = self.sceneView.pointOfView else { return }
然后您可以通过以下方式将对象放置在屏幕中间:
DispatchQueue.main.async {
pointOfView.addChildNode(yourNode)
}
所以现在对象在相机前面居中,它不会随着相机移动而相应移动。
然后为了通过倾斜头部移动对象 up/down 我们需要实现 ARSCNViewDelegate
并调用:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?
此方法要求代理提供一个与新添加的锚对应的 SceneKit 节点,在我的场景中我对 FaceAnchor 感兴趣。
我已经为 faceAnchor 分配了一个透明度为 0 的面部几何形状,因为我不需要可见它只是为了通过该节点跟踪面部位置,当面部移动时,将调用 didUpdate
方法然后我们可以在 didUpdate
方法中更新节点或任何其他内容,因为只要移动目标节点就会调用它。
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)
所以正如我之前所说,在每个 node/anchor 中有一个 属性 称为变换,它是一个矩阵,编码锚点相对于世界坐标的位置、方向和比例 space 放置锚点的 AR 会话。
简而言之:这与 3 维指标有关。
如果发现第 2 列中的 y 和 x 值是头部的水平和垂直运动,那里的小数学 + degreeToRadians
扩展只是将值转换为 eulerAngles
旋转矩阵。