我将在ARKit中检测水平和垂直平面。在检测出水平或垂直表面后,分别在检测到的表面上添加灰色平面。在检测到的平面上点击,我将添加.scn文件的3D对象。
我的代码可以很好地将3D对象(.scn文件)放置在水平面上,但不能在垂直平面上正常工作。
像相框一样的垂直平面的3D对象(.scn文件)在SceneKit编辑器中正对着。因此,我将其EularAngleY更改为-0,并且现在在SceneKit Editor中正对着前面。当我点击检测到的面向前方的垂直平面时,相框也朝右,如果我将设备向右移动并放置相框,那是正确的。
我要放置3D对象.scn文件,该文件应与平面平行(如果垂直平面面向前方,则即使在.scn文件中它面向任何方向也应面向前方).3D对象不平行于检测到的飞机。
我是否还需要相对于检测到的平面角度更改旋转角度,还是需要在SceneKit编辑器中对.scn文件进行任何更改?我该如何实现?
在击中检测到的垂直平面时,请检查以下代码。有什么问题吗?
@objc func addObjectToSceneView1(withGestureRecognizer recognizer: UIGestureRecognizer){
let tapLocation = recognizer.location(in: sceneView)
let hitTestResults = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)
guard let hitTestResult = hitTestResults.first, let anchor = hitTestResult.anchor as? ARPlaneAnchor else { return }
let translation = hitTestResult.worldTransform.columns.3
let x = translation.x
let y = translation.y
let z = translation.z
guard let shipScene = SCNScene(named: "art.scnassets/frame/frame.scn"),
let shipNode = shipScene.rootNode.childNode(withName: "frame", recursively: true)
else { return }
shipNode.position = SCNVector3(x,y,z)
sceneView.scene.rootNode.addChildNode(shipNode)
}
答案 0 :(得分:1)
正如我在答案here中提到的那样,最好在ARAnchor
上添加ARSession
,而不是在完成{命中测试。当前,您发布的代码未考虑检测到的飞机的旋转。为了使代码正常工作,您需要确定检测到的平面的法线,以点积和叉积与模型所需的方向相乘来计算旋转,然后应用旋转。但是,SCNNode
将为您完成所有这些工作。通过使用ARSession
,旋转编码为锚。因此,您只需要使用模型自己的局部坐标空间来处理变换。
例如:
ARAnchor(transform: hitTestResult.worldTransform)
然后在您的会话委托中回叫:
@objc func addObjectToSceneView1(withGestureRecognizer recognizer: UIGestureRecognizer){
let tapLocation = recognizer.location(in: sceneView)
let hitTestResults = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)
guard let hitTestResult = hitTestResults.first, let anchor = hitTestResult.anchor as? ARPlaneAnchor else { return }
// create anchor and add to session and wait for callback
let anchor = ARAnchor(transform: hitTestResult.worldTransform)
sceneView.session.add(anchor: anchor)
}
在scn文件中,您需要将模型放置在原点处且没有任何变换。这意味着您可能需要嵌套节点,并将基础模型相对于父级空节点定位。
在这里,“帧”是从func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
if anchor is ARPlaneAnchor {
// node for plane anchor
let anchorNode = SCNNode()
return anchorNode
} else {
// must be node for most recent hit test
guard let frameScene = SCNScene(named: "art.scnassets/frame/frame.scn"),
let frameNode = frameScene.rootNode.childNode(withName: "frame", recursively: true) else { return nil }
return frameNode
}
}
返回的无变换的外部节点,“图片”被旋转为平坦状态并缩放到内容的大小。
最终结果: