我的相机根节点前面有一个 SCNView,SCNNode 为 SCNPlane 几何体。
通过 SCNView,在 UIView 中,我添加了 UIImages(标记) - 橙色圆圈。
在 Motion 监听器中,我试图以某种方式定位标记,以便它们将粘附到平面的每个边缘的中心。
正确的标记对齐 - 当设备处于直线位置时:
我正在使用 SceneKit 对象到 UIView 的投影:
//world coordinates
let v1w = sm.node.convertPosition(sm.node.boundingBox.min,
to: self.sceneView.scene?.rootNode)
let v2w = sm.node.convertPosition(sm.node.boundingBox.max,
to: self.sceneView.scene?.rootNode)
//projected coordinates
let v1p = self.sceneView.projectPoint(v1w)
let v2p = self.sceneView.projectPoint(v2w)
//frame rectangle
let rect = CGRect.init(x: CGFloat(v1p.x), y: CGFloat(v2p.y),
width: CGFloat(v2p.x - v1p.x), height: CGFloat(v1p.y - v2p.y))
var frameOld = sm.marker.frame
switch sm.position
{
case .Top:
frameOld.origin.y = rect.minY - frameOld.size.height/2
frameOld.origin.x = rect.midX - frameOld.size.width/2
case .Bottom:
frameOld.origin.y = rect.maxY - frameOld.size.height/2
frameOld.origin.x = rect.midX - frameOld.size.width/2
case .Left:
frameOld.origin.y = rect.midY - frameOld.size.height/2
frameOld.origin.x = rect.minX - frameOld.size.width/2
case .Right:
frameOld.origin.y = rect.midY - frameOld.size.height/2
frameOld.origin.x = rect.maxX - frameOld.size.width/2
}
sm.marker.frame = frameOld
self.view.layoutSubviews()
你可以在这里找到类似的方法:场景工具包:计划的 projectPoint 被取代
所以我希望那些标记在设备运动过程中贴在平面的边缘。但问题是:当旋转设备时 - 标记从平面边缘漂移
查看问题视频:https://youtu.be/XBgNDDX5ZI8
我在 github 上创建了一个基本项目来重现一个问题:https://github.com/mgontar/SceneKitProjectionIssue
1 回答
这里的问题是
CGRect
用于计算中点是基于边界框的投影坐标。使用模型视图投影矩阵转换边界框的两个角点,以获得执行相同变换所需的中间点的正确视图空间坐标。希望代码更清晰一些。
这是一个很酷的小样本项目!
z-clipping 问题更新
projectPoint
方法返回一个 3DSCNVector
,x 任何 y coords 我们知道是屏幕坐标。 z 坐标告诉我们该点相对于远和近剪裁平面的位置(z = 0 在剪切平面附近,z = 1 远剪裁平面)。如果为近剪裁平面设置负值,则会渲染摄影机后面的对象。我们没有负近剪裁平面,但我们也没有任何逻辑可以说明如果那些投影点位置落在 z 远和 z 近距离之外会发生什么。我已更新上面的代码以包含此 zNear 和 zFar 检查并相应地切换 UIView 可见性。
TL;博士
相机旋转 180 度时可见的标记位于相机后面,但它们仍然投影到视图平面上。由于我们没有检查他们是否在镜头后面,他们仍然显示。