31

如何使用 ARKit 跟踪的水平和垂直平面将对象隐藏在墙壁后面/真实对象后面?目前,当您离开房间和/或在它们应该在它们后面的对象前面时,可以通过墙壁看到添加的 3D 对象。那么是否可以使用 ARKit 提供给我的数据来提供更自然的 AR 体验,而不会让物体穿过墙壁出现?

4

5 回答 5

33

你这里有两个问题。

(而且你甚至没有使用正则表达式!)

如何为 ARKit/SceneKit 创建遮挡几何?

如果将 SceneKit 材质设置colorBufferWriteMask为空值([]在 Swift 中),使用该材质的任何对象都不会出现在视图中,但它们仍会在渲染期间写入 z 缓冲区,这会影响其他对象的渲染。实际上,你会得到一个形状像你的对象的“洞”,通过它可以显示背景(在 的情况下是摄像头馈送ARSCNView),但它仍然可以遮挡其他 SceneKit 对象。

您还需要确保被遮挡的渲染在它应该遮挡的任何其他节点之前。您可以使用节点层次结构来做到这一点(我不记得父节点是在其子节点之前呈现还是相反,但它很容易测试)。层次结构中的对等节点没有确定性顺序,但您可以通过renderingOrder属性强制一个顺序,而不管层次结构如何。该属性默认为零,因此将其设置为 -1 将在所有内容之前呈现。(或者为了更好地控制,将renderingOrder多个节点的 s 设置为一系列值。)

如何检测墙壁/等,以便您知道在哪里放置遮挡几何?

在 iOS 11.3 及更高版本(又名“ARKit 1.5”)中,您可以打开vertical平面检测。(请注意,当您从中获取vertical平面锚点时,它们会自动旋转。因此,如果您将模型附加到锚点,它们的本地“向上”方向与平面垂直。)iOS 11.3 中的另一个新功能是,您可以获得每个检测到的平面的更详细的形状估计(请参阅ARSCNPlaneGeometry),无论其方向如何。

但是,即使您有水平和垂直,平面的外部限制也只是随时间变化的估计。也就是说,ARKit 可以快速检测墙壁的一部分在哪里,但它不知道墙壁的边缘在哪里,而无需用户花一些时间挥动设备来绘制空间。即便如此,映射的边缘可能不会与真实墙壁的边缘精确对齐。

所以......如果您使用检测到的垂直平面来遮挡虚拟几何体,您可能会发现应该隐藏的虚拟对象显示出来的地方,或者不是完全隐藏在墙的边缘,或者通过一些地方可见ARKit 没有映射整个真实的墙壁。(后一个问题你可以通过假设比 ARKit 更大的范围来解决。)

于 2017-07-05T01:54:25.400 回答
1

为了创建一个遮挡材质,它真的很简单

    let boxGeometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)

    // Define a occlusion material 
    let occlusionMaterial = SCNMaterial()
    occlusionMaterial.colorBufferWriteMask = []

    boxGeometry.materials = [occlusionMaterial]
    self.box = SCNNode(geometry: boxGeometry)
    // Set rendering order to present this box in front of the other models
    self.box.renderingOrder = -1
于 2018-09-28T02:34:29.783 回答
1

要创建遮挡材料(也称为黑洞材料或阻挡材料),您必须使用以下实例属性:.colorBufferWriteMask.readsFromDepthBuffer和。.writesToDepthBuffer.renderingOrder

你可以这样使用它们:

plane.geometry?.firstMaterial?.isDoubleSided = true
plane.geometry?.firstMaterial?.colorBufferWriteMask = .alpha  
plane.geometry?.firstMaterial?.writesToDepthBuffer = true
plane.geometry?.firstMaterial?.readsFromDepthBuffer = true
plane.renderingOrder = -100

...或者这样:

func occlusion() -> SCNMaterial {

    let occlusionMaterial = SCNMaterial()
    occlusionMaterial.isDoubleSided = true
    occlusionMaterial.colorBufferWriteMask = []
    occlusionMaterial.readsFromDepthBuffer = true
    occlusionMaterial.writesToDepthBuffer = true

    return occlusionMaterial
}

plane.geometry?.firstMaterial = occlusion()
plane.renderingOrder = -100
于 2018-06-10T13:51:57.797 回答
0

ARKit 4 和激光雷达扫描仪

您可以将任何对象隐藏在复制真实墙几何图形的虚拟隐形墙后面。配备 LiDAR(光检测和测距)扫描仪的 iPhone 12 Pro 和 iPad Pro 第 4 代可帮助我们重建周围环境的 3D 拓扑图。LiDAR 扫描仪极大地提高了 Z 通道的质量,允许从 AR 场景中遮挡或移除人类。

LiDAR 还改进了对象遮挡、运动跟踪和光线投射等功能。使用 LiDAR 扫描仪,即使在没有照明的环境中或在没有任何特征的白墙房间中,您也可以重建场景。由于sceneReconstruction实例属性,ARKit 4.0 中可以对周围环境进行 3D 重建。拥有重建的墙壁网格,现在可以非常轻松地将任何物体隐藏在真实墙壁后面。

sceneReconstruction在 ARKit 4.0 中激活实例属性,请使用以下代码:

@IBOutlet var arView: ARView!

arView.automaticallyConfigureSession = false

guard ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh)
else { return }

let config = ARWorldTrackingConfiguration()
config.sceneReconstruction = .mesh

arView.debugOptions.insert([.showSceneUnderstanding])
arView.environment.sceneUnderstanding.options.insert([.occlusion])
arView.session.run(config)


此外,如果您使用的是 SceneKit,请尝试以下方法:

@IBOutlet var sceneView: ARSCNView!

func renderer(_ renderer: SCNSceneRenderer, 
          nodeFor anchor: ARAnchor) -> SCNNode? {

    guard let meshAnchor = anchor as? ARMeshAnchor 
    else { return nil }

    let geometry = SCNGeometry(arGeometry: meshAnchor.geometry)

    geometry.firstMaterial?.diffuse.contents = 
                            colorizer.assignColor(to: meshAnchor.identifier)
‍
    let node = SCNNode()
    node.name = "Node_\(meshAnchor.identifier)"
    node.geometry = geometry
    return node
}

func renderer(_ renderer: SCNSceneRenderer,
          didUpdate node: SCNNode,
              for anchor: ARAnchor) {

    guard let meshAnchor = anchor as? ARMeshAnchor 
    else { return }

    let newGeometry = SCNGeometry(arGeometry: meshAnchor.geometry)

    newGeometry.firstMaterial?.diffuse.contents = 
                               colorizer.assignColor(to: meshAnchor.identifier)

    node.geometry = newGeometry
}

这是SCNGeometrySCNGeometrySource扩展:

extension SCNGeometry {
    convenience init(arGeometry: ARMeshGeometry) {
        let verticesSource = SCNGeometrySource(arGeometry.vertices, 
                                               semantic: .vertex)
        let normalsSource = SCNGeometrySource(arGeometry.normals, 
                                               semantic: .normal)
        let faces = SCNGeometryElement(arGeometry.faces)
        self.init(sources: [verticesSource, normalsSource], elements: [faces])
    }
}

extension SCNGeometrySource {
    convenience init(_ source: ARGeometrySource, semantic: Semantic) {
        self.init(buffer: source.buffer, vertexFormat: source.format,
                                             semantic: semantic,
                                          vertexCount: source.count,
                                           dataOffset: source.offset,
                                           dataStride: source.stride)
    }
}

...和SCNGeometryElementSCNGeometryPrimitiveType扩展:

extension SCNGeometryElement {
    convenience init(_ source: ARGeometryElement) {
        let pointer = source.buffer.contents()
        let byteCount = source.count * 
                        source.indexCountPerPrimitive * 
                        source.bytesPerIndex
        let data = Data(bytesNoCopy: pointer, 
                              count: byteCount, 
                        deallocator: .none)
        self.init(data: data, primitiveType: .of(source.primitiveType),
                             primitiveCount: source.count,
                              bytesPerIndex: source.bytesPerIndex)
    }
}

extension SCNGeometryPrimitiveType {
    static func of(type: ARGeometryPrimitiveType) -> SCNGeometryPrimitiveType {
        switch type {
            case .line: return .line
            case .triangle: return .triangles
        }
    }
}
于 2020-06-10T16:35:11.613 回答
0

很好的解决方案:

GitHub: arkit-遮挡

为我工作。

但就我而言,我想通过代码设置墙壁。因此,如果您不想通过用户设置墙壁 -> 使用平面检测来检测墙壁并通过代码设置墙壁。

或者在 4 米范围内,iphone 深度传感器工作,您可以使用ARHitTest检测障碍物。

于 2018-05-30T09:51:01.147 回答