iOS 18 RealityView:如何通过触摸拖拽手势精准移动Entity
RealityView实现2D拖拽3D实体精准跟随手指
在iOS 18的RealityView中,直接通过手势的translation累加固定比例移动实体,会因忽略相机投影关系导致无法精准对应手指位置。正确的做法是通过射线与固定平面相交,将2D触摸点映射到3D空间坐标,让实体跟随交点移动。
完整实现代码
import SwiftUI import RealityKit struct ContentView: View { @State private var box = Entity() // 定义实体拖拽时依附的平面Z坐标(可根据场景调整,默认相机在z=0,此处设为-1让实体处于相机前方) private let targetPlaneZ: Float = -1.0 var body: some View { RealityView { content in let boxMesh = ModelEntity( mesh: .generateBox(size: 0.25), materials: [SimpleMaterial(color: .blue, isMetallic: true)] ) box.addChild(boxMesh) box.position.z = targetPlaneZ // 让实体初始就在目标平面上 content.add(box) } .gesture(dragGesture) } private var dragGesture: some Gesture { DragGesture() .onChanged { value in guard let realityView = value.view as? RealityView else { return } // 获取场景中的相机实体 let camera = realityView.camera ?? realityView.scene.cameras.first! // 转换触摸点为RealityKit归一化坐标(原点在左下角) let viewSize = realityView.bounds.size let normalizedTouchPoint = CGPoint( x: value.location.x / viewSize.width, y: 1 - (value.location.y / viewSize.height) // 翻转y轴适配坐标空间差异 ) // 生成从相机穿过触摸点的射线 let ray = camera.generateRay(fromScreenPosition: normalizedTouchPoint, viewportSize: viewSize) // 计算射线与目标平面的交点 if let intersection = ray.intersection(withPlaneAt: [0, 0, targetPlaneZ], normal: [0, 0, 1]) { box.position = intersection.position } } .onEnded { _ in box.position = [0, 0, targetPlaneZ] } } } // 扩展Ray,实现射线与平面的交点计算 extension Ray { func intersection(withPlaneAt planePosition: SIMD3<Float>, normal: SIMD3<Float>) -> (position: SIMD3<Float>, distance: Float)? { let denominator = dot(normal, direction) guard abs(denominator) > 0.0001 else { return nil } // 射线与平面平行,无交点 let t = dot(planePosition - origin, normal) / denominator guard t >= 0 else { return nil } // 忽略相机后方的交点 let intersectionPos = origin + direction * t return (intersectionPos, t) } }
关键逻辑说明
- 坐标空间适配:SwiftUI触摸坐标原点在顶部,RealityKit屏幕坐标原点在左下角,因此需要翻转y轴的归一化值,确保射线方向正确。
- 射线生成:利用相机的
generateRay方法,生成从相机位置出发、穿过触摸点的3D射线,这是映射2D到3D的核心。 - 平面交点计算:通过数学计算射线与固定Z平面的交点,实体移动到该交点位置,保证手指位置与实体3D位置精准对应。
- 初始位置对齐:将实体初始Z坐标设置为目标平面的Z值,避免拖拽时出现位置跳变。
内容的提问来源于stack exchange,提问作者Ostoura
相关产品推荐
相关产品推荐

