ARKit detecta el entorno físico y RealityKit renderiza objetos 3D sobre él. La combinación de ambos permite colocar muebles virtuales en un salón, ver cómo queda un cuadro en la pared o construir juegos que usan el suelo y las mesas de la habitación real. Con SwiftUI, la integración es más sencilla que con UIKit gracias a ARView en un UIViewRepresentable.
Configurar ARKit: ARWorldTrackingConfiguration
ARKit usa la cámara y los sensores del dispositivo para construir un mapa del entorno. La configuración más completa es ARWorldTrackingConfiguration:
import ARKit
import RealityKit
class ARCoordinator: NSObject, ARSessionDelegate {
var arView: ARView?
func configurar() {
let config = ARWorldTrackingConfiguration()
config.planeDetection = [.horizontal, .vertical] // Detectar suelo, techo y paredes
config.environmentTexturing = .automatic // Reflexiones realistas
// Oclusión de personas (A14 en adelante)
if ARWorldTrackingConfiguration.supportsFrameSemantics(.personSegmentationWithDepth) {
config.frameSemantics.insert(.personSegmentationWithDepth)
}
arView?.session.run(config, options: [.resetTracking, .removeExistingAnchors])
arView?.session.delegate = self
}
// Cuando se detecta un nuevo plano
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
for anchor in anchors {
if let plano = anchor as? ARPlaneAnchor {
print("Plano (plano.alignment == .horizontal ? "horizontal" : "vertical") detectado")
}
}
}
}
ARView en SwiftUI con UIViewRepresentable
ARView es una vista UIKit que se envuelve en UIViewRepresentable para integrarse en SwiftUI:
import SwiftUI
import RealityKit
import ARKit
struct ARVistaSwiftUI: UIViewRepresentable {
@Binding var colocarObjeto: Bool
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
// Configurar AR
let config = ARWorldTrackingConfiguration()
config.planeDetection = [.horizontal]
arView.session.run(config)
// Añadir coaching overlay (guía visual para el usuario)
let overlay = ARCoachingOverlayView()
overlay.session = arView.session
overlay.goal = .horizontalPlane
overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
arView.addSubview(overlay)
// Gesto para colocar objetos al tocar
let toque = UITapGestureRecognizer(target: context.coordinator,
action: #selector(Coordinator.manejarToque(_:)))
arView.addGestureRecognizer(toque)
context.coordinator.arView = arView
return arView
}
func updateUIView(_ uiView: ARView, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject {
var arView: ARView?
@objc func manejarToque(_ reconocedor: UITapGestureRecognizer) {
guard let arView else { return }
let punto = reconocedor.location(in: arView)
colocarModelo(en: punto, arView: arView)
}
func colocarModelo(en punto: CGPoint, arView: ARView) {
// Raycasting: proyectar el toque sobre superficies detectadas
let resultados = arView.raycast(from: punto,
allowing: .estimatedPlane,
alignment: .horizontal)
guard let primer = resultados.first else { return }
// Crear entidad 3D en la posición del raycast
let mesh = MeshResource.generateBox(size: [0.1, 0.1, 0.1], cornerRadius: 0.01)
let material = SimpleMaterial(color: .orange, isMetallic: true)
let modelo = ModelEntity(mesh: mesh, materials: [material])
// Crear anchor en la posición AR
let anchor = AnchorEntity(world: primer.worldTransform)
anchor.addChild(modelo)
arView.scene.addAnchor(anchor)
}
}
}
Raycasting: colocar objetos con precisión
El raycasting proyecta un rayo desde el punto de toque en pantalla hacia el mundo real, devolviendo la intersección con superficies detectadas:
// Raycasting a planos existentes (más preciso)
let resultados = arView.raycast(from: puntoPantalla,
allowing: .existingPlaneGeometry,
alignment: .horizontal)
// Raycasting a planos estimados (funciona sin plano confirmado todavía)
let resultados2 = arView.raycast(from: puntoPantalla,
allowing: .estimatedPlane,
alignment: .any)
if let hit = resultados.first {
let posicion = hit.worldTransform.translation // simd_float3
// hit.worldTransform contiene posición + orientación de la superficie
}
Gestos AR: mover y rotar modelos
RealityKit tiene gestos AR integrados que funcionan directamente con los modelos:
// En el makeUIView, añadir gestos a la arView:
arView.installGestures([.translation, .rotation, .scale], for: modelo)
// El modelo debe tener CollisionComponent para que los gestos funcionen:
modelo.generateCollisionShapes(recursive: true)
modelo.components.set(InputTargetComponent())
App de decoración: ejemplo completo
struct AppDecoracion: View {
@State private var modeloSeleccionado: String = "silla"
@State private var colocarActivo = false
let modelos = ["silla", "mesa", "lampara", "sofá"]
var body: some View {
ZStack(alignment: .bottom) {
ARVistaSwiftUI(colocarObjeto: $colocarActivo)
.ignoresSafeArea()
// Panel de selección de muebles
ScrollView(.horizontal) {
HStack(spacing: 16) {
ForEach(modelos, id: .self) { nombre in
Button(nombre.capitalized) {
modeloSeleccionado = nombre
}
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(modeloSeleccionado == nombre ? Color.blue : Color.gray.opacity(0.5))
.foregroundStyle(.white)
.clipShape(Capsule())
}
}
.padding()
}
.background(.ultraThinMaterial)
}
}
}
ARCoachingOverlayView: guiar al usuario
ARCoachingOverlayView muestra instrucciones visuales automáticas para que el usuario mueva el dispositivo y permita a ARKit mapear el entorno. Se activa automáticamente cuando el tracking quality es insuficiente y desaparece cuando se alcanza el objetivo configurado. Es el estándar recomendado por Apple para el onboarding de apps AR.
Resumen
ARKit proporciona el mapa del entorno real (planos, anclas, posición del dispositivo) y RealityKit lo popula con objetos 3D. El flujo básico es: configurar ARWorldTrackingConfiguration con detección de planos, envolver ARView en UIViewRepresentable, usar raycasting para convertir toques en posiciones 3D y añadir entidades ModelEntity o modelos USDZ en esas posiciones. ARCoachingOverlayView gestiona el onboarding de tracking y los gestos integrados de RealityKit permiten mover y escalar objetos sin código adicional.
