tutoriales.com

Desbloquea ARKit: Realidad Aumentada en iOS con SwiftUI y USDZ

Este tutorial te guiará a través del fascinante mundo de la Realidad Aumentada en iOS utilizando el potente framework ARKit, la versatilidad de SwiftUI y el formato de archivo USDZ. Aprenderás a configurar tu proyecto, detectar superficies, colocar objetos 3D virtuales e interactuar con ellos, transformando la realidad que te rodea en una experiencia interactiva y mágica.

Intermedio20 min de lectura9 views
Reportar error

🚀 Introducción a la Realidad Aumentada y ARKit

La Realidad Aumentada (RA) es una tecnología que superpone información digital en el mundo real, creando una experiencia interactiva y mejorada. En iOS, Apple nos proporciona ARKit, un framework robusto que permite a los desarrolladores crear experiencias de RA inmersivas y de alta calidad con gran facilidad. Desde iOS 11, ARKit ha evolucionado significativamente, ofreciendo capacidades avanzadas como la detección de superficies horizontales y verticales, seguimiento de objetos 3D, mapeo de entornos y oclusión de personas.

Este tutorial te sumergirá en la creación de tu primera aplicación de RA utilizando ARKit junto con SwiftUI para la interfaz de usuario. Nos centraremos en la detección de planos y la colocación de modelos 3D en formato USDZ, el estándar de Apple para contenido 3D AR.

¿Por qué ARKit y SwiftUI?

  • ARKit: El corazón de la RA en iOS. Proporciona todas las herramientas necesarias para el seguimiento de movimiento, comprensión de escenas y renderizado de contenido. Es altamente optimizado y aprovecha al máximo el hardware de los dispositivos Apple.
  • SwiftUI: El framework declarativo de Apple para construir interfaces de usuario en todas sus plataformas. Su integración con ARKit, aunque requiere un poco de UIKit a través de UIViewRepresentable, simplifica enormemente la gestión del estado y la lógica de la UI.
  • USDZ: Un formato de archivo universal para activos 3D, desarrollado por Pixar y Apple. Es eficiente, soporta animaciones y texturas, y está optimizado para la RA en iOS, facilitando la visualización de modelos 3D.

🛠️ Requisitos y Configuración Inicial del Proyecto

Antes de sumergirnos en el código, asegúrate de tener lo siguiente:

  • Xcode: Versión 13 o superior. Puedes descargarlo desde la App Store.
  • Dispositivo iOS compatible con ARKit: iPhone SE (2ª generación o posterior), iPhone 6S o posterior, iPad Pro, o iPad (5ª generación o posterior). Los simuladores de iOS NO son compatibles con ARKit, necesitas un dispositivo real.
  • Conocimientos básicos de Swift y SwiftUI: Aunque guiaremos paso a paso, una base sólida te ayudará a comprender mejor los conceptos.

Creando un Nuevo Proyecto Xcode

  1. Abre Xcode y selecciona Create a new Xcode project.
  2. En la plantilla, elige iOS -> App y haz clic en Next.
  3. Configura tu proyecto:
    • Product Name: MiAppAR (o el que prefieras).
    • Interface: SwiftUI.
    • Language: Swift.
    • Storage: None (no usaremos Core Data para este tutorial).
  4. Haz clic en Next y guarda el proyecto en una ubicación conveniente.

Habilitando las Capacidades de Cámara para AR

Para que ARKit funcione, tu aplicación necesita acceso a la cámara. Esto se declara en el archivo Info.plist (o en la pestaña de Info del objetivo del proyecto).

  1. Selecciona el objetivo de tu proyecto (MiAppAR) en el navegador del proyecto.
  2. Ve a la pestaña Info.
  3. Desplázate hacia abajo y busca la sección Custom iOS Target Properties.
  4. Haz clic en el botón + para añadir una nueva clave.
  5. Escribe Privacy - Camera Usage Description (o selecciona Privacy - Camera Usage Description de la lista desplegable).
  6. En el campo Value, escribe una descripción que se mostrará al usuario cuando se le pida permiso para acceder a la cámara, por ejemplo: Necesitamos acceso a la cámara para la Realidad Aumentada.
📌 Nota: Si olvidas añadir esta descripción, tu aplicación fallará al intentar iniciar la sesión de ARKit.

🏞️ Integrando ARKit con SwiftUI: ARViewContainer

ARKit utiliza ARView (de RealityKit en iOS 13+) o ARSCNView (de SceneKit) para mostrar el contenido de RA. Dado que ARView es una vista de UIKit, necesitamos envolverla en un UIViewRepresentable para usarla en SwiftUI.

Crea un nuevo archivo Swift llamado ARViewContainer.swift y añade el siguiente código:

import SwiftUI
import RealityKit
import ARKit

struct ARViewContainer: UIViewRepresentable {
    @Binding var shouldPlaceObject: Bool

    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        
        // Configura la sesión de AR para detectar planos horizontales
        let config = ARWorldTrackingConfiguration()
        config.planeDetection = [.horizontal, .vertical] // Detecta planos horizontales y verticales
        arView.session.run(config)
        
        // Añade un delegado para los eventos de la sesión AR
        context.coordinator.arView = arView
        arView.session.delegate = context.coordinator
        
        // Añade gestos para interactuar con la vista AR
        let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handleTap(_:)))
        arView.addGestureRecognizer(tapGesture)
        
        return arView
    }

    func updateUIView(_ uiView: ARView, context: Context) {
        // Aquí puedes actualizar la vista si las propiedades de SwiftUI cambian
        // Por ejemplo, si shouldPlaceObject cambia, el coordinador puede manejar la lógica
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, ARSessionDelegate {
        var parent: ARViewContainer
        var arView: ARView?
        var anchorEntity: AnchorEntity? // Para el anclaje del objeto 3D

        init(_ parent: ARViewContainer) {
            self.parent = parent
        }
        
        // MARK: - ARSessionDelegate
        func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
            // Este método se llama cuando ARKit detecta un nuevo ancla (ej. un plano)
            for anchor in anchors {
                if let planeAnchor = anchor as? ARPlaneAnchor {
                    print("Plano detectado: \(planeAnchor.alignment == .horizontal ? "Horizontal" : "Vertical")")
                    // Opcional: Visualizar los planos detectados (útil para depuración)
                    // let planeMesh = MeshResource.generatePlane(width: planeAnchor.extent.x, depth: planeAnchor.extent.z)
                    // let material = SimpleMaterial(color: .blue.withAlphaComponent(0.5), is=(false))
                    // let modelEntity = ModelEntity(mesh: planeMesh, materials: [material])
                    // let planeAnchorEntity = AnchorEntity(anchor: planeAnchor)
                    // planeAnchorEntity.addChild(modelEntity)
                    // arView?.scene.addAnchor(planeAnchorEntity)
                }
            }
        }

        func session(_ session: ARSession, didFailWithError error: Error) {
            print("AR Session Failed: \(error.localizedDescription)")
        }
        
        // MARK: - Gesture Handling
        @objc func handleTap(_ sender: UITapGestureRecognizer) {
            guard let arView = arView else { return }
            
            let tapLocation = sender.location(in: arView)
            
            // Realiza un raycast para detectar una superficie en la ubicación del toque
            let results = arView.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .any)
            
            guard let firstResult = results.first else {
                print("No se detectó ninguna superficie en la ubicación del toque.")
                return
            }
            
            // Si shouldPlaceObject es verdadero, coloca el objeto 3D
            if parent.shouldPlaceObject {
                placeObject(at: firstResult.worldTransform)
                parent.shouldPlaceObject = false // Resetea la bandera después de colocar
            }
        }
        
        func placeObject(at transform: simd_float4x4) {
            guard let arView = arView else { return }

            // Si ya hay un objeto, lo removemos para reemplazarlo
            if let existingAnchor = anchorEntity {
                arView.scene.removeAnchor(existingAnchor)
                anchorEntity = nil
            }
            
            // Carga el modelo 3D (asegúrate de que "toy_biplane.usdz" esté en tu proyecto)
            // Puedes reemplazar "toy_biplane.usdz" por cualquier otro modelo USDZ que tengas.
            // Si no tienes uno, descarga uno de la galería de Apple AR Quick Look, por ejemplo.
            do {
                let modelEntity = try ModelEntity.load(named: "toy_biplane.usdz")
                modelEntity.setScale(SIMD3<Float>(0.005, 0.005, 0.005), relativeTo: nil) // Ajusta la escala si es necesario
                modelEntity.generateCollisionShapes(recursive: true) // Permite interacción (tapping)

                // Crea un AnchorEntity en la ubicación del raycast
                let anchor = AnchorEntity(world: transform)
                anchor.addChild(modelEntity)
                arView.scene.addAnchor(anchor)
                
                anchorEntity = anchor // Guarda una referencia al ancla
                
                // Añade una acción de gesto para interactuar con el modelo (ej. mover)
                arView.installGestures(.all, for: modelEntity)
                
                print("Objeto 3D colocado con éxito.")
            } catch {
                print("Error al cargar o colocar el modelo 3D: \(error.localizedDescription)")
            }
        }
    }
}
🔥 Importante: Para que el código funcione, necesitas un modelo USDZ en tu proyecto. Descarga, por ejemplo, `toy_biplane.usdz` de la galería de ejemplos de AR de Apple (busca 'Apple AR Quick Look Gallery'). Arrástralo a tu proyecto en Xcode, asegurándote de marcar la casilla para añadirlo a los targets de la app.

Explicación del ARViewContainer:

  • makeUIView: Crea y configura el ARView. Inicializa la sesión de AR para detectar planos horizontales y verticales (config.planeDetection). Asigna el Coordinator como delegado de la sesión y añade un UITapGestureRecognizer.
  • updateUIView: Se llama cuando las propiedades de la vista SwiftUI cambian. En este caso, no necesitamos actualizaciones complejas aquí, pero es el lugar para ellas.
  • makeCoordinator: Crea y devuelve una instancia de nuestro Coordinator.
  • Coordinator: Una clase NSObject que actúa como delegado para ARSessionDelegate y como target para los gestos.
    • session(_:didAdd:): Se invoca cuando ARKit detecta nuevos anclajes (como planos). Es útil para la depuración o para añadir indicaciones visuales.
    • handleTap(_:): Gestiona los toques en la pantalla. Realiza un raycast para encontrar una ubicación en el mundo real que corresponda al punto tocado. Si se encuentra una superficie y shouldPlaceObject es verdadero, llama a placeObject.
    • placeObject(at:): Carga un modelo USDZ y lo añade a la escena de AR en la posición especificada por la transform del raycast. También instala gestos para que el usuario pueda mover, escalar y rotar el objeto.

🎨 Creando la Interfaz de Usuario con SwiftUI

Ahora integraremos el ARViewContainer en nuestra vista principal de SwiftUI y añadiremos un botón para activar la colocación de objetos.

Modifica tu archivo ContentView.swift de la siguiente manera:

import SwiftUI
import RealityKit

struct ContentView: View {
    @State private var shouldPlaceObject = false
    @State private var showingInfoSheet = false

    var body: some View {
        ZStack {
            // Vista de Realidad Aumentada
            ARViewContainer(shouldPlaceObject: $shouldPlaceObject)
                .edgesIgnoringSafeArea(.all)
            
            // UI para interactuar con AR
            VStack {
                Spacer()
                HStack {
                    Button(action: {
                        showingInfoSheet.toggle()
                    }) {
                        Image(systemName: "info.circle.fill")
                            .font(.largeTitle)
                            .foregroundColor(.white)
                            .padding()
                            .background(Color.black.opacity(0.6))
                            .clipShape(Circle())
                    }
                    .padding(.leading, 20)
                    
                    Spacer()
                    
                    Button(action: {
                        // Activa la bandera para colocar el objeto
                        shouldPlaceObject = true
                    }) {
                        Image(systemName: "plus.circle.fill")
                            .font(.largeTitle)
                            .foregroundColor(.white)
                            .padding()
                            .background(Color.blue.opacity(0.8))
                            .clipShape(Circle())
                    }
                    .padding(.trailing, 20)
                }
                .padding(.bottom, 30)
            }
        }
        .sheet(isPresented: $showingInfoSheet) {
            InfoSheetView()
        }
    }
}

// Vista auxiliar para la información
struct InfoSheetView: View {
    var body: some View {
        NavigationView {
            VStack(alignment: .leading, spacing: 15) {
                Text("Cómo usar Mi App AR")
                    .font(.largeTitle)
                    .fontWeight(.bold)
                    .padding(.bottom, 10)
                
                Text("1. 🚶‍♂️ **Mueve tu dispositivo:** Escanea tu entorno lentamente para que ARKit pueda detectar superficies (planos horizontales y verticales).")
                
                Text("2. ➕ **Toca el botón '+'**: Esto activará el modo de colocación de objetos.")
                
                Text("3. 👆 **Toca una superficie:** Toca la pantalla en la ubicación deseada para colocar un modelo 3D.")
                
                Text("4. 🤏 **Interactúa:** Una vez colocado, puedes pellizcar para escalar, rotar con dos dedos o arrastrar para mover el objeto.")
                
                Spacer()
            }
            .padding()
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cerrar") {
                        // Dismiss sheet (handled by environment property)
                    }
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Desglose de ContentView:

  • @State private var shouldPlaceObject = false: Una variable de estado que usamos para comunicar al ARViewContainer que queremos colocar un objeto. Cuando el usuario toca el botón +, esta variable se establece en true. El Coordinator la consume y la vuelve a establecer en false después de colocar el objeto.
  • ARViewContainer(shouldPlaceObject: $shouldPlaceObject): Nuestra vista de Realidad Aumentada que ocupa toda la pantalla.
  • Botón +: Al tocarlo, shouldPlaceObject se activa, permitiendo la colocación del objeto al siguiente toque en la pantalla.
  • Botón Info: Muestra una hoja (sheet) con instrucciones para el usuario, lo cual es crucial para una buena experiencia de usuario en RA.

🖼️ Añadiendo Modelos USDZ al Proyecto

Como mencionamos, necesitas un modelo 3D en formato USDZ. Puedes crearlos con herramientas 3D como Blender o Cinema 4D y exportarlos a USDZ, o encontrar modelos ya hechos.

Pasos para añadir un modelo:

  1. Obtén un archivo USDZ: Para este tutorial, te recomiendo descargar toy_biplane.usdz o cualquier otro modelo de la Galería de Modelos AR Quick Look de Apple
  2. Arrastra y Suelta: Arrastra el archivo .usdz desde tu Finder directamente al navegador de proyecto de Xcode (donde están tus archivos Swift).
  3. Opciones de Añadir: Asegúrate de que la opción Copy items if needed esté marcada y que el target de tu aplicación (MiAppAR) esté seleccionado en la sección Add to targets.
  4. Verifica: Una vez añadido, deberías poder hacer clic en el archivo USDZ en Xcode y ver una vista previa del modelo 3D.
Inicio Arrastrar archivo USDZ al Navegador de Xcode Ventana de diálogo 'Add files to ...' Marcar: 'Copy items if needed' Seleccionar el Target correcto Clic en 'Add'

🏃 Ejecutando y Probando tu Aplicación AR

Ahora estás listo para probar tu aplicación en un dispositivo real.

  1. Conecta tu dispositivo iOS: Asegúrate de que esté conectado a tu Mac y seleccionado como el dispositivo de destino en Xcode.
  2. Ejecuta la aplicación: Haz clic en el botón Run (el triángulo) en Xcode.
  3. Permisos de Cámara: La primera vez, la aplicación te pedirá permiso para usar la cámara. Acepta.
  4. Escanea el Entorno: Mueve tu dispositivo lentamente por el área para que ARKit pueda detectar superficies. Verás una retroalimentación visual (a veces un punto o una cuadrícula, dependiendo de la configuración y la versión de iOS) indicando que ARKit está trabajando.
  5. Coloca el Objeto: Toca el botón + en la parte inferior de la pantalla. Luego, toca una superficie detectada. Deberías ver tu modelo 3D aparecer en el mundo real.
  6. Interactúa: Intenta arrastrar, pellizcar para escalar y rotar con dos dedos el modelo 3D que has colocado.
💡 Consejo: La calidad de la detección de planos mejora con buena iluminación y texturas variadas en el suelo o las paredes. Evita superficies monocromáticas o demasiado reflectantes.

🌟 Mejoras y Próximos Pasos

Has construido una aplicación básica de AR, pero hay mucho más que puedes explorar:

1. Retroalimentación Visual para la Detección de Planos

ARKit a menudo proporciona indicadores visuales de los planos detectados. Puedes mejorar la experiencia del usuario mostrando un punto o una cuadrícula donde el objeto se colocará antes de que el usuario toque la pantalla. Esto implica dibujar un indicador 3D en la posición del raycast continuo del centro de la pantalla.

2. Múltiples Objetos y Selección

Permite al usuario elegir entre varios modelos 3D para colocar. Esto implicaría una barra de herramientas o un selector de objetos en la UI de SwiftUI.

3. Interactividad Avanzada

  • Eliminar objetos: Añade un botón o un gesto para eliminar el objeto 3D colocado.
  • Cambiar materiales: Permite al usuario cambiar el color o la textura del modelo.
  • Animaciones: Si tu modelo USDZ tiene animaciones, puedes activarlas o desactivarlas programáticamente.

4. Anclajes de Imagen y Objeto

ARKit puede detectar imágenes o objetos 3D predefinidos en el entorno y anclar contenido de RA a ellos. Esto abre puertas a experiencias como catálogos interactivos o guías turísticas.

5. Persistencia de Sesión

Guarda el estado de la sesión de AR para que los objetos permanezcan en su lugar incluso si la aplicación se cierra y se vuelve a abrir. Esto se logra serializando y deserializando los ARWorldMap.

6. Oclusión de Personas y Objetos

Utiliza la capacidad de ARKit para segmentar personas u objetos del entorno, permitiendo que el contenido virtual aparezca detrás de ellos, lo que mejora drásticamente el realismo. Esto requiere dispositivos con sensor LiDAR (iPhone 12 Pro/13 Pro/14 Pro/15 Pro, algunos modelos de iPad Pro).

✨ Consejos para optimizar el rendimiento de AR
  • Optimización de modelos 3D: Usa modelos con un número razonable de polígonos y texturas optimizadas para móviles.
  • Gestión de recursos: Carga y descarga modelos eficientemente, especialmente si tienes muchos.
  • Evita cálculos complejos en el bucle principal: Realiza operaciones intensivas fuera del hilo principal para mantener la fluidez de la experiencia de AR.
  • Prueba en diferentes dispositivos: El rendimiento puede variar entre generaciones de dispositivos iOS.

📝 Resumen y Conclusión

¡Felicidades! Has dado tus primeros pasos en el emocionante mundo de la Realidad Aumentada en iOS. Has aprendido a:

  • Configurar un proyecto de Xcode para ARKit.
  • Integrar ARView en una aplicación SwiftUI usando UIViewRepresentable.
  • Detectar planos y realizar raycasts.
  • Cargar y colocar modelos 3D USDZ en el mundo real.
  • Añadir interactividad básica a los objetos 3D.

La Realidad Aumentada es una tecnología con un potencial inmenso, desde el entretenimiento y los juegos hasta la educación, el comercio minorista y la industria. Con ARKit y SwiftUI, tienes las herramientas para crear experiencias verdaderamente innovadoras y envolventes. ¡Sigue experimentando y construyendo!

💡 Recursos adicionales: * [Documentación oficial de ARKit](https://developer.apple.com/documentation/arkit) * [Documentación oficial de RealityKit](https://developer.apple.com/documentation/realitykit) * [Galería de Modelos AR Quick Look de Apple](https://developer.apple.com/augmented-reality/quick-look/)

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!