You need to enable JavaScript to run this app. ARKit开发:如何将SCNTorus节点置于相机前方对齐显示正圆
优惠活动
大模型
产品
解决方案
定价
更多

ARKit开发:如何将SCNTorus节点置于相机前方对齐显示正圆

问题根因
  • 你之前用node.eulerAngles.x = .pi / 2的方案,只是刚好匹配了竖屏持机、相机水平朝向这一个静态场景下的Torus朝向。
  • 当设备在空间中移动、俯仰、屏幕滚转时,相机自身的旋转角度是实时变化的,硬编码的固定旋转值无法和相机当前的成像平面方向对齐,Torus的环面就会和相机视线形成夹角,最终从正圆变成椭圆。
实现方案

要让固定在hitTest锚点上的Torus永远显示为正圆,不需要做复杂的矩阵计算,直接对齐相机的实时旋转即可:

  • SCNTorus的默认几何规则是:环面位于节点本地坐标系的XY平面,环的中心轴沿本地Z方向。
  • SceneKit相机节点的默认坐标系规则是:Z轴垂直于相机成像平面,指向相机视线的正前方。

只要把相机当前的世界空间旋转直接赋值给Torus节点,两者的旋转方向就会完全匹配,Torus的平面会永远平行于相机成像面,不管设备姿态怎么变,看到的都是无变形的正圆。

修正后的可运行代码

把原来硬编码旋转的逻辑替换为相机旋转同步即可,位置依然用之前hitTest拿到的世界坐标,不会改动锚点位置:

@objc private func didDoubleTap(_ sender: UITapGestureRecognizer) {
    let point = sender.location(in: sceneView)
    guard let targetVector = getVector(for: point) else { return }
    guard let cameraNode = sceneView.pointOfView else { return }

    let geometry = SCNTorus(ringRadius: 0.01, pipeRadius: 0.001)
    let node = SCNNode(geometry: geometry)
    // 同步hitTest得到的世界锚点位置
    node.simdWorldPosition = targetVector.simd
    // 同步相机的实时世界旋转,替换原来硬编码的欧拉角设置
    node.simdWorldOrientation = cameraNode.simdWorldOrientation

    sceneView.scene.rootNode.addChildNode(node)
    animatePointingNode(node)
}

补充优化:如果需要设备后续移动时,已经放置好的定位指针依然保持正圆形态,可以在场景每帧更新的回调中,遍历所有定位指针节点,重新同步一次相机的世界旋转即可。用四元数的旋转属性不会出现欧拉角的万向锁问题,对齐精度比手动算角度更高。

内容的提问来源于stack exchange,提问作者Nikolai Prokofev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 12:24:03