AI генерація 3D-моделі з фотографії у мобільних додатках
Генерувати 3D-об'єкт з однієї фотографії на мобільному пристрої—одна з найбільш ресурсномістких задач у мобільному AI. Класичні підходи вимагають десятків фотографій (фотограмметрія) або спеціального обладнання (LiDAR). Нейромережева генерація з однієї фото—реальна задача у 2024, але з істотними обмеженнями якості при роботі повністю on-device.
Архітектурні варіанти
Повністю на пристрої—легкі моделі типу DepthPro (Apple, 2024) для depth estimation + point cloud, або One-2-3-45 мобільна версія. Отримуємо груба 3D-структура, придатна для AR-превью, але не для експорту в професійні додатки.
Гібрид—на пристрої робимо depth map та початкову сегментацію об'єкту, на сервері—повноцінна 3D-реконструкція через Zero123++, One-2-3-45 або TripoSR. Сервер повертає .obj або .glb файл.
LiDAR-доповнений—на iPhone 12 Pro+ та iPad Pro є LiDAR сканер. ARKit + ARMeshAnchor дозволяють отримати реальний mesh сцени. Комбінація LiDAR mesh + текстура з камери + AI texture inpainting дає якісний результат без сервера.
On-device: DepthPro для початкової глибини
Apple DepthPro (2024)—Foundation Model для metric depth estimation. Конвертується у Core ML:
let model = try DepthPro(configuration: MLModelConfiguration())
// Вхідне зображення → depth map
let inputImage = try MLFeatureValue(cgImage: sourceImage.cgImage!, constraint: nil)
let prediction = try model.prediction(image: inputImage)
// prediction.depth—MLMultiArray з metric depth значеннями (у метрах)
let depthArray = prediction.depth // форма [1, H, W]
Depth map → point cloud: для кожного пікселю (x, y) з відомою глибиною Z обчислюємо 3D-координату через pinhole camera model з focal length з EXIF. Отримуємо хмару точок.
Візуалізація point cloud в AR—через RealityKit та ModelEntity з користувацьким MeshDescriptor:
var descriptor = MeshDescriptor(name: "pointCloud")
descriptor.positions = MeshBuffers.Positions(points) // [SIMD3<Float>]
descriptor.primitives = .points(Array(0..<points.count))
let mesh = try MeshResource.generate(from: [descriptor])
let entity = ModelEntity(mesh: mesh, materials: [UnlitMaterial(color: .white)])
Це не повноцінна 3D-модель з mesh, а point cloud—візуально працює для демо, для експорту потрібен meshing.
Meshing: Poisson або Marching Cubes
Point cloud → полігональний mesh через алгоритм Poisson Surface Reconstruction. На мобілі—через Open3D (C++ бібліотека через Objective-C bridge) або власна реалізація через Metal compute shaders. Poisson reconstruction потребує нормалей у кожній точці; нормалі оцінюємо з локального neighborhood через PCA.
Нетривіально на мобілі: Open3D скомпільована для iOS/Android—близько 15 МБ бінарник, вимагає C++17 та працює у фоновому потоці. Результат—.obj файл з mesh.
LiDAR шлях: ARKit ARMeshAnchor
На iPhone з LiDAR найбільш надійний—ARKit:
let configuration = ARWorldTrackingConfiguration()
configuration.sceneReconstruction = .meshWithClassification
// У ARSession delegate
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
for anchor in anchors.compactMap({ $0 as? ARMeshAnchor }) {
let geometry = anchor.geometry
// geometry.vertices, geometry.faces, geometry.normals—готовий mesh
exportMesh(geometry: geometry, transform: anchor.transform)
}
}
ARMeshAnchor.geometry.vertices—ARGeometrySource з Metal буфером. Експорт у .obj:
func exportToOBJ(geometry: ARMeshGeometry, transform: simd_float4x4) -> String {
var obj = ""
let vertices = geometry.vertices
// Ітеруємо MTLBuffer прямо через withUnsafeBytes
vertices.buffer.contents().withMemoryRebound(to: SIMD3<Float>.self, capacity: vertices.count) { ptr in
for i in 0..<vertices.count {
let v = ptr[i]
let world = transform * SIMD4<Float>(v.x, v.y, v.z, 1)
obj += "v \(world.x) \(world.y) \(world.z)\n"
}
}
// Аналогічно для faces (indices)
return obj
}
Текстурування mesh—проектуємо відеокадр на mesh через UV-mapping. Окрема задача; без неї mesh залишиться сірим.
Серверна генерація: TripoSR та Zero123++
Для високої якості без LiDAR—серверний конвеєр. TripoSR (Stability AI, 2024): приймає одну фото, генерирує .obj за 0.5–1 секунду на A10. API:
func generateModel(from image: UIImage) async throws -> URL {
let imageData = image.jpegData(compressionQuality: 0.9)!
var request = URLRequest(url: URL(string: "https://api.example.com/triposr")!)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
// ... upload + poll
}
Результат—.glb файл, завантажується у RealityKit через Entity.loadModel(named:) або через ModelEntity(mesh: try .loadModel(contentsOf: url)).
AR-превью результату
Будь-який з варіантів закінчується однаково: показуємо 3D-об'єкт в AR через RealityKit/ARSCNView. Користувач може «поставити» об'єкт на реальну поверхню, повертати, змінити масштаб. Це закриває сценарій «подивитися як меблі виглядають у кімнаті» або «показати продукт в AR».
Експорт: .usdz для iOS (нативний формат Apple, підтримує AR Quick Look), .glb для Android та вебу.
Процес
Вибір архітектури під задачу (LiDAR/on-device depth/сервер), реалізація конвеєру захоплення та обробки, AR-превью, експорт у потрібні формати. Окремо—тестування на складних об'єктах: скляні поверхні, тонкі деталі, монотонні кольори.
Кошторис за часом
LiDAR-based сканування з експортом на iOS займає 3–5 тижнів. Повний конвеєр з on-device depth + серверною реконструкцією + AR-превью на обох платформах вимагає 8–14 тижнів.







