将ARFaceAnchor与SpriteKit叠加层对齐

时间:2018-11-06 16:17:51

标签: swift sprite-kit scenekit arkit face

我正在尝试计算特定几何点ARFaceGeometry / ARFaceAnchor上SpriteKit覆盖内容的位置(而不仅仅是覆盖视觉内容)。

我从计算出的世界坐标中使用SCNSceneRenderer.projectPoint,但是结果是y反转并且未与相机图像对齐:

let vertex4 = vector_float4(0, 0, 0, 1)
let modelMatrix = faceAnchor.transform
let world_vertex4 = simd_mul(modelMatrix, vertex4)
let pt3 = SCNVector3(x: Float(world_vertex4.x),
                     y: Float(world_vertex4.y),
                     z: Float(world_vertex4.z))
let sprite_pt = renderer.projectPoint(pt3)

// To visualize sprite_pt
let dot = SKSpriteNode(imageNamed: "dot")
dot.size = CGSize(width: 7, height: 7)
dot.position = CGPoint(x: CGFloat(sprite_pt.x), 
                       y: CGFloat(sprite_pt.y))
overlayScene.addChild(dot)

2 个答案:

答案 0 :(得分:2)

根据我的经验,ARKit的projectPoint函数给出的屏幕坐标在绘制到CALayer时可以直接使用。这意味着它们遵循here中所述的iOS坐标,其中原点位于左上角,y取反。

SpriteKit具有its own coordinate system

  

单位坐标系将原点放置在框架的左下角,将(1,1)放置在框架的右上角。精灵的锚点默认为(0.5,0.5),与框架的中心相对应。

最后,将SKNode放置在SKScene中,其起源在左下角。您应该确保您的SKScene与您的实际视图大小相同,否则原点可能不在视图的左下角,因此您在视图中对节点的定位可能不正确。 this question的答案可能会有所帮助,特别是检查视图的AspectFit或AspectFill以确保场景按比例缩小。

  

场景的原点位于左下角,具体取决于您的场景大小和缩放比例,它可能不在屏幕上。这是0,0所在的位置。因此,您添加的每个孩子都会从那里开始,并根据位置正确地向上工作。 SKSpriteNode的原点位于中心。

因此,从视图坐标和SpriteKit坐标进行转换的两个基本步骤是:1)反转y轴,使原点位于左下角; 2)确保您的SKScene框架与视图框架匹配。

我可以稍作测试,然后编辑是否存在任何问题

答案 1 :(得分:0)

找到了使用camera.projectPoint而不是renderer.projectPoint的转换。

要在spritekit上正确缩放点:设置scaleMode = .aspectFill

我更新了https://github.com/AnsonT/ARFaceSpriteKitMapping进行了演示。

    guard let faceAnchor = anchor as? ARFaceAnchor,
        let camera = sceneView.session.currentFrame?.camera,
        let sie = overlayScene?.size
    else { return }

    let modelMatrix = faceAnchor.transform

    let vertices = faceAnchor.geometry.vertices

    for vertex in vertices {
        let vertex4 = vector_float4(vertex.x, vertex.y, vertex.z, 1)
        let world_vertex4 = simd_mul(modelMatrix, vertex4)
        let world_vector3 = simd_float3(x: world_vertex4.x, y: world_vertex4.y, z: world_vertex4.z)

        let pt = camera.projectPoint(world_vector3, orientation: .portrait, viewportSize: size)

        let dot = SKSpriteNode(imageNamed: "dot")
        dot.size = CGSize(width: 7, height: 7)
        dot.position = CGPoint(x: CGFloat(pt.x), y: size.height - CGFloat(pt.y))
        overlayScene?.addChild(dot)

    }