求移动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
- Load the model cleanly: For each file type, use methods that avoid importing animation data automatically.
- Strip animation (if needed): For .dae files (which might contain animation data), extract only the geometry and node transforms, leaving animations behind.
- 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: .doNotPlayand 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




