Как преобразовать позицию SCNVector3 в координату CGPoint SCNView?

У меня есть это приложение, которое просто работает в ландшафте.

У меня есть объект на сцене. Этот объект находится в определенной позиции, указанной:

 SCNNode * buttonRef = [scene.rootNode childNodeWithName:@"buttonRef" recursively:YES];
 SCNVector3 buttonRefPosition = [buttonRef position];

Теперь мне нужно преобразовать это SCNVector3 в mainView 2D координаты, где

 mainView = (SCNView *)self.view;

Сцена использует ортогональную камеру, поэтому нет перспективы. Камера является камерой по умолчанию. Нет вращения, нет перевода. Ортогональная шкала камеры составляет 5,4.

Как мне это преобразовать?

Я нашел другие ответы на SO об обратном вопросе, который является преобразованием из CGPoint в SCNVector3, но мне не кажется очевидным, как сделать обратное, из SCNVector3 в CGPoint.

Если SCNView является подклассом UIView, то (0,0) является верхней левой точкой, а в случае ландшафта iPhone 6 (667, 375) является нижней правой точкой.

Эта моя кнопка почти на полной высоте справа и в середине высоты. С точки зрения UIKit я бы сказал, что эта кнопка находится в (600, 187), но когда я делаю это:

SCNNode * buttonRef = [scene.rootNode childNodeWithName:@"buttonRef" recursively:YES];
SCNVector3 buttonRefPosition = [buttonRef position];

SCNVector3 projectedPoint = [mainView projectPoint: buttonRefPosition];

Я получаю ProjectPoint равным (7,8, 375, 0) (?)

и когда я добавляю 10x10 вид к координате (7.8, 375), используя UIKit, я получаю вид внизу слева!!

Как я уже говорил, приложение работает только в альбомной ориентации, но все эти системы координат перепутаны.

2 ответа

Решение

Преобразование точек пространства модели в точки пространства экрана называется проецированием (поскольку оно применяет преобразование проекции камеры для отображения из трехмерного пространства в двумерное). Рендерер (через графический процессор) делает это много, много раз за кадр, чтобы получить точки вашей сцены на экране.

Есть также удобный метод, когда вам нужно сделать это самостоятельно: projectPoint:

Довольно старый вопрос, но, к сожалению, ответ @ricksters мне не очень помог, так как projectPoint: продолжает доставлять испорченные координаты вида и в моём случае (та же проблема, что описана @SpaceDog)!

Однако я обнаружил, что в моем случае проблема заключалась в том, что я применил преобразование к своему корневому узлу (перевернул мир вверх ногами;-)). Это явно приводит к неверным результатам из ProjectPoint:...

Поскольку я не мог удалить преобразование, мне пришлось настроить свой ввод для projectPoint: соответственно.

SCNVector3  viewStartPosition = ...; // Some place in the scene
SCNVector3  viewStartPositionRel = SCNVector3FromSCNVector4(SCNMatrix4MultV(self.scene.rootNode.worldTransform, SCNVector4FromSCNVector3(viewStartPosition)));
// Vector from UISceneView 0/0 top/left to start point
SCNVector3  viewStartPositionInViewCoords = [self.sceneView projectPoint:viewStartPositionRel];

К сожалению, Apple не поставляет матричную математику для матриц SCNMatrix4, поэтому используемые (действительно простые) методы обработки матриц также являются "домашними":

/*
 SCNVector4FromSCNVector3

 */
SCNVector4 SCNVector4FromSCNVector3(SCNVector3 pV) {
    return SCNVector4Make(pV.x, pV.y, pV.z, 0.0);
}

/*
 SCNVector3FromSCNVector4

 */
SCNVector3 SCNVector3FromSCNVector4(SCNVector4 pV) {
    return SCNVector3Make(pV.x, pV.y, pV.z);
}

/*
 SCNMatrix4MultV

 */
SCNVector4 SCNMatrix4MultV(SCNMatrix4 pM, SCNVector4 pV) {
    SCNVector4  r = {
        pM.m11 * pV.x + pM.m12 * pV.y + pM.m13 * pV.z + pM.m14 * pV.w,
        pM.m21 * pV.x + pM.m22 * pV.y + pM.m23 * pV.z + pM.m24 * pV.w,
        pM.m31 * pV.x + pM.m32 * pV.y + pM.m33 * pV.z + pM.m34 * pV.w,
        pM.m41 * pV.x + pM.m42 * pV.y + pM.m43 * pV.z + pM.m44 * pV.w
    };
    return r;
}

Я понятия не имею, если это ошибка в SceneKit, или если возможно запрещено применять преобразования к корневому узлу... В любом случае: проблема решена:-)

Другие вопросы по тегам