这是我尝试过的代码:
var cake_1_PlaneNode : SCNNode? = nil func renderer(_ renderer: SCNSceneRenderer,didAdd node: SCNNode,for anchor: ARAnchor) { guard let imageAnchor = anchor as? ARImageAnchor else { return } if let imageName = imageAnchor.referenceImage.name { print(imageName) if imageName == "menu" { // Check To See The Detected Size Of Our menu Card (Should By 5cm*3cm) let menuCardWidth = imageAnchor.referenceImage.physicalSize.width let menuCardHeight = imageAnchor.referenceImage.physicalSize.height print( """ We Have Detected menu Card With Name \(imageName) \(imageName)'s Width Is \(menuCardWidth) \(imageName)'s Height Is \(menuCardHeight) """) //raspberry //cake 1 let cake_1_Plane = SCNPlane(width: 0.045,height: 0.045) cake_1_Plane.firstMaterial?.diffuse.contents = UIImage(named: "france") cake_1_Plane.cornerRadius = 0.01 let cake_1_PlaneNode = SCNNode(geometry: cake_1_Plane) self.cake_1_PlaneNode = cake_1_PlaneNode cake_1_PlaneNode.eulerAngles.x = -.pi/2 cake_1_PlaneNode.runAction(SCNAction.moveBy(x: 0.15,y: 0,z: -0.125,duration: 0.75)) node.addChildNode(cake_1_PlaneNode) self.sceneView.scene.rootNode.addChildNode(node) } } override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?) { let touch = touches.first as! UITouch if(touch.view == self.sceneView){ //print("touch working") let viewTouchLocation:CGPoint = touch.location(in: sceneView) guard let result = sceneView.hitTest(viewTouchLocation,options: nil).first else { return } if let planeNode = cake_1_PlaneNode,cake_1_PlaneNode == result.node{ print("match") cake_1() } } } func cake_1() { let plane = SCNPlane(width: 0.15,height: 0.15) plane.firstMaterial?.diffuse.contents = UIColor.black.withAlphaComponent(0.75) let planeNodee = SCNNode(geometry: plane) planeNodee.eulerAngles.x = -.pi / 2 planeNodee.runAction(SCNAction.moveBy(x: 0.21,z: 0,duration: 0)) } //cake_1
首先,您正在创建一个您已声明的全局变量:
var cake_1_PlaneNode : SCNNode? = nil
但是,在yourDelegate回调中为cake_1_PlaneNode使用本地变量和全局变量:
let cake_1_PlaneNode = SCNNode(geometry: cake_1_Plane) self.cake_1_PlaneNode = cake_1_PlaneNode
这应该只是这样读:
self.cake_1_PlaneNode = SCNNode(geometry: cake_1_Plane)
其次,您将cake_1_PlaneNode添加到ARSCNView的rootNode而不是您检测到的ARImageAnchor,这可能是您不想做的事情,因为当检测到ARAnchor时:
You can provide visual content for the anchor by attaching geometry
(or other SceneKit features) to this node or by adding child nodes.
因此,这种方法(除非你真的想这样做)是不必要的.
剩下的问题在于你的cake_1函数本身.
首先,您实际上并没有将planeNodee添加到sceneHierachy中.
由于您尚未指定是否应将新初始化的planeNode直接添加到ARSCNView或作为cake_1_planeNode的childNode,因此您的函数应包括以下内容之一:
self.sceneView.scene.rootNode.addChildNode(planeNodee) self.cake_1_planeNode.addChildNode(planeNodee)
此外,可能还没有必要旋转您的planeNodee,因为默认情况下SCNPlane是垂直渲染的.
由于您没有规定放置内容的位置,因此可能不需要使用-.pi / 2,因为这可能使其几乎看不见肉眼.
另一个问题也可能导致您在实际添加节点时没有看到您的节点是Z位置.
如果您在同一位置设置2个节点,您可能会遇到一个称为Z-fighting的问题(您可以阅读更多关于here的信息).因此,您可能应该在添加节点时稍微向前移动添加的节点,例如SCNVector3(0,0.001)来解释这一点.
基于所有这些要点,我在下面提供了一个完整的工作和评论示例:
import UIKit import ARKit //------------------------- //MARK: - ARSCNViewDelegate //------------------------- extension ViewController: ARSCNViewDelegate { func renderer(_ renderer: SCNSceneRenderer,for anchor: ARAnchor) { //1. Check We Have An ARImageAnchor,Then Get It's Reference Image & Name guard let imageAnchor = anchor as? ARImageAnchor else { return } let detectedTarget = imageAnchor.referenceImage guard let detectedTargetName = detectedTarget.name else { return } //2. If We Have Detected Our Virtual Menu Then Add The CakeOnePlane if detectedTargetName == "cakeMenu" { let cakeOnePlaneGeometry = SCNPlane(width: 0.045,height: 0.045) cakeOnePlaneGeometry.firstMaterial?.diffuse.contents = UIColor.cyan cakeOnePlaneGeometry.cornerRadius = 0.01 let cakeOnPlaneNode = SCNNode(geometry: cakeOnePlaneGeometry) cakeOnPlaneNode.eulerAngles.x = -.pi/2 //3. To Allow Us To Easily Keep Track Our Our Currently Added Node We Will Assign It A Unique Name cakeOnPlaneNode.name = "Strawberry Cake" node.addChildNode(cakeOnPlaneNode) cakeOnPlaneNode.runAction(SCNAction.moveBy(x: 0.15,duration: 0.75)) } } } class ViewController: UIViewController { @IBOutlet var augmentedRealityView: ARSCNView! let augmentedRealitySession = ARSession() let configuration = ARWorldTrackingConfiguration() //------------------ //MARK: - Life Cycle //------------------ override func viewDidLoad() { super.viewDidLoad() setupARSession() } //----------------- //MARK: - ARSession //----------------- /// Runs The ARSession func setupARSession(){ //1. Load Our Detection Images guard let detectionImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources",bundle: nil) else { return } //2. Configure & Run Our ARSession augmentedRealityView.session = augmentedRealitySession augmentedRealityView.delegate = self configuration.detectionImages = detectionImages augmentedRealitySession.run(configuration,options: [.resetTracking,.removeExistingAnchors]) } //-------------------- //MARK: - Interaction //-------------------- override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?) { //1. Get The Current Touch Location & Perform An ARSCNHitTest To Check For Any Hit SCNNode's guard let currentTouchLocation = touches.first?.location(in: self.augmentedRealityView),let hitTestNode = self.augmentedRealityView.hitTest(currentTouchLocation,options: nil).first?.node else { return } //2. If We Have Hit Our Strawberry Cake Then We Call Our makeCakeOnNode Function if let cakeID = hitTestNode.name,cakeID == "Strawberry Cake"{ makeCakeOnNode(hitTestNode) } } /// Adds An SCNPlane To A Detected Cake Target /// /// - Parameter node: SCNNode func makeCakeOnNode(_ node: SCNNode){ let planeGeometry = SCNPlane(width: 0.15,height: 0.15) planeGeometry.firstMaterial?.diffuse.contents = UIColor.black.withAlphaComponent(0.75) let planeNode = SCNNode(geometry: planeGeometry) planeNode.position = SCNVector3(0,0.001) planeNode.runAction(SCNAction.moveBy(x: 0.21,duration: 0)) node.addChildNode(planeNode) } }
这在我的设备上产生以下内容:
对于您的信息,这似乎表明您放置内容的计算是关闭的(除非当然这是期望的结果).
正如您所看到的,所有内容都正确呈现,但是这些内容的间距非常大,因此您可能需要稍微平移设备,以便在进一步测试和开发时看到它们.
希望能帮助到你…