You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

求移动SDK/代码:将.ply/.stl/.dae转为SceneKit支持的.scn格式并保存

Convert .ply/.dae/.stl to .scn (SceneKit) Without Unwanted Animations

Hey there, let's figure out how to convert those .ply, .dae, .stl files to SceneKit's .scn format—no extra animations attached—and save the result to your app's documents directory. The key here is to use native SceneKit APIs to strip out any unwanted animation data and export a clean .scn file, avoiding the quirks you ran into with AssimpKit.

Core Approach

  1. Load the model cleanly: For each file type, use methods that avoid importing animation data automatically.
  2. Strip animation (if needed): For .dae files (which might contain animation data), extract only the geometry and node transforms, leaving animations behind.
  3. Export to .scn: Create a fresh SceneKit scene, add your cleaned-up model, and save it to the documents directory.

Step-by-Step Code Implementation

1. Load the Model Without Animations

This function handles all three file types using native SceneKit, ensuring no unwanted animations come along for the ride:

import SceneKit

func loadCleanModel(from url: URL) -> SCNNode? {
    let fileExtension = url.pathExtension.lowercased()
    
    switch fileExtension {
    case "dae":
        // Load .dae with animation import disabled
        guard let sceneSource = SCNSceneSource(
            url: url,
            options: [.animationImportPolicy: SCNSceneSource.AnimationImportPolicy.doNotPlay]
        ), let scene = sceneSource.scene(options: nil) else {
            print("Failed to load .dae file")
            return nil
        }
        
        // Create a clean root node, only keeping geometry and transforms
        let cleanRoot = SCNNode()
        for childNode in scene.rootNode.childNodes {
            guard let geometry = childNode.geometry else { continue }
            let strippedNode = SCNNode(geometry: geometry)
            strippedNode.transform = childNode.transform
            cleanRoot.addChildNode(strippedNode)
        }
        return cleanRoot
        
    case "ply", "stl":
        // Directly load .ply/.stl as raw geometry (these formats don't support animation anyway)
        do {
            let modelData = try Data(contentsOf: url)
            let geometry = try SCNGeometry(data: modelData)
            return SCNNode(geometry: geometry)
        } catch {
            print("Failed to load \(fileExtension) file: \(error.localizedDescription)")
            return nil
        }
        
    default:
        print("Unsupported file format: \(fileExtension)")
        return nil
    }
}

2. Export the Clean Model to .scn

This function takes your cleaned-up model node, adds it to a new SceneKit scene, and saves it to the app's documents directory:

func exportModelToSCN(_ modelNode: SCNNode, fileName: String) -> URL? {
    // Create a fresh scene for export
    let exportScene = SCNScene()
    exportScene.rootNode.addChildNode(modelNode)
    
    // Get the app's documents directory URL
    guard let docsDirectory = FileManager.default.urls(
        for: .documentDirectory,
        in: .userDomainMask
    ).first else {
        print("Could not access documents directory")
        return nil
    }
    
    let exportURL = docsDirectory.appendingPathComponent("\(fileName).scn")
    
    // Export the scene
    do {
        try exportScene.write(
            to: exportURL,
            options: [.sceneExportPreset: SCNSceneExportPreset.original]
        )
        print("Successfully exported to: \(exportURL.path)")
        return exportURL
    } catch {
        print("Export failed: \(error.localizedDescription)")
        return nil
    }
}

3. How to Use These Functions

Here's a quick example of putting it all together:

// Example: Load a .ply file from your app bundle
guard let modelURL = Bundle.main.url(forResource: "my3dModel", withExtension: "ply") else {
    print("Model file not found in bundle")
    return
}

// Load the clean model
guard let cleanModelNode = loadCleanModel(from: modelURL) else {
    print("Failed to load clean model")
    return
}

// Export to documents directory with the name "converted_model"
_ = exportModelToSCN(cleanModelNode, fileName: "converted_model")

Key Notes

  • No AssimpKit Needed: For .ply and .stl, SceneKit can load these directly as raw geometry—no third-party libraries required, which avoids the animation issues you faced with AssimpKit.
  • .dae Handling: By loading the .dae with animationImportPolicy: .doNotPlay and stripping out everything except geometry and transforms, you ensure no unwanted animations make it into your .scn file.
  • Sandbox Permissions: On iOS, your app automatically has access to its own documents directory, so no extra permissions are needed here.

内容的提问来源于stack exchange,提问作者crazyidev

火山引擎 最新活动