如何将相机外部矩阵转换为 SCNCamera 位置和旋转
How to convert camera extrinsic matrix to SCNCamera position and rotation
我正在尝试通过 SceneKit
实现增强现实。
我使用 ARuco(OpenCV 增强现实库)通过估计标记的姿态得到了一个内在相机矩阵和一个外在矩阵。
然后我使用内在矩阵(fovy、aspect、zNear、zFar)的参数设置了 SCNCamera
的 projectionTransform
。
一般在OpenGL
,world coordinate relative to camera coordinate是用ModelView计算的,但是在SceneKit中,没有modelView之类的东西。
所以我计算了外部矩阵的逆矩阵以获得相对于世界坐标(标记坐标)的相机坐标。
我想我已经通过包含旋转和平移矩阵的逆矩阵得到了正确的相机位置。
但是我无法从中获取相机的旋转。
你有什么想法吗?
SceneKit 具有与您在 OpenGL 中遇到的相同的视图矩阵,在您开始使用着色器之前它们只是隐藏了一点。 IMO 有点太隐蔽了。
你似乎已经弄明白了大部分。投影矩阵来自您的相机 projectionTransform
,而视图矩阵来自相机矩阵的逆矩阵 SCNMatrix4Invert(cameraNode.transform)
。在我的例子中,一切都在世界坐标中,使我的模型矩阵成为一个简单的单位矩阵。
我最终用来获取经典模型-视图-投影矩阵的代码类似于...
let projection = camera.projectionTransform()
let view = SCNMatrix4Invert(cameraNode.transform)
let model = SCNMatrix4Identity
let viewProjection = SCNMatrix4Mult(view, projection)
let modelViewProjection = SCNMatrix4Mult(model, viewProjection)
出于某种原因,我发现 SCNMatrix4Mult(...)
接受参数的顺序与我预期的不同(例如,与 GLKMatrix4Multiply(...)
相反)。
我对此还不是 100%,欢迎 edits/tips。使用这种方法我无法获得 SceneKit MVP 矩阵(传递给着色器)以匹配上面代码计算的矩阵......但它已经足够接近我需要的了。
@lock 的回答看起来不错,添加了一些内容:
(1) 访问 SCNNode worldTransform 而不是 transform,以防 cameraNode 是动画的或父级的:
let view = SCNMatrix4Invert(cameraNode.presentationNode.worldTransform)
(2) 代码不考虑视图的纵横比。例如,假设透视投影,你会想要做:
perspMatrix.m11 /= viewportAR; //if using Yfov -> adjust Y`
/* or, */
perspMatrix.m22 *= viewportAR; //if using Xfov -> adjust X`
其中,viewportAR = viewport.width / viewport.height
另一种方法是让一个节点在场景中呈现代理,并从该代理中检索 SceneKit 的矩阵(它们作为选项传递):
FOUNDATION_EXTERN NSString * const SCNModelTransform;
FOUNDATION_EXTERN NSString * const SCNViewTransform;
FOUNDATION_EXTERN NSString * const SCNProjectionTransform;
FOUNDATION_EXTERN NSString * const SCNNormalTransform;
FOUNDATION_EXTERN NSString * const SCNModelViewTransform;
FOUNDATION_EXTERN NSString * const SCNModelViewProjectionTransform;
我正在尝试通过 SceneKit
实现增强现实。
我使用 ARuco(OpenCV 增强现实库)通过估计标记的姿态得到了一个内在相机矩阵和一个外在矩阵。
然后我使用内在矩阵(fovy、aspect、zNear、zFar)的参数设置了 SCNCamera
的 projectionTransform
。
一般在OpenGL
,world coordinate relative to camera coordinate是用ModelView计算的,但是在SceneKit中,没有modelView之类的东西。
所以我计算了外部矩阵的逆矩阵以获得相对于世界坐标(标记坐标)的相机坐标。
我想我已经通过包含旋转和平移矩阵的逆矩阵得到了正确的相机位置。
但是我无法从中获取相机的旋转。
你有什么想法吗?
SceneKit 具有与您在 OpenGL 中遇到的相同的视图矩阵,在您开始使用着色器之前它们只是隐藏了一点。 IMO 有点太隐蔽了。
你似乎已经弄明白了大部分。投影矩阵来自您的相机 projectionTransform
,而视图矩阵来自相机矩阵的逆矩阵 SCNMatrix4Invert(cameraNode.transform)
。在我的例子中,一切都在世界坐标中,使我的模型矩阵成为一个简单的单位矩阵。
我最终用来获取经典模型-视图-投影矩阵的代码类似于...
let projection = camera.projectionTransform()
let view = SCNMatrix4Invert(cameraNode.transform)
let model = SCNMatrix4Identity
let viewProjection = SCNMatrix4Mult(view, projection)
let modelViewProjection = SCNMatrix4Mult(model, viewProjection)
出于某种原因,我发现 SCNMatrix4Mult(...)
接受参数的顺序与我预期的不同(例如,与 GLKMatrix4Multiply(...)
相反)。
我对此还不是 100%,欢迎 edits/tips。使用这种方法我无法获得 SceneKit MVP 矩阵(传递给着色器)以匹配上面代码计算的矩阵......但它已经足够接近我需要的了。
@lock 的回答看起来不错,添加了一些内容:
(1) 访问 SCNNode worldTransform 而不是 transform,以防 cameraNode 是动画的或父级的:
let view = SCNMatrix4Invert(cameraNode.presentationNode.worldTransform)
(2) 代码不考虑视图的纵横比。例如,假设透视投影,你会想要做:
perspMatrix.m11 /= viewportAR; //if using Yfov -> adjust Y`
/* or, */
perspMatrix.m22 *= viewportAR; //if using Xfov -> adjust X`
其中,viewportAR = viewport.width / viewport.height
另一种方法是让一个节点在场景中呈现代理,并从该代理中检索 SceneKit 的矩阵(它们作为选项传递):
FOUNDATION_EXTERN NSString * const SCNModelTransform;
FOUNDATION_EXTERN NSString * const SCNViewTransform;
FOUNDATION_EXTERN NSString * const SCNProjectionTransform;
FOUNDATION_EXTERN NSString * const SCNNormalTransform;
FOUNDATION_EXTERN NSString * const SCNModelViewTransform;
FOUNDATION_EXTERN NSString * const SCNModelViewProjectionTransform;