如何计算垂直平面的可见部分的四边形? [英] How to calculate quadrangle for visible part of vertical plane?

查看:68
本文介绍了如何计算垂直平面的可见部分的四边形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是计算可见"垂直平面的一部分,锚定到某些 ARPlaneAnchor 上,并用四边形表示,如下图所示:

My goal is to calculate the "visible" part of vertical plane that is anchored to some ARPlaneAnchor and represent it with quadrangle as shown in the picture below:

我目前的方法是基于很少的命中测试,不幸的是,这似乎并没有给我令人满意的结果.

My current approach is based on few hit tests, which unfortunately seems to not giving me the satisfying results.

首先,当我检测到 ARPlaneAnchor 时,将一个不可见的 SCNNode 添加到其主节点.

First, when I detect a ARPlaneAnchor I add a big invisible SCNNode to its main node.

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()
    }
}

然后,当需要计算垂直平面的可见部分时(无论何时,可以是在触摸屏幕后或每次渲染新帧时),我将屏幕的中心位置执行一些命中测试.

Then, when it's time to calculate the visible part of vertical plane (it doesn't matter when, it can be after some screen touch or each time the new frame is being rendered) I take the center of the screen and perform some hit tests.

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])
    }
}

在这里我停了下来.绘制的多边形似乎并不代表垂直平面的可见部分.

And here I stopped. The drawn polygon doesn't seem to be representing the visible part of the vertical plane.

问题是,我的估计错误在哪里,以及我应该如何检测可见"错误?垂直平面的一部分?

The question is, how where my estimatations are wrong and how should I detect the "visible" part of vertical plane correctly?

推荐答案

尝试以下方法:

extension ViewController: ARSCNViewDelegate {
    
    func renderer(_ renderer: SCNSceneRenderer,
                 didAdd node: SCNNode,
                  for anchor: ARAnchor) {
        
        guard let planeAnchor = anchor as? ARPlaneAnchor
        else { return }
        
        let width = CGFloat(planeAnchor.extent.x)
        let height = CGFloat(planeAnchor.extent.z)
        
        let myPlane = SCNPlane(width: width,
                              height: height)

        myPlane.materials.first?.diffuse.contents = UIColor(white: 0.0, 
                                                            alpha: 0.5)
        
        let planeNode = SCNNode(geometry: myPlane)
        let x = CGFloat(planeAnchor.center.x)
        let y = CGFloat(planeAnchor.center.y)
        let z = CGFloat(planeAnchor.center.z)
        
        planeNode.position = SCNVector3(x, y, z)
        planeNode.eulerAngles.x = -Float.pi / 2
        
        node.addChildNode(planeNode)
    }      
    
    func renderer(_ renderer: SCNSceneRenderer,
              didUpdate node: SCNNode,
                  for anchor: ARAnchor) {
        
        guard let planeAnchor = anchor as? ARPlaneAnchor,
              let planeNode = node.childNodes.first,
              let myPlane = planeNode.geometry as? SCNPlane
        else { return }
        
        let width = CGFloat(planeAnchor.extent.x)
        let height = CGFloat(planeAnchor.extent.z)
        myPlane.width = width
        myPlane.height = height
        
        let x = CGFloat(planeAnchor.center.x)
        let y = CGFloat(planeAnchor.center.y)
        let z = CGFloat(planeAnchor.center.z)
        planeNode.position = SCNVector3(x, y, z)
    }
}

这篇关于如何计算垂直平面的可见部分的四边形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆