Nicode
Nicode

Reputation: 103

SwiftUI Rotation using drag gesture

I try to rotate Model3D for Apple Vision Pro with a DragGesture. To do it I just add degrees to an Angle object, and it works fine but it only rotate left or right not both.

So I've been able to detect left / right gesture and add or remove degrees to the angle. But since there the rotation isn't working well and direction may change to right while I'm still dragging left.

@State var rotation: Angle = .zero
@State var previousLocation: CGPoint = .zero
var rotateGesture: some Gesture {
    DragGesture()
        .targetedToAnyEntity()
        .onChanged { value in
            if (previousLocation == .zero) {
                previousLocation = value.location
            }
            
            if (previousLocation.x > value.location.x) {
                rotation.degrees -= 1.0
            } else {
                rotation.degrees += 1.0
            }
            
            previousLocation = value.location
        }
}

Rotation is applied to 3d model like this

.gesture(rotateGesture)
.rotation3DEffect(rotation, axis: .y)

Does anyone knows what's wrong or what I missed ?

Upvotes: 1

Views: 666

Answers (1)

Andy Jazz
Andy Jazz

Reputation: 58133

It seems your problem is related to gimbal lock. To prevent the behavior you are experiencing, use the model's orientation property in RealityView rather than .rotation3DEffect() modifier for Model3D view.

import SwiftUI
import RealityKit

struct ContentView: View {
    @State var rotation: Angle = .zero
    let cube = ModelEntity(mesh: .generateBox(size: 0.25))
    
    var dragGesture: some Gesture {
        DragGesture()
            .targetedToAnyEntity()
            .onChanged { value in
                Task { @MainActor in
                    if value.translation.width < 0 {
                        rotation.degrees -= 5.0
                    }
                    if value.translation.width > 0 {
                        rotation.degrees += 5.0
                    }
                }
            }
    }
    var body: some View {
        RealityView { rvc in
            rvc.add(cube)
        } update: { rvc in
            if let model = rvc.entities.first as? ModelEntity {
                model.generateCollisionShapes(recursive: false)
                model.components.set(InputTargetComponent())
                model.orientation = .init(angle: -Float(rotation.radians), 
                                           axis: [0, 0, 1])
            }
        }.gesture(dragGesture)
    }
}

Upvotes: 1

Related Questions