2017-08-24 4 views
1

J'ai créé un SCNSphere, maintenant il ressemble à une planète. C'est exactement ce que je veux. Mon prochain objectif est de permettre aux utilisateurs de faire pivoter la sphère à l'aide d'un outil de reconnaissance de mouvements. Ils sont autorisés à le faire tourner autour de l'axe X ou Y. Je me demandais comment je pouvais faire ça. C'est ce que j'ai jusqu'ici.Comment faire pivoter un SCNSphere à l'aide d'un outil de reconnaissance de mouvements de pan

origin = sceneView.frame.origin 
node.geometry = SCNSphere(radius: 1) 
node.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "world.jpg") 

let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(CategoryViewController.panGlobe(sender:))) 
sceneView.addGestureRecognizer(panGestureRecognizer) 

func panGlobe(sender: UIPanGestureRecognizer) { 
    // What should i put inside this method to allow them to rotate the sphere/ball 
} 
+0

Pourquoi voulez-vous ajouter un geste à la vue de la scène? Recherchez le hitTest. Je peux vous dire que ça ne va pas être facile. –

+0

Parce que la scène contient une balle. Donc, je veux seulement que le geste s'applique à la balle/sphère – user8426652

+0

C'est une mauvaise idée. –

Répondre

2

Nous avons un ViewController qui contient un nœud sphereNode qui contient notre sphère. Pour faire pivoter la sphère, nous pourrions utiliser un UIPanGestureRecognizer. Étant donné que le système de reconnaissance signale la distance totale parcourue par notre doigt sur l'écran, nous mettons en cache le dernier point qui nous a été signalé.

var previousPanPoint: CGPoint? 
let pixelToAngleConstant: Float = .pi/180 
func handlePan(_ newPoint: CGPoint) { 
    if let previousPoint = previousPanPoint { 
     let dx = Float(newPoint.x - previousPoint.x) 
     let dy = Float(newPoint.y - previousPoint.y) 

     rotateUp(by: dy * pixelToAngleConstant) 
     rotateRight(by: dx * pixelToAngleConstant) 
    } 

    previousPanPoint = newPoint 
} 

Nous calculons dx et dy avec combien pixel doigt a voyagé dans chaque direction depuis la dernière a appelé la reconnaissance. Avec le pixelToAngleConstant nous convertissons notre valeur de pixel dans un angle (en randians) pour faire tourner notre sphère. Utilisez une plus grande constante pour une rotation plus rapide. Le système de reconnaissance de gestes renvoie un state que nous pouvons utiliser pour déterminer si le geste a commencé, s'est terminé ou si le doigt a été déplacé. Lorsque le geste commence, nous sauvegardons l'emplacement des doigts dans previousPanPoint. Lorsque notre doigt bouge, nous appelons la fonction ci-dessus. Lorsque le geste est terminé ou annulé, nous effaceons previousPanPoint.

@objc func handleGesture(_ gestureRecognizer: UIPanGestureRecognizer) { 
    switch gestureRecognizer.state { 
    case .began: 
     previousPanPoint = gestureRecognizer.location(in: view) 
    case .changed: 
     handlePan(gestureRecognizer.location(in: view)) 
    default: 
     previousPanPoint = nil 
    } 
} 

Comment fait-on tourner notre sphère? Les fonctions rotateUp et rotateRight appellent simplement notre fonction plus générale, rotate(by: around:) qui accepte non seulement l'angle mais aussi l'axe de rotation autour. rotateUp tourne autour de l'axe des x, rotateRight autour de l'axe des y.

func rotateUp(by angle: Float) { 
    let axis = SCNVector3(1, 0, 0) // x-axis 
    rotate(by: angle, around: axis) 
} 

func rotateRight(by angle: Float) { 
    let axis = SCNVector3(0, 1, 0) // y-axis 
    rotate(by: angle, around: axis) 
} 

Le rotate(by:around:) est dans ce cas relativement simple parce que nous supposons que le nœud ne se traduit pas/nous voulons tourner autour de l'origine des noeuds système de coordonnées local. Tout est un peu plus compliqué quand on regarde un cas général mais cette réponse n'est qu'un petit point de départ.

func rotate(by angle: Float, around axis: SCNVector3) { 
    let transform = SCNMatrix4MakeRotation(angle, axis.x, axis.y, axis.z) 
    sphereNode.transform = SCNMatrix4Mult(sphereNode.transform, transform) 
} 

Nous créons une matrice de rotation de la angle et la axis et multiplier l'ancien transform de notre sphère avec les valeurs calculées pour obtenir un nouveau transform.

Voici la petite démo que j'ai créé:

Demo


Cette approche présente deux inconvénients majeurs.

  1. Il tourne seulement autour des nœuds origine des coordonnées et ne fonctionne correctement que si est SCNVector3Zero

  2. position du nœud Il ne prend ni la vitesse du geste en compte ni la sphère continue de tourner lorsque le le geste s'arrête. Un effet similaire à une vue de table où vous pouvez retourner votre doigt et la vue de la table défile rapidement puis ralentit ne peut pas être facilement réalisée avec cette approche. Une solution serait d'utiliser le système de physique pour cela.