首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ARKit体验中计算旋转SCNPlane的4个顶点的位置

在ARKit体验中计算旋转SCNPlane的4个顶点的位置
EN

Stack Overflow用户
提问于 2019-04-17 21:15:30
回答 2查看 742关注 0票数 1

我正在开发一个iOS应用程序,目前正在尝试获取AR体验中旋转的SCNNode的4个顶点的坐标(参考世界/根节点

从我调试这个乱七八糟的东西来看,旋转和倾斜的SCNPlane的边界框仍然与世界原点保持一致。

我已经在this线程中尝试过这个解决方案。

我试图探测的飞机直接放在ARKit探测到的图像上:

代码语言:javascript
复制
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    let referenceImage = imageAnchor.referenceImage

    updateQueue.async {

        // Create a plane to visualize the initial position of the detected image.
        let plane = SCNPlane(width: referenceImage.physicalSize.width,
                             height: referenceImage.physicalSize.height)
        let planeNode = SCNNode(geometry: plane)
        planeNode.opacity = 0.25

        /*
         `SCNPlane` is vertically oriented in its local coordinate space, but
         `ARImageAnchor` assumes the image is horizontal in its local space, so
         rotate the plane to match.
         */
        planeNode.eulerAngles.x = -.pi / 2

        /*
         Image anchors are not tracked after initial detection, so create an
         animation that limits the duration for which the plane visualization appears.
         */
        planeNode.runAction(self.imageHighlightAction)

        // This is where I tried to calculate the edge
        let (min, max) = planeNode.boundingBox

        let topLeft = SCNVector3(min.x, max.y, 0)

        let worldTopLeft = planeNode.convertPosition(topLeft, to: self.sceneView.scene.rootNode)

        let world2dTopLeft = self.sceneView.projectPoint(worldTopLeft)


        node.addChildNode(planeNode)
    }
}

预期的结果是屏幕上的某种2D位置,在3D视图中直接位于角落的顶部,但我总是得到巨大的数字,如x: 8847.291, y: -10651.121

有谁有解决这个问题的办法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-24 19:11:20

好了,我找到了解决方案:

我需要通过一些高级数学来计算,你们中的一些人可能比我解释得更好。

工作副本(适用于Swift 4.2)为:

代码语言:javascript
复制
let imageAnchor: ARImageAnchor! // provided by renderer()
let scale: CGFloat!             // UIDevice.main.scale (device scale)

// returns a transform matrix from a point
let imageTransform: (_ x: CGFloat, _ y: CGFloat) -> float4x4 = {x, y in
    var tf = float4x4(diagonal: float4(repeating: 1))
    tf.columns.3 = float4(x: Float(x), y: 0, z: Float(y), w: 1)
    return tf
}

let imageSize = imageAnchor.referenceImage.physicalSize
let worldTransform = imageAnchor.transform

let topLeft = imageTransform(-imageSize.width / 2, -imageSize.height / 2)
let topRight = imageTransform(imageSize.width / 2, -imageSize.height / 2)
let bottomLeft = imageTransform(-imageSize.width / 2, imageSize.height / 2)
let bottomRight = imageTransform(imageSize.width / 2, imageSize.height / 2)

let transformTopLeft = worldTransform * topLeft
let transformTopRight = worldTransform * topRight
let transformBottomLeft = worldTransform * bottomLeft
let transformBottomRight = worldTransform * bottomRight

let pointTopLeft = self.sceneView.projectPoint(SCNVector3(x: transformTopLeft.columns.3.x,
                                                          y: transformTopLeft.columns.3.y,
                                                          z: transformTopLeft.columns.3.z))

let pointTopRight = self.sceneView.projectPoint(SCNVector3(x: transformTopRight.columns.3.x,
                                                           y: transformTopRight.columns.3.y,
                                                           z: transformTopRight.columns.3.z))

let pointBottomLeft = self.sceneView.projectPoint(SCNVector3(x: transformBottomLeft.columns.3.x,
                                                             y: transformBottomLeft.columns.3.y,
                                                             z: transformBottomLeft.columns.3.z))

let pointBottomRight = self.sceneView.projectPoint(SCNVector3(x: transformBottomRight.columns.3.x,
                                                              y: transformBottomLeft.columns.3.y,
                                                              z: transformBottomLeft.columns.3.z))

// Those are the CGPoints, projected to the screen
let cgTL = CGPoint(x: CGFloat(pointTopLeft.x)*scale, y: extent.height-CGFloat(pointTopLeft.y)*scale)
let cgTR = CGPoint(x: CGFloat(pointTopRight.x)*scale, y: extent.height-CGFloat(pointTopRight.y)*scale)
let cgBL = CGPoint(x: CGFloat(pointBottomLeft.x)*scale, y: extent.height-CGFloat(pointBottomLeft.y)*scale)
let cgBR = CGPoint(x: CGFloat(pointBottomRight.x)*scale, y: extent.height-CGFloat(pointBottomRight.y)*scale)

这一切都运行得很好。我希望有人能解释一下我在那里做了什么。

票数 2
EN

Stack Overflow用户

发布于 2019-04-24 18:18:13

从局部空间变换到世界空间时,不应将z位置设置为零。您可以使用边界框minmax值,而无需修改它们:

代码语言:javascript
复制
let (min, max) = planeNode.boundingBox

// local space to world space
let minWorld = planeNode.convertPosition(min, to: self.sceneView.scene.rootNode)
let maxWorld = planeNode.convertPosition(max, to: self.sceneView.scene.rootNode)

// world space to screen space
let minScreen = self.sceneView.projectPoint(minWorld)
let maxScreen = self.sceneView.projectPoint(maxWorld)

然后,您可以使用minScreenmaxScreen的x和y坐标并忽略z。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55728415

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档