ARKit Place a SCNNode facing the camera

前端 未结 6 2020
挽巷
挽巷 2021-02-02 00:15

I\'m using ARKit to display 3D objects. I managed to place the nodes in the real world in front of the user (aka the camera). But I don\'t manage to make them to fa

相关标签:
6条回答
  • 2021-02-02 00:47

    Here's how I did it:

    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
    }()
    

    As stated earlier a SCNBillboardConstraint will make the node always look at the camera. I am animating it so the node doesn't just immediately snap into place, this is optional. In the SCNTransaction.completionBlock I remove the constraint, also optional.

    Also I set the SCNBillboardConstraint's freeAxes, which customizes on what axis the node follows the camera, again optional.

    0 讨论(0)
  • 2021-02-02 00:49

    Do you want the nodes to always face the camera, even as the camera moves? That's what SceneKit constraints are for. Either SCNLookAtConstraint or SCNBillboardConstraint can keep a node always pointing at the camera.

    Do you want the node to face the camera when placed, but then hold still (so you can move the camera around and see the back of it)? There are a few ways to do that. Some involve fun math, but a simpler way to handle it might just be to design your 3D assets so that "front" is always in the positive Z-axis direction. Set a placed object's transform based on the camera transform, and its initial orientation will match the camera's.

    0 讨论(0)
  • 2021-02-02 00:55

    here's my code for the SCNNode facing the camera..hope help for someone

        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
        }
    
    0 讨论(0)
  • 2021-02-02 00:59

    First, get the rotation matrix of the camera:

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

    Then, combine the matrices:

    let rotateTransform = simd_mul(r.worldTransform, rotate)
    

    Lastly, apply a transform to your node, casting as SCNMatrix4:

    node.transform = SCNMatrix4(rotateTransform)
    

    Hope that helps

    EDIT

    here how you can create SCNMatrix4 from simd_float4x4

       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)
    
    0 讨论(0)
  • 2021-02-02 01:05

    I want the node to face the camera when I place it then keep it here (and be able to move around). – Marie Dm Blockquote

    You can put object facing to camera, using this:

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

    This code will save you from gimbal lock and other troubles.

    The four-component rotation vector specifies the direction of the rotation axis in the first three components and the angle of rotation (in radians) in the fourth. The default rotation is the zero vector, specifying no rotation. Rotation is applied relative to the node’s simdPivot property.

    The simdRotation, simdEulerAngles, and simdOrientation properties all affect the rotational aspect of the node’s simdTransform property. Any change to one of these properties is reflected in the others.

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

    0 讨论(0)
  • 2021-02-02 01:08
    guard let frame = self.sceneView.session.currentFrame else {
        return
    }
    node.eulerAngles.y = frame.camera.eulerAngles.y
    
    0 讨论(0)
提交回复
热议问题