如何在 SwiftUI SceneView 中水平旋转对象

问题描述 投票:0回答:2

我正在 SwiftUI 中使用

SceneView
加载 3D 对象:

SceneView(
            scene: scene,
            pointOfView: cameraNode,
            options: [.autoenablesDefaultLighting]
        )

我已从

.allowsCameraControl
中删除了
options
属性以手动处理手势。我希望能够水平旋转对象。在 UIKit 中,我可以使用
UIPanGestureRecognizer
来做到这一点,如下所示:

func rotateObject(_ gesture: UIPanGestureRecognizer) {
    var currentAngleY: Float = 0.0
    guard let nodeToRotate = scene?.rootNode else { return }
    let translation = gesture.translation(in: gesture.view!)
    var newAngleY = (Float)(translation.x) * (Float)(Double.pi) / 180.0
    newAngleY += currentAngleY
    nodeToRotate.eulerAngles.y = newAngleY
    if(gesture.state == .ended) { currentAngleY = newAngleY }
}

但是在 SwiftUI 中我不确定如何做到这一点,任何帮助将不胜感激。

swift swiftui scenekit sceneview
2个回答
0
投票

我刚刚弄清楚这一点,部分原因是我对无用的自我推销答案感到非常恼火。

基本上,您只需将 DragGesture 添加到 SceneView,然后使用拖动位置的某个因子,这意味着某个常数因子乘以位置增量(平移的宽度和高度)并将其转换为以弧度为单位的角度。在这里,我不知道距对象的视口距离,所以我只使用拖动移动点数的 1/100,将其用作度数,然后除以 2 * Pi 转换为弧度。

如果你想移动某个指定的距离,你可能可以计算出来,但通常我认为人们只想要一些拖动长度与角度的比率。

在手势更改期间,您希望将旋转重置为开始的位置,否则行为会有点奇怪(除非您越过起点,否则旋转不会改变方向)

最后,您希望将其保存为最后一次旋转,以便下次看到拖动时可以从那里开始。

在 SwiftUI(SwiftUI 4)中:

@State private var lastRotation: SCNVector4 = .init()

var body: some View {
    VStack {
        SceneView(scene: scene, preferredFramesPerSecond: 30 )
            .gesture( DragGesture()
                .onChanged({ dgv in
                    let locationXDelta = dgv.translation.width
                    let locationYDelta = dgv.translation.height
                    
                    let dragSensitivityFactor = 0.01
                    
                    let rX = locationXDelta * dragSensitivityFactor / .pi * 2
                    let rY = locationYDelta * dragSensitivityFactor / .pi * 2
                    scene.rootNode.rotation = lastRotation
                    self.scene.rootNode.simdLocalRotate(by: .init(angle: Float(rX), axis: .init(x: 0, y: 1, z: 0)))
                    self.scene.rootNode.simdLocalRotate(by: .init(angle: Float(rY), axis: .init(x: 1, y: 0, z: 0)))
                })
                    .onEnded({ dgv in
                        self.lastRotation = scene.rootNode.rotation
                    }))
    }
    .padding()
}

-1
投票

您可以在这篇文章中找到解决方案背后的完整故事。 SwiftUI 中的代码。

Circle()
.fill(Color.white)
.opacity(0.1)
.frame(width: 256, height: 256, alignment: .center)

.gesture(
    DragGesture(minimumDistance: 30, coordinateSpace: .global)
        .onChanged { gesture in
            startWalking.send(gesture.translation)
        }
        .onEnded { _ in
            stopWalking.send(true)
        }
)

您可以使用拖动手势和订阅在 sceneView 和 SwiftUI 界面之间传输信息。

© www.soinside.com 2019 - 2024. All rights reserved.