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

ARKit应用实现平面检测自动生成3D桌面对象的方案求助

ARKit平面检测时自动生成桌子模型的解决方案

问题排查

你之前在平面检测回调中生成模型失败、模型出现在屏幕顶部,核心原因有两个:

  1. 未在平面检测回调中正确加载并定位桌子模型,仅添加了网格平面
  2. 若直接将桌子添加到根节点,未利用ARKit锚点节点的坐标系绑定,导致位置计算错误

修正后的完整代码

// 添加标记,避免同一平面重复生成桌子
private var hasGeneratedTable = false

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    print("Tapped")
    
    if let touch = touches.first {
        let touchLocation = touch.location(in: sceneView)           
        let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
        
        if let hitResults = results.first {                
            let diceScene = SCNScene(named: "art.scnassets/Table.scn")!
            
            if let diceNode = diceScene.rootNode.childNode(withName: "Table", recursively: true) {                  
                diceNode.position = SCNVector3(
                    x: hitResults.worldTransform.columns.3.x,
                    y: hitResults.worldTransform.columns.3.y,
                    z: hitResults.worldTransform.columns.3.z)
                
                sceneView.scene.rootNode.addChildNode(diceNode)   
                print("Rendered")
            }
        }
    }
}

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let planeAnchor = anchor as? ARPlaneAnchor, !hasGeneratedTable else {
        return
    }
    
    // 生成网格平面(保留原有逻辑)
    let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
    let planeNode = SCNNode()
    planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)
    planeNode.transform = SCNMatrix4MakeRotation(-Float.pi/2, 1, 0, 0)
    
    let gridMaterial = SCNMaterial()
    gridMaterial.diffuse.contents = UIImage(named: "art.scnassets/grid.png")
    plane.materials = [gridMaterial]  
    planeNode.geometry = plane               
    node.addChildNode(planeNode)
    
    // 加载并生成桌子模型
    guard let tableScene = SCNScene(named: "art.scnassets/Table.scn"),
          let tableNode = tableScene.rootNode.childNode(withName: "Table", recursively: true) else {
        print("Failed to load table model")
        return
    }
    
    // 设置桌子位置:与平面锚点中心对齐,y值匹配平面高度
    tableNode.position = SCNVector3(
        x: planeAnchor.center.x,
        y: planeAnchor.center.y,
        z: planeAnchor.center.z
    )
    
    // 将桌子添加到锚点对应的节点,确保平面更新时模型同步跟踪
    node.addChildNode(tableNode)
    hasGeneratedTable = true
    print("Table automatically generated on detected plane")
}

// 可选:处理平面更新,避免模型位置偏移
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let planeAnchor = anchor as? ARPlaneAnchor,
          let planeNode = node.childNodes.first,
          let plane = planeNode.geometry as? SCNPlane else {
        return
    }
    
    // 更新网格平面的大小和位置
    plane.width = CGFloat(planeAnchor.extent.x)
    plane.height = CGFloat(planeAnchor.extent.z)
    planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)
}

关键注意事项

  • 避免重复生成:通过hasGeneratedTable标记控制只生成一次桌子,防止ARKit持续检测平面时重复添加
  • 坐标系绑定:将桌子节点添加到锚点对应的node上,而非直接加到根节点,这样平面位置更新时桌子会同步跟随
  • 位置校准:使用planeAnchor.center.y作为桌子的y坐标,确保桌子刚好落在检测到的平面上,解决模型出现在屏幕顶部的问题
  • 模型加载校验:添加加载失败的打印日志,方便排查模型文件路径或命名错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:50:21