Created
February 4, 2024 10:20
-
-
Save elkraneo/5ccd1e1be8f29844008fc5a09748350b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import RealityKit | |
import RealityKitContent | |
import SwiftUI | |
struct ManipulationState { | |
var active = false | |
var transform: AffineTransform3D = .identity | |
} | |
struct ContentView: View { | |
@State private var showImmersiveSpace = false | |
@State private var immersiveSpaceIsShown = false | |
@Environment(\.openImmersiveSpace) var openImmersiveSpace | |
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace | |
@GestureState var manipulationState = ManipulationState() | |
var body: some View { | |
VStack { | |
Model3D(named: "Scene", bundle: realityKitContentBundle) | |
.padding(.bottom, 50) | |
.scaleEffect(manipulationState.transform.scale.width) | |
.rotation3DEffect(manipulationState.transform.rotation ?? .identity) | |
.offset( | |
x: manipulationState.transform.translation.x, | |
y: manipulationState.transform.translation.y | |
) | |
.offset(z: manipulationState.transform.translation.z) | |
.animation(.spring, value: manipulationState.transform) | |
.gesture( | |
manipulationGesture.updating($manipulationState) { value, state, transaction in | |
state.active = true | |
state.transform = value | |
} | |
) | |
Text("Hello, world!") | |
Toggle("Show Immersive Space", isOn: $showImmersiveSpace) | |
.toggleStyle(.button) | |
.padding(.top, 50) | |
} | |
.padding() | |
.onChange(of: showImmersiveSpace) { _, newValue in | |
Task { | |
if newValue { | |
switch await openImmersiveSpace(id: "ImmersiveSpace") { | |
case .opened: | |
immersiveSpaceIsShown = true | |
case .error, .userCancelled: | |
fallthrough | |
@unknown default: | |
immersiveSpaceIsShown = false | |
showImmersiveSpace = false | |
} | |
} else if immersiveSpaceIsShown { | |
await dismissImmersiveSpace() | |
immersiveSpaceIsShown = false | |
} | |
} | |
} | |
} | |
} | |
#Preview(windowStyle: .automatic) { | |
ContentView() | |
} | |
//MARK: - Manipulation Gesture | |
// Gesture combining dragging, magnification, and 3D rotation all at once. | |
var manipulationGesture: some Gesture<AffineTransform3D> { | |
DragGesture() | |
.simultaneously(with: MagnifyGesture()) | |
.simultaneously(with: RotateGesture3D()) | |
.map { gesture in | |
let (translation, scale, rotation) = gesture.components() | |
return AffineTransform3D( | |
scale: scale, | |
rotation: rotation, | |
translation: translation | |
) | |
} | |
} | |
// Helper for extracting translation, magnification, and rotation. | |
extension SimultaneousGesture< | |
SimultaneousGesture<DragGesture, MagnifyGesture>, | |
RotateGesture3D | |
>.Value { | |
func components() -> (Vector3D, Size3D, Rotation3D) { | |
let translation = self.first?.first?.translation3D ?? .zero | |
let magnification = self.first?.second?.magnification ?? 1 | |
let size = Size3D(width: magnification, height: magnification, depth: magnification) | |
let rotation = self.second?.rotation ?? .identity | |
return (translation, size, rotation) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment