0

I have an quite complex SwiftUI App which incoperates in on part the SceneKit Library.

Besides a lot of other functionalities (e.g. with one finger i drag and rotate objects in the scene), I want the user to control the camera via multi-touch gestures.

  • two-finger pinch: Zoom the camera in and out
  • two-finger pan: move the camera on x and y

But SwiftUI only has the MagnificationGesture, which I right now using as pinch for the zoom. I can't make it work to have the pan with two fingers.

I tried a lot of different implementation of SceneKit into the SwiftUI-World. Right now I have a working solution with a quite good manipulability of the scene. But gestures are a big problem. I was not able to have prober implementation of the UIKit-Gestures, however it may be possbile?

Since I need full control over the scene and the gestures, i cannot use "allow Camera Control".

Has anyone out here a solution or a hint for me?

Thanks!


Here snippets out of my code

View:

import Combine
import SwiftUI
import SceneKit

struct Canvas3DView: View {
    @StateObject private var canvas3DViewModel: Canvas3DViewModel
        
    @State private var dragOver = false
    @State private var dragPosition: CGPoint = .zero
    
    private let topBarHeight : CGFloat = 20
       
    var body: some View {
            ZStack { // 3D Canvas and PopUp Menus
                ZStack { // 3DCanvas with direct 2D HUD
                    // 3D Canvas
                    SceneView(
                                scene: Canvas3DViewModel.scene,
                                pointOfView: canvas3DViewModel.pointOfViewNode,
                                delegate: canvas3DViewModel.sceneRendererDelegate,
                                technique: canvas3DViewModel.getHightlighTechnique()
                        )
                    HStack{
                        Spacer()
                        if(self.canvas3DViewModel.isDebugModeOn) {
                            DebugView(c3VM: self.canvas3DViewModel)
                        }
                    }
                    // 2D HUD
                    VStack {
                        topBar
                            .padding([.bottom, .top], 5)
                            .background(Color.white.opacity(0.25))
                        
                        SpawnArea(c3VM: self.canvas3DViewModel)
                        
                        Spacer()
                            .padding([.leading, .trailing], 8)
                        bottomBar
                            .padding([.bottom, .top], 5)
                        
                    }
                    .font(.system(size: topBarHeight))
                    
                    FlexibleSheet(sheetMode: self.$canvas3DViewModel.showingTable, definedOffset: 80) {
                        SomeOtherView(canvas3DVM: self.canvas3DViewModel)
                    }
                }
                .gesture(self.canvas3DViewModel.exclusiveGesture)
                .onTapGesture { location in
                    _ = self.canvas3DViewModel.pick(atPoint: location, isTapAction: true)
                    dragPosition = location
                }
                .defersSystemGestures(on: .all)
                .ignoresSafeArea()
                .onDisappear(perform: {self.canvas3DViewModel.sceneRendererDelegate.onEachFrame = nil})
                .onAppear(perform: {self.canvas3DViewModel.sceneRendererDelegate.onEachFrame = self.canvas3DViewModel.onEachFrame})
                .coordinateSpace(name: Canvas3DViewModel.DRAGCOORDINATESPACE)
                .cornerRadius(15)
                .overlay(
                    RoundedRectangle(cornerRadius: 15)
                        .stroke(Color.systemBlue, lineWidth: 2)
                )
                .toast(message: self.canvas3DViewModel.toastMessage, isShowing: self.$canvas3DViewModel.showToast, duration: Toast.long)
                .padding()
                .navigationTitle("3D Scene " + (self.canvas3DViewModel.isDebugModeOn ? "!DebugMode!" : ""))

        }
    }

implementation gesture:

    public var magnify: some Gesture {
        MagnificationGesture()
            .onChanged{ [self] value in
                // preparing
                if(self.firstMagnify) {
                    self.firstMagnify = false
                    self.lastMagnifyValue = value
                }

                // execution
                currentPinchValue = pinchRange.clamp(value: currentPinchValue - value)
                self.pointOfViewNode.camera!.orthographicScale = currentPinchValue

                // post-work
                self.lastMagnifyValue = value
            }
            .onEnded{ value in
                self.firstMagnify = true
                self.lastMagnifyValue = 0
            }
    }
    
    public var exclusiveGesture: some Gesture {
        ExclusiveGesture(self.drag, self.magnify)
    }
HBE
  • 1
  • 2

0 Answers0