swift 如何记录ARCamera随时间变化的位置和旋转并保存到文件中?

jum4pzuy  于 2023-02-21  发布在  Swift
关注(0)|答案(1)|浏览(145)

我已经尝试创建一个ARView两天多了,它可以记录相机在空间中的位置,然后保存到一个关键帧文件中。基本上,我想创建一个应用程序,让你记录虚拟相机的运动,然后可以在3d应用程序中使用,如Autodesk MayaCinema4D,以驱动相机。首选的文件输出将是任何可以容纳摄影机对象并随时间对其设置动画的对象(或者也可以是随时间移动的对象,然后我可以将摄影机设置为该对象的父对象)。
这是我的代码,很抱歉它有点混乱,我已经尝试了很多不同的东西...基本上我试图记录设备的位置和旋转,然后保存到一个MDL对象,但不知何故,它没有动画。我也尝试了多种不同的文件类型(其中一些不支持关键帧动画,所以没有帮助,但据我所知,Alembic做)

import SwiftUI
import ARKit
import RealityKit
import ModelIO

struct ARViewContainer: UIViewRepresentable {
    let session = ARSession()
    let delegate = MySessionDelegate()
    
    func makeUIView(context: Context) -> ARView {
        // Set up the ARView with session
        let arView = ARView(frame: .zero)
        let boxAnchor = try! Experience.loadBox()
        arView.scene.anchors.append(boxAnchor)
        arView.session.delegate = delegate // assign delegate to the session
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        // Update the ARView if needed
    }
    
    func startARSession() {
        // Start the ARSession
        let configuration = ARWorldTrackingConfiguration()
        configuration.planeDetection = [.horizontal, .vertical]
        session.run(configuration, options: [])
    }
    
    func stopARSession() {
        // Stop the ARSession
        session.pause()
    }
}

class MySessionDelegate: NSObject, ARSessionDelegate {
    var object: MDLMesh?
    let asset = MDLAsset()
    let cameraTransform = MDLTransform()
    var documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    
    func session(_ session: ARSession, didUpdate frame: ARFrame) {
            // Get the camera position and orientation for the current frame
            let transform = frame.camera.transform
            let rotation = frame.camera.eulerAngles
            let position = transform.columns.3
            let elapsedTime = frame.timestamp
            cameraTransform.setTranslation(position[SIMD3(0,1,2)], forTime: elapsedTime)
            cameraTransform.setRotation(rotation, forTime: elapsedTime)
            print("Camera Transform: \(cameraTransform.matrix)")
    }

}

struct Camera: View {
    var body: some View {
        VStack {
            ARViewContainer().onAppear(perform: ARViewContainer().startARSession)
                .onDisappear(perform: ARViewContainer().stopARSession)
            Button("Export Recording") {
                // Create an MDLAsset with a box representing the camera transform
                let object = MDLMesh(boxWithExtent: .init(0.1, 0.1, 0.1), segments: .init(10, 10, 10), inwardNormals: false, geometryType: .triangles, allocator: nil)
                object.name = "Camera Transform"
                object.transform = MySessionDelegate().cameraTransform
                
                let asset = MDLAsset()
                asset.add(object)
                
                // Export the MDLAsset to a file
                let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
                let fileURL = documentsDirectory.appendingPathComponent("recording.abc")
                try! asset.export(to: fileURL)
            }
        }
        
    }
}

如果有完全不同的做法,也请大家分享,提前感谢大家的任何帮助!

6ie5vjzr

6ie5vjzr1#

每秒记录60个4x4变换矩阵

为了将数据写入文本文件,我使用了4x4转换矩阵的JSON数据编码(即使用复数转换)。单击Record Transform Values按钮后,数据立即开始写入toMaya.txt文件。 屏幕上的矩阵(我在iPad上测试了这个,所以买一个屏幕更大的设备)。
使用常规Python或MEL脚本可以轻松读取toMaya.txt文件中nested lists的数据。请查看嵌套的外观。 为浮点型。

[x0,y0,z0,w0]是第一矩阵列,[x1,y1,z1,w1]是第二矩阵列,等等。
下面是代码:

import SwiftUI
import RealityKit
import Combine

struct ARViewContainer : UIViewRepresentable {
    @Binding var arView: ARView

    func makeUIView(context: Context) -> ARView { return arView }
    func updateUIView(_ view: ARView, context: Context) { }
}
struct ContentView : View {
    
    @State private var arView = ARView(frame: .zero)
    @State private var subs: [AnyCancellable] = []
    @State private var array: [[[Float]]] = [[ [1,0,0,0], [0,1,0,0],
                                               [0,0,1,0], [0,0,0,1] ]]
    
    let url = FileManager.default.urls(for: .documentDirectory,
                                        in: .userDomainMask)[0]
                                 .appendingPathComponent("toMaya.txt")
                                 
    var body: some View {
        ZStack {
            ARViewContainer(arView: $arView).ignoresSafeArea()
            HStack {
                VStack {
                    Text("\(array.last![0][0])").foregroundColor(.white)
                    Text("\(array.last![0][1])").foregroundColor(.white)
                    Text("\(array.last![0][2])").foregroundColor(.white)
                    Text("\(array.last![0][3])").foregroundColor(.white)
                }
                VStack {
                    Text("\(array.last![1][0])").foregroundColor(.white)
                    Text("\(array.last![1][1])").foregroundColor(.white)
                    Text("\(array.last![1][2])").foregroundColor(.white)
                    Text("\(array.last![1][3])").foregroundColor(.white)
                }
                VStack {
                    Text("\(array.last![2][0])").foregroundColor(.white)
                    Text("\(array.last![2][1])").foregroundColor(.white)
                    Text("\(array.last![2][2])").foregroundColor(.white)
                    Text("\(array.last![2][3])").foregroundColor(.white)
                }
                VStack {
                    Text("\(array.last![3][0])").foregroundColor(.white)
                    Text("\(array.last![3][1])").foregroundColor(.white)
                    Text("\(array.last![3][2])").foregroundColor(.white)
                    Text("\(array.last![3][3])").foregroundColor(.white)
                }
            }
            VStack {
                Button("Record Transform Values") {
                    DispatchQueue.main.async {
                        arView.scene.subscribe(to: SceneEvents.Update.self) { _ in
                                                        
                            let col = arView.cameraTransform.matrix.columns
                            
                            let mtx: [[Float]] = [
                                        [col.0.x, col.0.y, col.0.z, col.0.w],
                                        [col.1.x, col.1.y, col.1.z, col.1.w],
                                        [col.2.x, col.2.y, col.2.z, col.2.w],
                                        [col.3.x, col.3.y, col.3.z, col.3.w]
                            ]                                
                            array.append(mtx)
                            
                            if let data = try? JSONEncoder().encode(self.array) {

                                guard let str = String(data: data, encoding: .ascii)
                                else { return }
                                
                                do {
                                    try str.write(to: url, 
                                          atomically: true, 
                                            encoding: .ascii)
                                    print(url)
                                } catch {
                                    print(error.localizedDescription)
                                }
                            }
                        }.store(in: &subs)
                    }
                }
                Spacer()
            }
            VStack {
                Spacer()
                Text("\(array.count)").foregroundColor(.white)
            }
        }
    }
}

我的toMaya.txt文件在下面的***debugging***目录中等待我:

file:///var/mobile/Containers/Data/Application/7C675F52-C78B-4252-98B5-3EBD37A3F832/Documents/toMaya.txt

相关问题