Saltar al contenido

Formas virtuales 3D en su sala de estar

Para mezclar con éxito las escenas virtuales con el mundo real, físico, necesitamos ser capaces de identificar la geometría de nuestro entorno. ARKit puede detectar superficies planas en el mundo real y proporciona su posición y orientación. Esta información nos permite colocar objetos virtuales en techos, mesas u otros planos horizontales en el mundo real.

Creé un clon de la demo de FirstARKitApp que creamos anteriormente y lo llamé PlaneDetection. No necesitaremos ningún activo de escena en esta demo, así que lo borré. También eliminé el código de inicialización de la escena 3D del método viewDidLoad() del ViewController, que sólo debería contener las siguientes líneas de código:

Formas virtuales 3D en su sala de estar
Formas virtuales 3D en su sala de estar
123456789suprimir la función viewDidLoad() { super.viewDidLoad() // Establecer la vista delegar escenaView.delegate = self // Mostrar estadísticas como fps e información de tiempo escenaView.showsStatistics = true}

A continuación, necesitamos habilitar la detección de aviones en ARKit. Esto se puede conseguir estableciendo la propiedad planeDetection en el objeto de configuración de la sesión en ARWorldTrackingConfiguration.PlaneDetection.horizontal en el método viewWillAppear() delegate:

123456789101112overridefuncviewWillAppear(_ animado:Bool){super.viewWillAppear(animado)// Crear una sesión configurationlet configuration =ARWorldTrackingConfiguration()// Activar la detección del plano horizontal configuration.planeDetection =.horizontal // Ejecutar la escena de sesión de la vistaView.session.run(configuration)}

swift

Con esta configuración, la sesión detectará superficies horizontales y planas en la geometría del mundo real capturada por la cámara frontal del dispositivo.

Para visualizar cómo funciona la detección de aviones, necesitamos añadir el valor de ARSCNDebugOptions.showFeaturePoints a las debugOptions de la vista de la escena.

123456overridefuncviewDidLoad(){super.viewDidLoad() ... sceneView.debugOptions =[ARSCNDebugOptions.showFeaturePoints] ...}

swift

Al ejecutar la aplicación se mostrarán indicadores visuales, los llamados puntos de características, ya que ARKit encuentra superficies en tiempo real:

Eso está bien, pero ¿qué tal si visualizamos los aviones detectados?

Aquí es donde necesitamos al delegado de ARSCNView. Como recordarán, el delegado del ARSCNView está configurado para ser uno mismo en el método viewDidLoad() delegate:

1234567overridefuncviewDidLoad(){super.viewDidLoad()// Establecer la escena de delegado de la vistaView.delegate =self ...}

swift

El protocolo ARSCNViewDelegate proporciona útiles métodos de delegación. En esta demostración, nos basaremos en el método de delegar del renderizador (nodo _:didAdd: para el ancla:). ARKit llama a este método delegado siempre que se ha añadido a la escena un nuevo nodo correspondiente a un ancla.

Veamos más de cerca el método:

1funcrenderer(_ renderer:SCNSceneRenderer, didAdd node:SCNNode,for anchor:ARAnchor)

swift

El primer parámetro es un renderizador de escenas. Esta es nuestra instancia ARSCNView. El segundo es un objeto SCNNode. El tercer parámetro es un objeto ancla AR correspondiente al nodo.

Entonces, ¿qué es un objeto de anclaje AR? Los anclajes AR se usan para rastrear las posiciones y orientaciones en el mundo real de objetos reales o simulados en relación con la cámara. Cuando activamos la detección de plano horizontal, ARKit llama al renderer(_: didAdd node:, for anchor:) delega el método automáticamente siempre que detecta un nuevo plano horizontal y añade un nuevo nodo para él. Recibimos el ancla de cada superficie plana detectada, que será del tipo ARPlaneAnchor.

ARPlaneAnchor representa una superficie plana en el mundo, definida usando las coordenadas X y Z, donde Y es la normal del plano.

Vamos a implementar el método renderer(_: didAdd node:, para el ancla:):

123456789101112funcrenderer(_ renderer:SCNSceneRenderer, didAdd node:SCNNode,for anchor:ARAnchor){iflet planAnchor = anchor as?ARPlaneAnchor{let plan =SCNPlane(width:CGFloat(planAnchor.extent.x), height:CGFloat(planAnchor.extent.z)) plan.firstMaterial? .contenidos.difusos =UIColor(blanco:1, alfa:0.75)let planeNode =SCNNode(geometría: plano) planeNode.position =SCNVector3Make(planeAnchor.center.x, planeAnchor.center.x, planeAnchor.center.z) planeNode.eulerAngles.x =-.pi /2 node.addChildNode(planeNode)}}

swift

Explicación detallada de este código

1234iflet aviónAnchor = ancla as?ARPlaneAnchor{ ...}

swift

Sólo procesamos anclas del tipo ARPlaneAnchor, ya que sólo estamos interesados en detectar aviones.

1let plano =SCNPlane(width:CGFloat(planAnchor.extent.x), height:CGFloat(planAnchor.extent.z))

swift

Para visualizar los aviones detectados, creo un objeto SCNPlane. El SCNPlane es un tipo de SceneKit que representa una geometría de plano unilateral.

A continuación, establecí el ancho y la altura del avión a los valores X e Y de la extensión del anclaje. La propiedad de la extensión del objeto ARPlaneAnchor proporciona el tamaño estimado del plano detectado. Así, el objeto SCNPlane tendrá el mismo tamaño que el plano detectado en el mundo.

1 plano.primerMaterial?.contenido.difuso =UIColor(blanco:1, alfa:0.75)

swift

Luego, puse el material difuso del avión en blanco con un 75% de transparencia.

123 planoletNode =SCNNode(geometría: plano) planoNode.position =SCNVector3Make(planoAnchor.center.x, planoAnchor.center.y, planoAnchor.center.z) planoNode.eulerAngles.x =-.pi /2

swift

Se crea un SCNode con la geometría del plano. La posición del nodo coincidirá con la posición del ancla para darnos una pista visual precisa. Utilizo las coordenadas del centro del ancla para crear un vector 3D. El SCNPlane es unilateral y aparecería perpendicular a la superficie por defecto. Necesito rotar el planoNodo 90 grados en sentido contrario a las agujas del reloj para que se muestre correctamente.

1 nodo.addChildNode(planNode)

swift

Finalmente hacemos el planeNode, un nodo hijo del recién creado nodo de la escena.

Ejecutar la aplicación producirá resultados como este:

ARKit sigue monitoreando el ambiente y actualiza las anclas previamente detectadas. Podemos suscribirnos a estas actualizaciones implementando el renderer(_:, nodo didUpdate:, para el ancla:) ARSCNViewDelegate método delegado.

Pongamos en práctica el delegado para que podamos mostrar resultados más precisos.

123456789funcrenderer(_ renderer:SCNSceneRenderer, didUpdate node:SCNNode,for anchor:ARAnchor){iflet planAnchor = anchor as?ARPlaneAnchor,let planNode = node.childNodes.first,let plan = planNode. geometría as?SCNPlane{ plano.ancho =CGFloat(planoAnchor.extent.x) plano.alto =CGFloat(planoAnchor.extent.z) planoNode.position =SCNVector3Make(planoAnchor.center.x,0, planoAnchor.center.z)}}

swift

Primero, realizamos algunas comprobaciones de seguridad para asegurarnos de que estamos trabajando con la información del avión. Luego, fijamos el ancho y la altura del objeto SCNPlane. Finalmente, actualizamos la posición del nodo infantil.

Ahora, somos capaces de detectar superficies continuas más grandes y mostrar las superposiciones de los planos con más precisión.

Construye y ejecuta la aplicación en un dispositivo. Permita que ARKit recopile suficiente información sobre el entorno moviendo su dispositivo por superficies planas. Verá a ARKit en acción a medida que actualiza el tamaño y la posición de las superficies detectadas.