背景
在体验HelloWorld时,很好奇每个功能是怎么实现的,但是这个demo复用了很多功能、数据模型,刚开始理解起来就比较困难。所以我就先从功能点来看,将复用的功能、数据模型都剔除掉,保证单一功能能解藕单独运行。
环境
Xcode:15.1 beta
VisionOS:1.0
梳理功能
graph LR;
功能点-->A(设置光照);
style A fill:#bbf,color:#fff
click A "https://www.6hu.cc/post/7298690615046651943"
功能点-->B(手势转动地球)
style B fill:#bbf,color:#fff
click B "https://www.6hu.cc/post/7298765809290706983"
功能点-->C(地球自转)
style C fill:#bbf,color:#fff
click C "https://www.6hu.cc/post/7298775642261569575"
功能点-->D(地球跟随鼠标拖动)
功能点-->E(卫星围绕地球转动)
功能点-->F(月球围绕地球转动)
功能点-->G(沉浸式与窗口之间的切换)
地球跟随鼠标拖动
在这里可以明显看到窗口是有边界的,触碰到边界时,整个模型都很会切掉。如果我们在加载模型后,看不到效果,要考虑下是不是超出窗口了,适当的调整模型的位置,窗口的大小。
import SwiftUI
import RealityKit
import RealityKitContent
struct EarthPlacement: View {
var body: some View {
RealityView { content in
guard let earth = await RealityKitContent.entity(named: "Globe") else {
return
}
content.add(earth)
earth.setSunlight(intensity: 14)
earth.scale = SIMD3(repeating: 0.3)
}
.placementGestures(initialPosition: Point3D([450,300.0,100.0]))
}
}
#Preview {
EarthPlacement()
}
1. 加载3D资源
和手势转动地球一样,资源必须要添加一个InputComponent
,这样才可以添加手势。
![[VisionOS] 拆分HelloWorld的功能点 - 地球跟随鼠标拖动 [VisionOS] 拆分HelloWorld的功能点 - 地球跟随鼠标拖动](https://www.6hu.cc/wp-content/uploads/2023/11/b85eefcb092d5a5e512d2fe0a5c32fe6.webp)
2. 添加手势
import SwiftUI
import RealityKit
extension View {
/// Listens for gestures and places an item based on those inputs.
func placementGestures(
initialPosition: Point3D = .zero,
axZoomIn: Bool = false,
axZoomOut: Bool = false
) -> some View {
self.modifier(
PlacementGesturesModifier(
initialPosition: initialPosition,
axZoomIn: axZoomIn,
axZoomOut: axZoomOut
)
)
}
}
/// A modifier that adds gestures and positioning to a view.
private struct PlacementGesturesModifier: ViewModifier {
var initialPosition: Point3D
var axZoomIn: Bool
var axZoomOut: Bool
@State private var scale: Double = 1
@State private var startScale: Double? = nil
@State private var position: Point3D = .zero
@State private var startPosition: Point3D? = nil
func body(content: Content) -> some View {
content
.onAppear {
position = initialPosition
}
.scaleEffect(scale)
.position(x: position.x, y: position.y)
.offset(z: position.z)
// Enable people to move the model anywhere in their space.
.simultaneousGesture(DragGesture(minimumDistance: 0.0, coordinateSpace: .global)
.handActivationBehavior(.pinch)
.onChanged { value in
if let startPosition {
let delta = value.location3D - value.startLocation3D
position = startPosition + delta
} else {
startPosition = position
}
}
.onEnded { _ in
startPosition = nil
}
)
// Enable people to scale the model within certain bounds.
.simultaneousGesture(MagnifyGesture()
.onChanged { value in
if let startScale {
scale = max(0.1, min(3, value.magnification * startScale))
} else {
startScale = scale
}
}
.onEnded { value in
startScale = scale
}
)
.onChange(of: axZoomIn) {
scale = max(0.1, min(3, scale + 0.2))
startScale = scale
}
.onChange(of: axZoomOut) {
scale = max(0.1, min(3, scale - 0.2))
startScale = scale
}
}
}
和手势转动地球类似,添加了DragGesture
手势,在onChanged
、onEnded
中改变position
。MagnifyGesture
放大手势,我暂时是没有用,模拟器也不知道怎么模拟。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。