ARKit将SCNNode放置在面向相机的位置

问题描述 投票:10回答:6

我正在使用ARKit来显示3D对象。我设法将节点放在用户面前的真实世界(也就是相机)。但是当我放下相机时,我无法让它们面对镜头。

let tap_point=CGPoint(x: x, y: y)
let results=arscn_view.hitTest(tap_point, types: .estimatedHorizontalPlane)
guard results.count>0 else{
    return
}
guard let r=results.first else{
    return
}

let hit_tf=SCNMatrix4(r.worldTransform)
let new_pos=SCNVector3Make(hit_tf.m41, hit_tf.m42+Float(0.2), hit_tf.m43)

guard let scene=SCNScene(named: file_name) else{
    return
}
guard let node=scene.rootNode.childNode(withName: "Mesh", recursively: true) else{
    return
}
node.position=new_pos
arscn_view.scene.rootNode.addChildNode(node)

节点位于相机前面的平面上。但他们都朝着同一个方向前进。我想我应该旋转SCNNode,但我没有设法做到这一点。

ios swift arkit scnnode arscnview
6个回答
6
投票

首先,获取相机的旋转矩阵:

let rotate = simd_float4x4(SCNMatrix4MakeRotation(sceneView.session.currentFrame!.camera.eulerAngles.y, 0, 1, 0))

然后,组合矩阵:

let rotateTransform = simd_mul(r.worldTransform, rotate)

最后,将转换应用于您的节点,转换为SCNMatrix4:

node.transform = SCNMatrix4(rotateTransform)

希望有所帮助

编辑

在这里你如何从simd_float4x4创建SCNMatrix4

   let rotateTransform = simd_mul(r.worldTransform, rotate)

  node.transform =  SCNMatrix4(m11: rotateTransform.columns.0.x, m12: rotateTransform.columns.0.y, m13: rotateTransform.columns.0.z, m14: rotateTransform.columns.0.w, m21: rotateTransform.columns.1.x, m22: rotateTransform.columns.1.y, m23: rotateTransform.columns.1.z, m24: rotateTransform.columns.1.w, m31: rotateTransform.columns.2.x, m32: rotateTransform.columns.2.y, m33: rotateTransform.columns.2.z, m34: rotateTransform.columns.2.w, m41: rotateTransform.columns.3.x, m42: rotateTransform.columns.3.y, m43: rotateTransform.columns.3.z, m44: rotateTransform.columns.3.w)

3
投票

这是我面向相机的SCNNode的代码......希望对某人有所帮助

    let location = touches.first!.location(in: sceneView)

    var hitTestOptions = [SCNHitTestOption: Any]()
    hitTestOptions[SCNHitTestOption.boundingBoxOnly] = true

    let hitResultsFeaturePoints: [ARHitTestResult]  = sceneView.hitTest(location, types: .featurePoint)

    let hitTestResults = sceneView.hitTest(location)
    guard let node = hitTestResults.first?.node else {
        if let hit = hitResultsFeaturePoints.first {
            let rotate = simd_float4x4(SCNMatrix4MakeRotation(sceneView.session.currentFrame!.camera.eulerAngles.y, 0, 1, 0))
            let finalTransform = simd_mul(hit.worldTransform, rotate)
            sceneView.session.add(anchor: ARAnchor(transform: finalTransform))
        }
        return
    }

1
投票

即使相机移动,您是否希望节点始终面向相机?这就是SceneKit constraints的用途。 SCNLookAtConstraintSCNBillboardConstraint可以保持节点始终指向相机。

您是否希望节点在放置时面向相机,但保持静止(这样您可以移动相机并查看其背面)?有几种方法可以做到这一点。有些涉及有趣的数学,但处理它的一种更简单的方法可能就是设计3D资产,使“前”总是在正Z轴方向。根据相机变换设置放置对象的变换,其初始方向将与相机匹配。


1
投票

我是这样做的:

func faceCamera() {
    guard constraints?.isEmpty ?? true else {
        return
    }
    SCNTransaction.begin()
    SCNTransaction.animationDuration = 5
    SCNTransaction.completionBlock = { [weak self] in
        self?.constraints = []
    }
    constraints = [billboardConstraint]
    SCNTransaction.commit()
}

private lazy var billboardConstraint: SCNBillboardConstraint = {
    let constraint = SCNBillboardConstraint()
    constraint.freeAxes = [.Y]
    return constraint
}()

如前所述,SCNBillboardConstraint将使节点始终看着相机。我正在设置动画,因此节点不会立即捕捉到位,这是可选的。在SCNTransaction.completionBlock我删除约束,也是可选的。

我还设置了SCNBillboardConstraintfreeAxes,它可以自定义节点跟随摄像机的轴,也是可选的。


0
投票

我希望节点在我放置它时面对相机然后将它保持在这里(并且能够移动)。 - Marie Dm Blockquote

您可以将对象面向相机,使用此:

if let rotate = sceneView.session.currentFrame?.camera.transform {
    node.simdTransform = rotate
}

此代码将为您节省gimbal lock和其他麻烦。

四分量旋转矢量指定前三个分量中的旋转轴的方向和第四个中的旋转角度(以弧度表示)。默认旋转是零向量,指定无旋转。相对于节点的simdPivot属性应用旋转。

simdRotation,simdEulerAngles和simdOrientation属性都会影响节点的simdTransform属性的旋转方面。对其中一个属性的任何更改都会反映在其他属性中。

https://developer.apple.com/documentation/scenekit/scnnode/2881845-simdrotation https://developer.apple.com/documentation/scenekit/scnnode/2881843-simdtransform


0
投票
guard let frame = self.sceneView.session.currentFrame else {
    return
}
node.eulerAngles.y = frame.camera.eulerAngles.y
© www.soinside.com 2019 - 2024. All rights reserved.