web-dev-qa-db-fra.com

ARKit Placez un SCNNode face à la caméra

J'utilise ARKit pour afficher des objets 3D. J'ai réussi à placer les nœuds dans le monde réel devant l'utilisateur (alias la caméra). Mais je n'arrive pas à les faire faire face à la caméra quand je les laisse tomber. 

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)

Les nœuds sont bien positionnés sur le plan, devant la caméra. Mais ils regardent tous dans la même direction. Je suppose que je devrais faire une rotation la SCNNode mais je n’ai pas réussi à le faire. 

10
Marie Dm

D'abord, obtenez la matrice de rotation de la caméra:

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

Ensuite, combinez les matrices:

let rotateTransform = simd_mul(r.worldTransform, rotate)

Enfin, appliquez une transformation à votre nœud, en tant que SCNMatrix4:

node.transform = SCNMatrix4(rotateTransform)

J'espère que cela pourra aider

MODIFIER

voici comment créer SCNMatrix4 à partir de 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)
7
modium

Voulez-vous que les nœuds soient toujours face à la caméra, même lorsque celle-ci bouge? C'est pour ça que SceneKit contraintes est. SCNLookAtConstraint ou SCNBillboardConstraint permet de garder un nœud toujours dirigé vers la caméra. 

Voulez-vous que le nœud soit face à la caméra une fois placé, mais reste immobile (pour pouvoir déplacer la caméra et voir l'arrière de celle-ci)? Il y a plusieurs façons de le faire. Certains impliquent des maths amusantes, mais un moyen plus simple de le gérer pourrait simplement consister à concevoir vos éléments 3D de manière à ce que "devant" soit toujours dans la direction de l'axe Z positif. Définissez la transformation d'un objet placé en fonction de la transformation de la caméra, et son orientation initiale correspondra à celle de la caméra. 

1
rickster

Voici comment je l'ai fait:

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

Comme indiqué précédemment, un SCNBillboardConstraint fera que le nœud regarde toujours la caméra. Je l'anime pour que le nœud ne s'enclenche pas immédiatement, c'est facultatif. Dans le SCNTransaction.completionBlock, je supprime la contrainte, également facultative.

De plus, je règle le SCNBillboardConstraint de freeAxes, qui personnalise l'axe sur lequel le nœud suit la caméra, là encore facultatif.

1
Quan Vo

voici mon code pour le SCNNode face à la caméra..hope aide pour quelqu'un

    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
Caleb

Je veux que le nœud soit face à la caméra quand je le place puis le garde ici (et pouvoir bouger). - Marie Dm Blockquote

Vous pouvez placer un objet face à la caméra en utilisant ceci:

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

Ce code vous sauvera de gimbal lock et d’autres problèmes.

Le vecteur de rotation à quatre composantes spécifie la direction de l'axe de rotation dans les trois premières composantes et l'angle de rotation (en radians) dans la quatrième. La rotation par défaut est le vecteur zéro, ne spécifiant aucune rotation. La rotation est appliquée par rapport à la propriété simdPivot du nœud.

Les propriétés simdRotation, simdEulerAngles et simdOrientation affectent toutes l’aspect rotationnel de la propriété simdTransform du nœud. Toute modification de l'une de ces propriétés est reflétée dans les autres.

https://developer.Apple.com/documentation/scenekit/scnnode/2881845-simdrotationhttps://developer.Apple.com/documentation/scenekit/scnnode/2881843-simdtransform

0
Denis Markov
guard let frame = self.sceneView.session.currentFrame else {
    return
}
node.eulerAngles.y = frame.camera.eulerAngles.y
0
iOS Unit