上一小節(jié)中扛邑,我們?cè)贏RKit虛擬世界中添加了3D物體抛丽,接下來(lái)我們會(huì)使用ARKit檢測(cè)現(xiàn)實(shí)世界的平面淹真。這樣我們才能在平面上放置物體以及進(jìn)行其他操作检激。
檢測(cè)平面
如果要在ARKit空間里檢測(cè)水平面巍扛,需要設(shè)置ARSessionConfiguration的planeDetection屬性為ARPlaneDetectionHorizontal领跛。設(shè)置完后,ARSceneView的delegate方法會(huì)收到回調(diào)撤奸。
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
if let planeAnchor = anchor as? ARPlaneAnchor {
self.addPlane(node: node, anchor: planeAnchor)
}
}
}
每次ARKit認(rèn)為檢測(cè)到平面時(shí)都會(huì)調(diào)用該方法吠昭,并且返回一個(gè)ARAnchor對(duì)象喊括,包含當(dāng)前檢測(cè)平面錨點(diǎn),其真正類型是ARPlaneAnchor矢棚,擁有extent(范圍)郑什、center(中心)等屬性信息。
open class ARPlaneAnchor : ARAnchor {
// The alignment of the plane.
open var alignment: ARPlaneAnchor.Alignment { get }
// The center of the plane in the anchor’s coordinate space.
open var center: vector_float3 { get }
// The extent of the plane in the anchor’s coordinate space.
open var extent: vector_float3 { get }
}
渲染平面
根據(jù)第一步得到的錨點(diǎn)信息蒲肋,我們可以在ARKit的空間中繪制一個(gè)3D平面蹦误。創(chuàng)建一個(gè)Plance類,繼承自SCNNode來(lái)管理需要渲染的平面肉津,然后創(chuàng)建SCNGeometry子類SCNPlane的對(duì)象强胰,可以用該對(duì)象創(chuàng)建平面對(duì)應(yīng)的SCNNode。在構(gòu)造方法中創(chuàng)建平面并調(diào)整其大忻蒙场:
init(_ anchor: ARPlaneAnchor) {
...
// 用ARPlaneAnchor的尺寸來(lái)創(chuàng)建3D平面幾何體
let plane = SCNPlane(width: CGFloat(anchor.extent.x - 0.05), height: CGFloat(anchor.extent.z - 0.05))
let material = SCNMaterial()
material.colorBufferWriteMask = []
material.isDoubleSided = true
plane.materials = [material]
planeNode = SCNNode()
planeNode!.geometry = plane
// SceneKit 里的平面默認(rèn)是垂直的偶洋,所以需要旋轉(zhuǎn)90度來(lái)匹配 ARKit 中的平面
planeNode!.transform = SCNMatrix4MakeRotation(-Float.pi / 2.0, 1, 0, 0)
// 將平面plane移動(dòng)到ARKit對(duì)應(yīng)的位置
planeNode!.position = SCNVector3Make(anchor.center.x, -0.01, anchor.center.z)
}
然后在ARSCNViewDelegate的回調(diào)方法中,每次掃描到新的ARAnchor時(shí)都可以創(chuàng)建新的平面距糖。
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
if let planeAnchor = anchor as? ARPlaneAnchor {
let plane = Plane(anchor)
node.addChildNode(plane)
}
}
}
更新平面
上述創(chuàng)建渲染的平面只會(huì)保持創(chuàng)建時(shí)的大小玄窝,然后現(xiàn)實(shí)世界的平面可能比創(chuàng)建初始化的大很多,若需要更新平面的大小悍引,需要更新平面的extent(范圍)值恩脂。
可以從ARSCNViewDelegate的代理方法中獲取到更新的信息:
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
if let planeAnchor = anchor as? ARPlaneAnchor {
plane.update(anchor)
}
}
}
然后在Plane類的update方法里,更新plane的寬高:
func update(_ anchor: ARPlaneAnchor) {
plane.width = CGFloat(anchor.extent.x - 0.05)
plane.height = CGFloat(anchor.extent.z - 0.05)
// 更新位置
plane.position = SCNVector3Make(anchor.center.x, -0.01, anchor.center.z)
}
待補(bǔ)充趣斤。俩块。。有點(diǎn)小忙浓领。玉凯。。