2017-12-05 1 views
0

카메라 루트 노드 앞에 SCNPlane 형상의 SCNNode가있는 SCNView가 있습니다.iOS SceneKit에서 UIView 프로젝션 문제

UIView에서 SCNView를 통해 UIImages (Markers) - 주황색 원을 추가하고 있습니다.

모션 리스너에서 평면의 각 모서리 중심에 고정되도록 마커를 배치하려고합니다.

적절한 마커 정렬 - 장치가 직선 위치에있는 동안 : A proper Markers alignment - while device is in straight position

내가 UIView의에 SceneKit 객체에서이 사용 투사를하고 있어요 :

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

비슷한 방법 당신이 여기 찾을 수 있습니다 Scene Kit: projectPoint calculated is displaced

그래서 마커가 기기 동작 중에 평면의 가장자리에 붙어 있기를 바랍니다. 그러나 문제가있다 : 장치를 회전 할 때 - 마커가 비행기에서 표류하는 것은 가장자리 When rotating device - Markers are drifting from the Plane edges

문제의

참조 비디오 : https://github.com/mgontar/SceneKitProjectionIssue

: 나는이 문제를 재현 GitHub의에 기본 프로젝트를 만든 https://youtu.be/XBgNDDX5ZI8

답변

1

여기서 중점을 계산하는 데 사용하는 CGRect은 경계 상자의 투영 된 좌표를 기반으로합니다. 경계 상자의 두 모서리 점은 모델 뷰 투영 행렬을 사용하여 변형되어 동일한 변환을 수행하는 데 필요한 중간 점에 대한 올바른 뷰 공간 좌표를 가져옵니다.

코드가 조금 더 명확하게 표시되기를 바랍니다.

//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) 

//calc center of BB in world coordinates 
let center = SCNVector3Make(
    (v1w.x + v2w.x)/2, 
    (v1w.y + v2w.y)/2, 
    (v1w.z + v2w.z)/2) 

//calc each mid point 
let mp1w = SCNVector3Make(v1w.x, center.y, center.z) 
let mp2w = SCNVector3Make(center.x, v2w.y, center.z) 
let mp3w = SCNVector3Make(v2w.x, center.y, center.z) 
let mp4w = SCNVector3Make(center.x, v1w.y, center.z) 

//projected coordinates 
let mp1p = self.sceneView.projectPoint(mp1w) 
let mp2p = self.sceneView.projectPoint(mp2w) 
let mp3p = self.sceneView.projectPoint(mp3w) 
let mp4p = self.sceneView.projectPoint(mp4w) 

var frameOld = sm.marker.frame 

switch sm.position 
{ 
case .Top: 
    frameOld.origin.y = CGFloat(mp1p.y) - frameOld.size.height/2 
    frameOld.origin.x = CGFloat(mp1p.x) - frameOld.size.width/2 
    sm.marker.isHidden = (mp1p.z < 0 || mp1p.z > 1) 
case .Bottom: 
    frameOld.origin.y = CGFloat(mp2p.y) - frameOld.size.height/2 
    frameOld.origin.x = CGFloat(mp2p.x) - frameOld.size.width/2 
    sm.marker.isHidden = (mp2p.z < 0 || mp2p.z > 1) 
case .Left: 
    frameOld.origin.y = CGFloat(mp3p.y) - frameOld.size.height/2 
    frameOld.origin.x = CGFloat(mp3p.x) - frameOld.size.width/2 
    sm.marker.isHidden = (mp3p.z < 0 || mp3p.z > 1) 
case .Right: 
    frameOld.origin.y = CGFloat(mp4p.y) - frameOld.size.height/2 
    frameOld.origin.x = CGFloat(mp4p.x) - frameOld.size.width/2 
    sm.marker.isHidden = (mp4p.z < 0 || mp4p.z > 1) 
} 

멋진 샘플 프로젝트입니다. 우리는 화면 좌표 알고 Z-클리핑 문제에

Points line up on box edges

업데이트

projectPoint 방법은 3D SCNVector,는 x 어떤 Y 좌표를 반환합니다. z 좌표는 먼 곳과 가까운 쪽의 클리핑면 (z = 0 클리핑면 근처, z = 1 먼 클리핑면)에 상대적인 점의 위치를 ​​알려줍니다. 근거리 클리핑면에 음수 값을 설정하면 카메라 뒤의 객체가 렌더링됩니다. 클리핑 플레인 근처에 음수가 없습니다. 그러나 투영 된 점 위치가 z 멀리 및 z 가까운 범위 밖에있을 경우 어떤 일이 발생할지 말하기위한 논리가 없습니다.

위의 코드를 업데이트하여 zNear 및 zFar 체크를 포함하고 그에 따라 UIView 가시성을 전환합니다.

TL; DR 카메라는 180도 회전 할 때

마커 표시 카메라 뒤에 있지만 여전히 뷰 평면 상으로 투영되었다. 그리고 우리가 카메라 뒤에 있는지를 확인하지 않았기 때문에, 그들은 여전히 ​​전시되었습니다.

+0

귀하의 답변은 정말 훌륭하고 완벽합니다. 감사합니다! –

+0

그러나 한 가지 더 많은 문제가 있습니다. aroud를 180 도로 돌리고 마커가 표시되는지 확인하십시오. https://youtu.be/HzDMdsP_CQY –

+1

@MaxGontar 버그를 재현하려면 육체 이동이 자주 발생하지 않습니다. 위의 응답을 수정 했으므로 이제는 정상입니다. – lock