【发布时间】:2021-03-11 18:07:40
【问题描述】:
我的目标是计算固定到某个ARPlaneAnchor 的垂直平面的“可见”部分,并用四边形表示,如下图所示:
我目前的方法是基于少数命中测试,不幸的是,这似乎没有给我令人满意的结果。
首先,当我检测到ARPlaneAnchor 时,我会在其主节点中添加一个不可见的大SCNNode。
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
let planeNode = SCNNode(geometry: SCNPlane(width: 100.0, height: 100.0))
planeNode.name = "infinite_plane"
planeNode.position = SCNVector3(planeAnchor.center.x, planeAnchor.center.y, planeAnchor.center.z)
planeNode.eulerAngles = SCNVector3(-0.5 * .pi, 0, 0)
planeNode.geometry?.firstMaterial?.diffuse.contents = UIColor.clear
node.addChildNode(planeNode)
node.enumerateChildNodes { childNode, _ in
childNode.removeFromParentNode()
}
}
然后,当需要计算垂直平面的可见部分时(时间无关紧要,可以是在某些屏幕触摸之后或每次渲染新帧时),我会取屏幕的中心并执行一些命中测试。
let center = CGPoint(x: sceneView.bounds.midX, y: sceneView.bounds.midY)
let hitTestResults = sceneView.hitTest(center, types: [.existingPlaneUsingGeometry, .estimatedVerticalPlane])
if let hitTestResult = hitTestResults.first,
let hitAnchor = hitTestResult.anchor,
let hitNode = sceneView.node(for: hitAnchor) {
let width = sceneView.bounds.width
let height = sceneView.bounds.height
// A B
// C D
guard let aPosition = sceneView.hitTest(CGPoint(x: 0, y: 0)).first?.worldCoordinates,
let bPosition = sceneView.hitTest(CGPoint(x: width, y: 0)).first?.worldCoordinates,
let cPosition = sceneView.hitTest(CGPoint(x: 0, y: height)).first?.worldCoordinates,
let dPosition = sceneView.hitTest(CGPoint(x: width, y: height)).first?.worldCoordinates else {
return
}
let geometry = SCNGeometry.polygon(vertices: [aPosition, bPosition, dPosition, cPosition])
let node = SCNNode(geometry: geometry)
node.geometry?.firstMaterial?.diffuse.contents = UIColor.green
node.geometry?.firstMaterial?.isDoubleSided = true
sceneView.scene.rootNode.addChildNode(node)
}
extension SCNGeometry {
static func polygon(vertices: [SCNVector3]) -> SCNGeometry {
let source = SCNGeometrySource(vertices: vertices)
var indices = vertices.indices.map { UInt32($0) }
indices.insert(UInt32(vertices.count), at: 0)
let data = Data(bytes: indices, count: indices.count * MemoryLayout<Int32>.size)
let element = SCNGeometryElement(
data: data,
primitiveType: .polygon,
primitiveCount: 1,
bytesPerIndex: MemoryLayout<Int32>.size
)
return SCNGeometry(sources: [source], elements: [element])
}
}
然后我停了下来。绘制的多边形似乎并不代表垂直平面的可见部分。
问题是,我的估计哪里错了,我应该如何正确检测垂直平面的“可见”部分?
【问题讨论】:
-
找到解决方案成功了吗?
标签: swift augmented-reality scenekit arkit