我计算在 Vuforia 中渲染的 SCNScene
的相机位置。然而,物体并没有固定在标记上,而是在移动时跳跃。场景中的立方体仅以正交方式出现,无论设备如何围绕侧面移动都无法看到。
相机位置是根据每一帧计算的:
// Get model view matrix
Vuforia::Matrix44F modelViewMatrix = Vuforia::Tool::convertPose2GLMatrix(result->getPose());
// Convert to extrinsic matrix
SCNMatrix4 extrinsic = [self SCNMatrix4FromVuforiaMatrix44: modelViewMatrix];
SCNMatrix4 inverted = SCNMatrix4Invert(extrinsic);
// Set new position of SCNCamera
cameraNode.transform = inverted;
相机投影矩阵是在相机凝视时计算的:
// Get device camera calibration
const Vuforia::CameraCalibration& cameraCalibration = Vuforia::CameraDevice::getInstance().getCameraCalibration();
projectionGLMatrix = Vuforia::Tool::getProjectionGL(cameraCalibration, 2.0f, 5000.0f);
// Convert matrix
GLKMatrix4 glkMatrix;
for(int i=0; i<16; i++) {
glkMatrix.m[i] = projectionGLMatrix.data[i];
}
// Convert matrix
SCNMatrix4 projectionTransform = SCNMatrix4FromGLKMatrix4(glkMatrix);
cameraNode.camera.projectionTransform = projectionTransform;
我在这里做错了什么?
更新 1
当相机启动时,投影矩阵现在计算如下:
const Vuforia::CameraCalibration& cameraCalibration = Vuforia::CameraDevice::getInstance().getCameraCalibration();
Vuforia::Matrix44F vuforiaMatrix = Vuforia::Tool::getProjectionGL(cameraCalibration, 2.0f, 5000.0f);
matrix_float4x4 simdMatrix = simdMatrixWithVuforiaMatrix44F(vuforiaMatrix);
cameraNode.camera.projectionTransform = SCNMatrix4FromMat4(simdMatrix);
相机位置随每一帧更新:
Vuforia::Matrix44F modelViewMatrix = Vuforia::Tool::convertPose2GLMatrix(result->getPose());
matrix_float4x4 simdMatrix = simdMatrixWithVuforiaMatrix44F(modelViewMatrix);
cameraNode.transform = SCNMatrix4FromMat4(simdMatrix);
NSLog(@"camera position: x%lf, y%lf, z%lf, rotation: x%lf, y%lf, z%lf", _cameraNode.position.x, _cameraNode.position.y, _cameraNode.position.z, _cameraNode.rotation.x, _cameraNode.rotation.y, _cameraNode.rotation.z);
通过移动设备并观察相机位置(左图)和旋转(右图)的记录,轴似乎是:
旋转轴与位置轴不同。此外,围绕剩余轴(下图中无标题)的旋转不会对在 0.999 左右浮动的cameraNode.rotation.x 值产生任何影响。
这里出了什么问题?
最佳答案
您正在经历经典的“我在矩阵上做错了什么”行为,需要大量的反复试验才能解决。我还认为您一直在 Vuforia 网站上阅读内容,但这些内容几乎没有任何帮助。 :)
重新排列矩阵可能是你出错的地方。 SCNMatrix
应该直接与 OpenGL 兼容。实际上,我将所有内容放入 simd::matrix4x4
中,并使用内置的 SCNMatrix4FromMat4
将它们转换为 SCNMatrix
。
SceneKit uses matrices to represent coordinate space transformations, which in turn can represent the combined position, rotation or orientation, and scale of an object in three-dimensional space. SceneKit matrix structures are in row-major order, so they are suitable for passing to shader programs or OpenGL APIs that accept matrix parameters.
所以,总结一下......我认为你应该删除:
SCNMatrix4 inverted = SCNMatrix4Invert(extrinsic);
至于将GLMatrix
复制到SCNMatrix
,无需尝试,应该是正确的。将使用您的方法生成的投影矩阵的结果与我的方法进行比较。它们应该是相同的。
投影矩阵
我得到的投影矩阵是这样的:
const Vuforia::Matrix44F projectionMatrix = Vuforia::Tool::getProjectionGL(cameraCalibration, nearPlane, farPlane);
simdMatrixWithVuforiaMatrix44F(projectionMatrix);
我将矩阵转换为 simd::matrix4x4
(我在 C++ 领域花费了大量时间),这只是 SceneKit 支持的 Apple 定义的结构。
#include <simd/simd.h>
matrix_float4x4 simdMatrixWithVuforiaMatrix44F(const Vuforia::Matrix44F &matrix)
{
vector_float4 col0 = { matrix.data[0], matrix.data[1], matrix.data[2], matrix.data[3] };
vector_float4 col1 = { matrix.data[4], matrix.data[5], matrix.data[6], matrix.data[7] };
vector_float4 col2 = { matrix.data[8], matrix.data[9], matrix.data[10], matrix.data[11] };
vector_float4 col3 = { matrix.data[12], matrix.data[13], matrix.data[14], matrix.data[15] };
return matrix_from_columns(col0, col1, col2, col3);
}
返回 View Controller
let extrinsic = SCNMatrix4FromMat4(projectionMatrix)
_cameraNode?.camera?.projectionTransform = extrinsic
帧标记姿势
我有一个名为 Framemarker 的对象,它实际上包含标识符和姿势,但该姿势与投影矩阵的 simd::matrix4x4
相同。
for framemarker in framemarkers {
switch framemarker.identifier {
case 337:
let pose = SCNMatrix4FromMat4(framemarker.pose)
_firstNode?.transform = pose
break
case 357:
let pose = SCNMatrix4FromMat4(framemarker.pose)
_secondNode?.transform = pose
break
default:
break
}
}
关于swift - 如何从Vuforia GL矩阵计算相机位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42035046/