This is part of an app that communicates with one of my projects via BLE to reflect the position of the motor on the device using SceneKit. It took me a while to figure out, but it's working. However, the device lags trying to keep up with all the position updates. The position value is always being sent from my ESP32.
I've tried to move all of the pivots, translations, and linking of nodes to the makeUIView function and keep the piece of code that actually updates the position in the updateUIView, but that doesn't properly rotate the meshes how I want them to, ignoring the pivots and child nodes set.
I've verified that the app is able to see the motor position in realtime just updating text and not having to update the meshes.
I've also tried to implement a system where the Euler angles won't update unless the value being sent from the ESP is different than the last, but it seems that the app receives a float with more decimals that's being sent from the ESP. I'm not sure if this is the app or ESP fault.
Here is my code:
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
meshInstance562Node.eulerAngles = SCNVector3(x: 0, y: -0.01745329 * service.posititonValue, z: 0)
}
}
}
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)
}
}