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

ARKit中实现SCNNode随相机旋转始终保持屏幕居中的技术求助

Fix: Keep a Node Locked to Screen Center in ARKit

Hey there! Let's get your green dot (or ship) staying firmly in the screen center no matter how you rotate the camera. The issue with your current code is that it relies on detecting real-world feature points—if there's no feature point at the screen center, your node won't move, and even when it does, it's tied to physical environment features instead of the camera's line of sight.

The Correct Approach

Instead of using hitTest, we need to calculate the 3D position that corresponds to the screen center along the camera's viewing direction. This position will sit at a fixed distance in front of the camera, so it stays centered on the screen as the camera rotates, regardless of the surrounding environment.

Step-by-Step Solution

  1. Initialize the Node Once
    Don't recreate the node every time the session updates—set it up once when your view loads. This is more efficient and avoids unnecessary scene operations.

  2. Calculate Screen Center's 3D World Position
    Use ARSCNView's unprojectPoint(_:) method to convert the screen center's 2D coordinate into a 3D world position. We'll define a fixed distance (like 2 meters) for the node to sit in front of the camera.

  3. Update Position Every Frame
    In the session update method, recalculate this position each frame and smoothly move the node to it.

Updated Code

First, set up your node in viewDidLoad() (or your setup method):

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Configure ARSCNView
    sceneView.delegate = self
    sceneView.session.run(ARWorldTrackingConfiguration())
    
    // Create your green dot node (replace with your ship model if needed)
    let dotGeometry = SCNSphere(radius: 0.05)
    dotGeometry.firstMaterial?.diffuse.contents = UIColor.green
    let centerNode = SCNNode(geometry: dotGeometry)
    centerNode.name = "CenterDot"
    
    // Add it to the scene (position will be updated dynamically)
    sceneView.scene.rootNode.addChildNode(centerNode)
}

Then, update the session delegate method to lock the node to the screen center:

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    guard let centerNode = sceneView.scene.rootNode.childNode(withName: "CenterDot", recursively: false) else {
        return
    }
    
    // Get screen center coordinates
    let screenCenter = CGPoint(x: sceneView.bounds.midX, y: sceneView.bounds.midY)
    
    // Convert screen center to 3D world position (2 meters in front of camera)
    // z=0 is camera position, z=1 is far plane—adjust z to control distance
    let targetPosition = sceneView.unprojectPoint(SCNVector3(screenCenter.x, screenCenter.y, 0.5))
    
    // Smoothly move the node to the target position
    let moveAction = SCNAction.move(to: targetPosition, duration: 0.1)
    moveAction.timingMode = .easeInEaseOut
    centerNode.runAction(moveAction)
}

Key Notes

  • Adjust Distance: Tweak the z value in unprojectPoint to move the node closer (e.g., 0.3) or farther (e.g., 3.0) from the camera.
  • Smooth Movement: The short duration and ease-in/ease-out timing ensure the node moves fluidly instead of jumping.
  • Environment Independence: This method works even in feature-poor environments, since it's based purely on the camera's perspective.

If you want to use your ship model instead of a green dot, just replace the sphere geometry initialization with your ship node setup in viewDidLoad().

内容的提问来源于stack exchange,提问作者Viktor Todorov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 20:47:34