我已经使用ARFaceTrackingConfiguration会话设置了SceneView,并在Scene资源中创建了一个虚拟3D模型。
该模型已导入SceneView中,但随着摄像机的移动而相应地移动,我需要将模型位置固定在SceneView的中心。
下图演示了我要实现的目标。
因此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
}
答案 0 :(得分:0)
这是我自己的问题的答案。
首先将对象静态地放置在sceneView的中间,这意味着您不希望在摄像机移动时移动该对象,需要将其位置设置为摄像机的当前朝向位置。
要获取相机的当前位置,我们需要访问pointOfView值。
pointOfView
包含cameraView的当前位置和方向
一种用例是当我们需要在摄像机前面添加节点时。
位置和方向在pointOfView
内编码成transformMatrices SCNMatrix4
。
从Apple文档中:
下图显示了一些更常见的矩阵配置 您可以进行的转换。将任何坐标乘以 标识变换返回完全相同的坐标。对于其他 变换,如何修改坐标完全取决于 您更改哪些矩阵组件。例如,沿 仅x轴,您将为tx组件提供非零值 转换矩阵的值,并将ty和tz值保留为0。 旋转,您将提供适当的正弦和余弦值 目标旋转角度。
的矩阵配置
P ...!
现在,如果您使用pointOfView
方法而不是ARSCNViewDelegate
方法,则可以在类主体中获取renderer(_nodeFor:)
,然后对象将遵循面的几何形状:
guard let pointOfView = self.sceneView.pointOfView else { return }
然后可以通过以下方式将对象放置在屏幕中间:
DispatchQueue.main.async {
pointOfView.addChildNode(yourNode)
}
因此,现在该对象位于摄像头的中央,并且不会随摄像头的移动而相应地移动。
然后通过上下倾斜头部移动对象,我们需要实现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)
因此,正如我之前说过的,在每个节点/锚点内部都有一个称为transform的属性,该属性是一个矩阵,该矩阵编码锚点相对于放置该锚点的AR会话的世界坐标空间的位置,方向和比例。
简而言之:这与3维指标有关。
如果发现第2列中的y和x值是头部的水平和垂直移动,则那里的小数学运算符+ degreeToRadians
的扩展名只是用来转换eulerAngles
旋转矩阵的值。>