我已经尝试创建一个 ARView 两天多了,它可以随时间记录相机在空间中的位置,然后将其保存到关键帧文件中。基本上,我想创建一个应用程序,让您记录虚拟相机运动,然后可以在 3d 应用程序中使用,如
Autodesk Maya
或 Cinema4D
来驱动相机。首选文件输出将是任何可以容纳相机对象并随时间对其进行动画处理的对象(或者也可以是随时间移动的对象,然后我可以将相机作为父对象)。
这是我的代码,抱歉它有点混乱,我尝试了很多不同的东西......基本上我尝试记录设备位置和旋转,然后将它保存到 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)
}
}
}
}
如果有完全不同的做法,也请分享,我提前感谢大家的帮助!
为了将数据写入文本文件,我使用了 4x4 转换矩阵的 JSON 数据编码。点击
Record Transform Values
按钮后,数据立即开始写入toMaya.txt
文件。为了方便,我把矩阵的16个值全部放在屏幕上
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) { }
}
toMaya.txt
文件中的嵌套数组中的数据可以使用常规 Python 或 MEL 脚本轻松读取。
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
文件在以下目录中等着我:
file:///var/mobile/Containers/Data/Application/7C675F52-C78B-4252-98B5-3EBD37A3F832/Documents/toMaya.txt