如何在ARKit 1.5中实现初始检测后的图像锚点跟踪?
Hey there! I get exactly what you're dealing with—ARKit 1.5's image recognition has that annoying limitation where ARImageAnchor doesn't track after initial detection, and it lacks the center property that ARPlaneAnchor has. Let's break down how to fix this and get those UI elements (images, buttons, labels) staying put like you want.
First, Understand the Limitation
ARKit 1.5 only performs one-time image detection, not continuous tracking. That means once the anchor is added, it won't update as the camera moves or the image shifts. So we need to work around this by reusing the initial anchor's transform to lock our UI elements in place.
Solution 1: Lock 3D Content (SceneKit Nodes) to the Initial Anchor Position
If you're using SceneKit to display 3D content (like a plane with your UI rendered onto it), you can save the initial transform of the ARImageAnchor and force your node to stick to that position every frame.
Here's a code example:
import ARKit import SceneKit class ViewController: UIViewController, ARSCNViewDelegate { @IBOutlet var sceneView: ARSCNView! // Store the initial anchor transform and your custom node private var imageAnchorTransform: simd_float4x4? private var trackedContentNode: SCNNode? override func viewDidLoad() { super.viewDidLoad() sceneView.delegate = self sceneView.scene = SCNScene() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let configuration = ARImageTrackingConfiguration() // Add your reference images to the configuration guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else { fatalError("No reference images found") } configuration.trackingImages = referenceImages sceneView.session.run(configuration) } // Capture the initial anchor transform when the image is first detected func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { guard let imageAnchor = anchor as? ARImageAnchor else { return } // Save the initial transform imageAnchorTransform = imageAnchor.transform // Create your custom content (e.g., a plane with a button texture, or a 3D label) let imageSize = imageAnchor.referenceImage.physicalSize let planeGeometry = SCNPlane(width: imageSize.width, height: imageSize.height) planeGeometry.firstMaterial?.diffuse.contents = UIImage(named: "your-ui-image") let planeNode = SCNNode(geometry: planeGeometry) planeNode.eulerAngles.x = -.pi / 2 // Rotate to match the image plane trackedContentNode = planeNode node.addChildNode(trackedContentNode!) // Optional: Set a timer to hide the plane after a set duration Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { [weak self] _ in self?.trackedContentNode?.isHidden = true } } // Force the node to keep using the initial transform every frame func renderer(_ renderer: SCNSceneRenderer, didUpdate frame: ARFrame) { guard let initialTransform = imageAnchorTransform, let contentNode = trackedContentNode else { return } contentNode.transform = initialTransform } }
Solution 2: Fix UIKit Elements (Buttons, Labels) to the Screen
If you want to display native UIKit elements (like a UIButton or UILabel) over the AR view, you can convert the initial anchor's 3D position to screen coordinates and update the UI's position every frame.
Add this to the previous example (or your existing code):
@IBOutlet var customButton: UIButton! func renderer(_ renderer: SCNSceneRenderer, didUpdate frame: ARFrame) { guard let initialTransform = imageAnchorTransform else { return } // Extract the anchor's 3D position from its transform let anchorPosition = simd_float3(initialTransform.columns.3) // Convert 3D position to screen coordinates let screenPoint = sceneView.projectPoint(SCNVector3(anchorPosition)) // Update the button's position (adjust for any offset you need) customButton.center = CGPoint( x: CGFloat(screenPoint.x), y: CGFloat(screenPoint.y) ) }
Key Notes
- Since ARKit 1.5 doesn't track the image after initial detection, this method locks your UI to the first detected position. If the image moves, the UI won't follow—but this matches the "fixed display" behavior you're aiming for.
- For the plane visibility timer, adjust the
TimeIntervalvalue to control how long the plane stays visible after detection.
内容的提问来源于stack exchange,提问作者magohamote

