我应该如何将 OpenGL 模型视图转换为 CATransform3D?

Posted

技术标签:

【中文标题】我应该如何将 OpenGL 模型视图转换为 CATransform3D?【英文标题】:How should I translate an OpenGLES modelView to a CATransform3D? 【发布时间】:2013-02-03 04:28:46 【问题描述】:

我的目标是使用图像跟踪和 Vuforia AR SDK 在检测到的形状上覆盖标准 UIKit 视图(目前,我只是创建 UILabel,但最终我将拥有自定义内容)。我有一些有用的东西,但有一个我无法解释的“软糖”术语。我想了解我的错误在哪里,因此我可以证明此更正的存在是合理的,或者使用已知有效的不同算法。

我的项目基于 Vuforia SDK 中的 ImageTargets 示例项目。他们的EAGLView 迭代结果以渲染 OpenGL 茶壶,我已将其替换为调用我的 ObjC++ 类TrackableObjectController。对于每个可跟踪的结果,它会这样做:

- (void)augmentedRealityView:(EAGLView *)view foundTrackableResult:(const QCAR::TrackableResult *)trackableResult

    // find out where the target is in Core Animation space
    const QCAR::ImageTarget* imageTarget = static_cast<const QCAR::ImageTarget*>(&(trackableResult->getTrackable()));
    TrackableObject *trackable = [self trackableForName: TrackableName(imageTarget)];
    trackable.tracked = YES;
    QCAR::Vec2F size = imageTarget->getSize();
    QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(trackableResult->getPose());
    CGFloat ScreenScale = [[UIScreen mainScreen] scale];
    float xscl = qUtils.viewport.sizeX/ScreenScale/2;
    float yscl = qUtils.viewport.sizeY/ScreenScale/2;
    QCAR::Matrix44F projectedTransform = 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1;
    QCAR::Matrix44F qcarTransform = 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1;
    /* this sizeFudge constant is here to put the label in the correct place in this demo; I had thought that
     * the problem was related to the units used (I defined the length of the target in mm in the Target Manager;
     * the fact that I've got to multiply by ten here could be indicative of the app interpreting length in cm).
     * That turned out not to be the case, when I changed the reported length of the target it stopped drawing the
     * label at the correct size. Currently, therefore, the app and the target database are both using mm, but
     * there's the following empirically-divised fudge factor to get the app to position the correctly-sized view
     * in the correct position relative to the detected object.
     */
    const double sizeFudge = 10.0;
    ShaderUtils::translatePoseMatrix(sizeFudge * size.data[0] / 2, sizeFudge * size.data[1] / 2, 0, projectedTransform.data);
    ShaderUtils::scalePoseMatrix(xscl, -yscl, 1.0, projectedTransform.data); // flip along y axis
    ShaderUtils::multiplyMatrix(projectedTransform.data, qUtils.projectionMatrix.data, qcarTransform.data);
    ShaderUtils::multiplyMatrix(qcarTransform.data, modelViewMatrix.data, qcarTransform.data);
    CATransform3D transform = *((CATransform3D*)qcarTransform.data); // both are array[16] of float
    transform = CATransform3DScale(transform,1,-1,0); //needs flipping to draw
    trackable.transform = transform;

然后在主线程上调用其他代码,查看我的TrackableObject 实例,将计算得到的CATransform3D 应用到覆盖视图的层,并将覆盖视图设置为EAGLView 的子视图。

我的问题是,由于代码示例中的注释已经泄露,这个 sizeFudge 因素。除了这个因素,我的代码做同样的事情as this answer;但这将我的观点置于错误的位置。

根据经验,我发现如果我不包含 sizeFudge 术语,那么我的叠加视图可以很好地跟踪被跟踪对象的方向和平移,但在 iPad 屏幕上向下和向右偏移 - 这是平移差异,因此更改用于 . 的术语是有道理的。我首先认为问题在于 Vuforia 的目标管理器中指定的对象大小。事实证明并非如此。如果我创建一个十倍大小的目标,那么覆盖视图将绘制在相同的、不正确的位置但小十倍(因为 AR 假设它跟踪的对象更远,我想)。

只是翻译这里的姿势才能让我到达我想去的地方,但这并不令人满意,因为它对我没有任何意义。谁能解释从 Vuforia 提供的 OpenGL 坐标转换为不依赖幻数的 CATransform3D 的正确方法?

** 更多数据 **

问题比我写这个问题时想象的要复杂。标签的位置实际上似乎取决于 iPad 到被跟踪对象的距离,尽管不是线性的。还有一个明显的系统错误。

这是一张图表,通过将 iPad 移动到距离目标一定距离(位于黑色方块上方),并用笔在视图中心出现的位置进行标记。正方形上方和左侧的点具有如上所述的翻译软糖,下方和右侧的点具有sizeFudge==0。希望此处显示的距离和偏移量之间的关系能够让比我更了解 3D 图形的人了解变换的问题所在。

【问题讨论】:

他们的 OpenGL ES 视图使用的坐标系是什么?通常,OpenGL ES 场景设置的坐标从 -1 到 1,而不是 UIKit 坐标的 0 到 [width] 或 [height]。我可以看到需要翻译来解释这一点。如果他们使用范围从 -10 到 10 的坐标系,这可能解释了您的翻译捏造因素。 感谢@BradLarson 的洞察力。我不确定如何找到这个坐标系;我目前看不到项目在哪里设置了截锥体或其他相机投影。我也觉得这是不相关的,因为 view 的 坐标系在视图平面上是二维的,不是吗? 看起来这些人可能会给你答案,或者至少有一些有用的建议:***.com/questions/6045502/… @cb88 这是我在这个问题中链接的问题;我正在做同样的事情但没有得到预期结果的那个。 跟踪视图的大小是多少?如果你设置trackingView.center = CGPointZero会发生什么? 【参考方案1】:

这可能首先与您的视图设置有关。奇怪的偏移量可能是由错误的宽度和高度或任何其他可能的不正确值(例如在 iPad 上使用 iPhone 屏幕比例)引起的。

您的应用前景如何?如果是这样,那就试试纵向吧。我过去注意到,应用程序似乎总是以纵向屏幕尺寸启动(不过我还没有证实这一点),所以如果你的视图设置发生在屏幕是“正确的方式”之前,你会得到不匹配。

您也可以尝试准确计算出差了多少。而不是将 size.data 乘以 hack:添加另一个翻译并调整数字直到它是正确的。这些数字可能会让您更好地了解正在发生的事情。 *10 可能只是侥幸,没有多大意义。

【讨论】:

这听起来很有希望,谢谢。由于纵向/横向方向,我在应用中看到了其他问题,所以我会调查一下。 在我看来,在不同的方向上肯定存在不同的一些错误,这可能是一个线索。这不是全部,因为一切都出现在纵向方向的(不同的)错误位置。我发现偏离量随与目标的距离而变化,因此它看起来像是矩阵变换的一般问题。

以上是关于我应该如何将 OpenGL 模型视图转换为 CATransform3D?的主要内容,如果未能解决你的问题,请参考以下文章

现代 OpenGL 投影视图模型转换不起作用

如何将 OpenGL 纹理转换为 CUDA 纹理?

如何将 2D 世界转换为屏幕坐标 OpenGL

需要帮助在 OpenGL 中移动相机

Qt4 模型/视图 - 在视图中转换数据?

当涉及旋转时,将鼠标坐标转换为 OpenGL 中的模型坐标