简体   繁体   English

如何使用 SwiftUI 更新 SceneKit 场景?

[英]How to update a SceneKit scene with SwiftUI?

I have a cylinder as SCNCylinder in a SCNScene in SceneKit and want to display it in a frame in SwiftUI.我在 SceneKit 的SCNScene中有一个圆柱体作为SCNCylinder ,并希望在 SwiftUI 的框架中显示它。 My goal is to rotate the cylinder by a angle of 180° or 90° (as the user chooses).我的目标是将圆柱体旋转 180° 或 90°(由用户选择)。 To take the input (of the angle of rotation) i have used Text() and onTapGesture{ .... } property in SwiftUI.为了获取输入(旋转角度),我在 SwiftUI 中使用了Text()onTapGesture{ .... }属性。 After I tap the text, the cylinder rotates but now I have two cylinders, one at the original position and one rotating at an desired angle.点击文本后,圆柱体旋转,但现在我有两个圆柱体,一个在原始位置,另一个以所需角度旋转。 I am not sure why this happens.我不确定为什么会发生这种情况。 I want the same cylinder to rotate, not a identical copy of that doing it.我想要同一个圆柱体旋转,而不是一个完全相同的副本。 I have connected the SwiftUI view and SceneKit view by using @State and @Binding .我已经使用@State@Binding连接了 SwiftUI 视图和 SceneKit 视图。

Here is my code :这是我的代码:

struct ContentView: View {
 @State var rotationAngle = 0

var body: some View {

    VStack{

        Text("180°").onTapGesture {
            self.rotationAngle = 180
        }

        Spacer()

        Text("90°").onTapGesture {
            self.rotationAngle = 90
        }

        SceneKitView(angle: $rotationAngle)
            .position(x: 225.0, y: 200)
            .frame(width: 300, height: 300, alignment: .center)

    }
  }
}

struct SceneKitView: UIViewRepresentable {

 @Binding var angle: Int

func degreesToRadians(_ degrees: Float) -> CGFloat {
    return CGFloat(degrees * .pi / 180)
}

func makeUIView(context: UIViewRepresentableContext<SceneKitView>) -> SCNView {

    let sceneView = SCNView()
    sceneView.scene = SCNScene()
    sceneView.allowsCameraControl = true
    sceneView.autoenablesDefaultLighting = true
    sceneView.backgroundColor = UIColor.white
    sceneView.frame = CGRect(x: 0, y: 10, width: 0, height: 1)

    return sceneView
}

func updateUIView(_ sceneView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {

        let cylinder = SCNCylinder(radius: 0.02, height: 2.0)
        let cylindernode = SCNNode(geometry: cylinder)
        cylindernode.position = SCNVector3(x: 0, y: 0, z: 0)
        cylinder.firstMaterial?.diffuse.contents = UIColor.green

        cylindernode.pivot = SCNMatrix4MakeTranslation(0, -1, 0)

        let inttofloat = Float(self.angle)

         let rotation = SCNAction.rotate(by: self.degreesToRadians(inttofloat), around: SCNVector3(1, 0, 0), duration: 5)

         cylindernode.runAction(rotation)

         sceneView.scene?.rootNode.addChildNode(cylindernode)

}
typealias UIViewType = SCNView

}

I want to have a single cylinder rotation at a given angle.我想以给定的角度进行单个圆柱体旋转。

The problem is, that updateUIView will be called several times.问题是, updateUIView 将被多次调用。 You can check this by adding a debug point there.您可以通过在那里添加调试点来检查这一点。 Because of that your cylinder will be added several times.因此,您的气缸将被添加多次。 So you can solve this by many ways...one way would be to delete all nodes in your sceneview before starting your animation like so:所以你可以通过多种方式解决这个问题......一种方法是在开始动画之前删除场景视图中的所有节点,如下所示:

func updateUIView(_ sceneView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {

    sceneView.scene?.rootNode.enumerateChildNodes { (node, stop) in
        node.removeFromParentNode()
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM