You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让RealityKit模型绕任意点而非中心点旋转?

在visionOS中实现对象绕选中点旋转

要让RealityView中的对象绕触摸选中的点(比如立方体边角)旋转,核心是通过射线检测获取命中点,再调整对象的变换逻辑,步骤如下:

1. 捕获触摸命中的精确点

在拖拽手势的回调里,利用RealityView的射线检测能力,从触摸位置发射射线,命中目标对象时记录世界空间下的命中坐标。

2. 转换坐标获取本地偏移

将世界空间的命中点转换为目标对象本地空间的坐标,得到该点相对于对象中心点的偏移量,后续旋转时需要基于这个偏移来调整位置。

3. 组合平移与旋转实现绕点旋转

旋转时,先将对象平移,让选中点对齐到世界空间的原命中位置,执行旋转后再平移回对应位置,确保旋转轴心始终是用户选中的点。

代码示例

struct RotateAroundHitPointView: View {
    @State private var targetEntity: Entity?
    @State private var hitWorldPosition: SIMD3<Float> = .zero
    @State private var initialLocalOffset: SIMD3<Float> = .zero
    @State private var initialRotation: simd_quatf = .init(angle: 0, axis: .zero)

    var body: some View {
        RealityView { content in
            // 加载Reality Composer Pro创建的场景
            guard let scene = try? await Entity(named: "YourScene", in: .main) else { return }
            content.add(scene)
            // 替换为你场景中目标对象的名称
            targetEntity = scene.findEntity(named: "Cube")
        }
        .gesture(
            DragGesture()
                .onChanged { gestureValue in
                    guard let entity = targetEntity else { return }
                    
                    // 射线检测获取命中点
                    let raycastResults = content.raycast(
                        from: gestureValue.location,
                        allowing: .entity,
                        alignmentTarget: .any
                    )
                    if let hit = raycastResults.first, hit.entity == entity {
                        hitWorldPosition = hit.position
                        // 将世界坐标转为对象本地坐标,记录偏移
                        initialLocalOffset = entity.convert(position: hitWorldPosition, from: nil)
                        initialRotation = entity.transform.rotation
                    }
                    
                    // 计算拖拽产生的旋转角度(这里以绕Y轴为例)
                    let rotationAngle = Float(gestureValue.translation.width / 80)
                    let rotationAxis = SIMD3<Float>(0, 1, 0)
                    let updatedRotation = simd_quatf(angle: rotationAngle, axis: rotationAxis) * initialRotation
                    
                    // 计算对象新位置:让选中点保持在原世界位置
                    let newWorldPosition = hitWorldPosition - entity.convert(position: initialLocalOffset, from: entity)
                    // 应用新的变换
                    entity.transform = Transform(
                        scale: entity.transform.scale,
                        rotation: updatedRotation,
                        translation: newWorldPosition
                    )
                }
        )
    }
}

注意事项

  • 射线检测参数allowing设为.entity可确保只命中目标实体,避免误触场景中其他对象;
  • 若目标对象有父节点,坐标转换时要注意空间层级,确保convert方法的from参数正确;
  • 如需支持多手指旋转,可替换为RotationGesture,核心逻辑保持一致,仅角度计算改为手势的旋转量。

内容的提问来源于stack exchange,提问作者Mark Tamotsu Kinoshita

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 02:12:34