首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在使用SceneNode时始终将sceneView定位在sceneView的中心

如何在使用SceneNode时始终将sceneView定位在sceneView的中心
EN

Stack Overflow用户
提问于 2019-04-29 15:10:31
回答 1查看 1.6K关注 0票数 4

我已经用SceneView会话设置了ARFaceTrackingConfiguration,并在场景资产中创建了一个虚拟的3D模型。

模型是在sceneView中导入的,但是随着相机的移动,它会相应地移动,我需要的是修复模型在sceneView中心的位置。

下面的图片展示了我正在努力实现的目标。

因此,3D模型不应该基于摄像机的运动而移动。

代码语言:javascript
复制
@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
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-02 20:11:30

这是我自己问题的答案。

首先,要静态地将一个对象放置在sceneView的中间,这意味着当摄像机移动时,您不希望对象移动,您需要将它的位置设置为摄像机当前面对的位置。要获得摄像机的当前位置,我们需要访问pointOfView值。pointOfView包含cameraView的当前位置和方向,一个用例是当我们需要在摄像机前面添加节点时。位置和方向在pointOfView内部编码为transformMatrices SCNMatrix4。来自苹果公司的文档:

下图显示了您可以进行的一些更常见的转换的矩阵配置。将任意坐标乘以恒等变换返回完全相同的坐标。对于其他转换,如何修改坐标完全取决于您更改的矩阵组件。例如,为了仅沿x轴进行转换,您将为转换矩阵的tx组件提供一个非零值,并将ty和tz值保留为0。对于旋转,您将提供适当的正弦和余弦值的目标旋转角度。矩阵配置

菲尤!现在,获取类体中的pointOfView,而不是在ARSCNViewDelegate方法中,如果您在renderer(_nodeFor:)方法中这样做,那么您的对象将遵循面几何图形:

代码语言:javascript
复制
guard let pointOfView = self.sceneView.pointOfView else { return }

然后,您可以通过以下方法将对象定位在屏幕的中间:

代码语言:javascript
复制
DispatchQueue.main.async {
    pointOfView.addChildNode(yourNode)
}

因此,现在物体的中心是在摄像机前面,它将不会相应地移动与相机的运动。

然后,为了通过上下倾斜来移动对象,我们需要实现ARSCNViewDelegate并调用:

代码语言:javascript
复制
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?

该方法要求委托提供一个与新添加的锚点相对应的SceneKit节点,在我的场景中,我对FaceAnchor感兴趣。我为faceAnchor分配了一个具有0透明度的人脸几何,因为我不需要通过该节点跟踪人脸位置--这仅仅是为了跟踪面部位置,当人脸被移动时,didUpdate方法将被调用,然后我们可以更新节点或didUpdate方法中的任何东西,因为每当移动目标节点时,都会调用它。

代码语言:javascript
复制
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会话的世界坐标空间的位置、方向和规模。简而言之:这与三维度量有关。如果发现第2列中的y和x值是头部的水平和垂直运动,则这里的小数学+ degreeToRadians扩展就是转换eulerAngles旋转矩阵的值。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55906182

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档