How to get SceneKit to update a nodes orientation based on values that update in real time without lagging or stuttering

Hi everyone

I'm making a small private app for my one of my engineering projects, a part of this app shows a 3D model of what it looks like in real life based on a position value of a joint that needs to be updated in real time.

I was able import a USDZ of the exact model of the project, and make the proper nodes that can rotate, however I run into a problem where SceneKit takes forever to update the node, I'm not sure if my code just needs optimizing or SceneKit is just not the framework to use when needing things in a 3D model to be updated in real time

I've confirmed that the device receives the values in realtime, it is just SceneKit that doesn't update the model in time

I'm not very good at explaining things so I put as much detail as I possibly can and hope my problem is clear, I'm also pretty new to swift and iOS development.

Here is the code I'm using


import SwiftUI
import SceneKit



struct ModelView2: UIViewRepresentable {

    @State private var eulerAngle: Float = 0.0
    
    @StateObject var service = BluetoothService()
    
    let sceneView = SCNView()
    
    func makeUIView(context: Context) -> SCNView {

        
        if let scene = SCNScene(named: "V4.usdz") {
            sceneView.scene = scene
            
            if let meshInstanceNode = scene.rootNode.childNode(withName: "MeshInstance", recursively: true),
               let meshInstance1Node = scene.rootNode.childNode(withName: "MeshInstance_1", recursively: true),
               let meshInstance562Node = scene.rootNode.childNode(withName: "MeshInstance_562", recursively: true) {
                
                // Rotate mesh instance around its own axis
                

                /*
                meshInstance562Node.eulerAngles = SCNVector3(x: 0, y: -0.01745329 * service.posititonValue, z: 0)
                */
                 
                print(meshInstance562Node.eulerAngles)
                
                
                
            }
            
        }
        sceneView.allowsCameraControl = true
        sceneView.autoenablesDefaultLighting = true
        
        return sceneView
        
    }
    func updateUIView(_ uiView: SCNView, context: Context) {
        if let scene = SCNScene(named: "V4.usdz") {
            sceneView.scene = scene
            
            if let meshInstanceNode = scene.rootNode.childNode(withName: "MeshInstance", recursively: true),
               let meshInstance1Node = scene.rootNode.childNode(withName: "MeshInstance_1", recursively: true),
               let meshInstance562Node = scene.rootNode.childNode(withName: "MeshInstance_562", recursively: true) {
             
                let boundingBox = meshInstance562Node.boundingBox
                let pivot = SCNMatrix4MakeTranslation(
                    boundingBox.min.x + (boundingBox.max.x - boundingBox.min.x) / 2,
                    boundingBox.min.y + (boundingBox.max.y - boundingBox.min.y) / 2,
                    boundingBox.min.z + (boundingBox.max.z - boundingBox.min.z) / 2
                )
                meshInstance562Node.pivot = pivot
                
                meshInstance562Node.addChildNode(meshInstanceNode)
                meshInstance562Node.addChildNode(meshInstance1Node)
                
                var original = SCNMatrix4Identity
                original = SCNMatrix4Translate(original, 182.85785, 123.54999, 17.857864) // Translate along the Y-axis
                
                meshInstance562Node.transform = original

                
                print(service.posititonValue)
                var buffer: Float = 0.0
                if service.posititonValue != buffer {
                    meshInstance562Node.eulerAngles = SCNVector3(x: 0, y: -0.01745329 * service.posititonValue, z: 0)
                    buffer = service.posititonValue
                }

                
                
            }
        }
    }
    func rotateNodeInPlace(node: SCNNode, duration: TimeInterval, angle: Float) {
        // Create a rotation action
        let rotationAction = SCNAction.rotateBy(x: 0, y: CGFloat(angle), z: 0, duration: duration)
        
        // Repeat the rotation action indefinitely
        // let repeatAction = SCNAction.repeatForever(rotationAction)
        
        // Run the action on the node
        node.runAction(rotationAction)
        print(node.transform)
        
    }
    func rotate(node: SCNNode, angle: Float) {
        node.eulerAngles = SCNVector3(x: 0, y: -0.01745329 * angle, z: 0)
    }
}
    
#Preview {
    ModelView2()
    
}



Replies

in UIViewRepresentable.updateUIView, you shouldn't be reloading the scene from disk on each update. that seems expensive

if that doesn't make an impact, I'm not familiar with using SceneKit with SwiftUI, so not sure how UIViewRepresentable.updateUIView works with/against a typical SceneRenderDelegate.updateAtTime implementation. fwiw.

  • When you mean reloading the scene, are you talking about the translations/pivots or whatever? if not how can I not do and only load the scene once?

Add a Comment