I am trying to load a .sdf (Simulation Description Format) file and display it as a 3D model using Swift, UIKit, and SceneKit on iPad and macOS only. However, SceneKit does not directly support loading .sdf files.
I attempted to parse the .sdf file using an XML parser, but I wasn’t successful. I would prefer to load the .sdf file without converting it to another format, if possible. As I am new to Swift, I need guidance on how to achieve this
What I’ve tried:
Used an XML parser to try and parse the .sdf file.
Searched for any SceneKit extensions or libraries that might support .sdf files directly.
Environment:
Swift
UIKit
SceneKit
below is my codes
import UIKit
import SceneKit
import PhyKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
// Load and display the SDF model
if let sdfURL = Bundle.main.url(forResource: "model", withExtension: "sdf") {
loadAndDisplaySDFModel(from: sdfURL)
}
}
func loadAndDisplaySDFModel(from url: URL) {
// Create a new SceneKit scene
let scene = SCNScene()
// Parse the SDF file and add nodes to the scene
if let sdfNodes = parseSDFFile(at: url) {
for node in sdfNodes {
scene.rootNode.addChildNode(node)
}
}
// Create a SceneKit view and set its scene
let scnView = SCNView(frame: self.view.frame)
scnView.scene = scene
// Add the SceneKit view to the view controller's view
self.view.addSubview(scnView)
// Allow the user to manipulate the camera
scnView.allowsCameraControl = true
scnView.autoenablesDefaultLighting = true
scnView.backgroundColor = .white
}
func parseSDFFile(at url: URL) -> [SCNNode]? {
// Read the file content
guard let data = try? Data(contentsOf: url) else {
print("Failed to read SDF file")
return nil
}
// Parse the XML
let parser = XMLParser(data: data)
let sdfParserDelegate = SDFParserDelegate()
parser.delegate = sdfParserDelegate
if parser.parse() {
return sdfParserDelegate.nodes
} else {
print("Failed to parse SDF file")
return nil
}
}
}
class SDFParserDelegate: NSObject, XMLParserDelegate {
var nodes: [SCNNode] = []
var currentElement: String = ""
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
currentElement = elementName
if elementName == "box" {
let size = attributeDict["size"]?.split(separator: " ").map { CGFloat(Double($0) ?? 1.0) } ?? [1.0, 1.0, 1.0]
let box = SCNBox(width: size[0], height: size[1], length: size[2], chamferRadius: 0.0)
let material = SCNMaterial()
material.diffuse.contents = UIColor.red
box.materials = [material]
let boxNode = SCNNode(geometry: box)
nodes.append(boxNode)
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
// Handle found characters if needed
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
currentElement = ""
}
}
Thank you for your help!