Zap*_*pko 6 3d opengl-es calayer catransform3d projection-matrix
所有,
我有一个iphone项目,使用OpenGL-ES为给定的模型视图矩阵和给定的投影矩阵绘制3D模型.我需要用CALayer替换3D模型,所以我将模型视图矩阵的值放入CATransform3D结构并分配给它layer.transform
.它运作良好,图层可见并按预期在屏幕上移动,但过了一段时间后我意识到我的图层行为不够精确,我应该考虑投影矩阵.然后出现了一个问题:当我简单地连接两个矩阵时,我的图层看起来很奇怪(它非常小,大约2个像素,而它应该是大约300个,因为它距离很远)或根本不可见.我该如何解决?
这是一段代码:
- (void)adjustImageObjectWithUserInfo:(NSDictionary *)userInfo
{
NSNumber *objectID = [userInfo objectForKey:kObjectIDKey];
CALayer *layer = [self.imageLayers objectForKey:objectID];
if (!layer) { return; }
CATransform3D transform = CATransform3DIdentity;
NSArray *modelViewMatrix = [userInfo objectForKey:kModelViewMatrixKey];
// Get raw model view matrix;
CGFloat *p = (CGFloat *)&transform;
for (int i = 0; i < 16; ++i)
{
*p = [[modelViewMatrix objectAtIndex:i] floatValue];
++p;
}
// Rotate around +z for Pi/2
transform = CATransform3DConcat(transform, CATransform3DMakeRotation(M_PI_2, 0, 0, 1));
// Project with projection matrix
transform = CATransform3DConcat(transform, _projectionMatrix);
layer.transform = transform;
}
Run Code Online (Sandbox Code Playgroud)
任何帮助将不胜感激.
Ham*_*mer 10
我最近遇到了这个问题(我也使用了ARToolKit),我很失望地看到你没有找到答案.我想你现在已经开始了,但我想出来了,我正在为任何其他失落的灵魂发布它,可能会遇到同样的问题.
对我来说最令人困惑的是,每个人都谈到通过将m34变量设置为一个小的负数来进行CALayer透视变换.虽然这确实有效,但它根本没有很多信息.我最终意识到变换的工作方式与其他变换完全一样,它是同源坐标的列主变换矩阵.唯一的特殊情况是它必须组合模型视图和投影矩阵,然后在一个矩阵中缩放到openGL视口的大小.我开始尝试在款式用一个矩阵,其中M34是在更为详细的解释一个小的负数在这里,但最终切换到OPEN GL风格的角度转变为解释在这里.事实上,它们彼此相当,只代表不同的思考方式.
在我们的例子中,我们试图使CALayer变换完全复制一个开放的GL变换.所需要的只是将模型视图,投影和缩放矩阵相乘,并且翻转y轴以考虑设备屏幕原点是左上方并且打开GL是左下方的事实.只要图层锚点位于(.5,.5)并且其位置正好在屏幕的中心,结果将与开放GL的变换相同
void attach_CALayer_to_marker(CATransform3D* transform, Matrix4 modelView, Matrix4 openGL_projection, Vector2 GLViewportSize)
{
//Important: This function assumes that the CA layer has its origin in the
//exact center of the screen.
Matrix4 flipY = { 1, 0,0,0,
0,-1,0,0,
0, 0,1,0,
0, 0,0,1};
//instead of -1 to 1 we want our result to go from -width/2 to width/2, same
//for height
CGFloat ScreenScale = [[UIScreen mainScreen] scale];
float xscl = GLViewportSize.x/ScreenScale/2;
float yscl = GLViewportSize.y/ScreenScale/2;
//The open GL perspective matrix projects onto a 2x2x2 cube. To get it onto the
//device screen it needs to be scaled to the correct size but
//maintaining the aspect ratio specified by the open GL window.
Matrix4 scalingMatrix = {xscl,0 ,0,0,
0, yscl,0,0,
0, 0 ,1,0,
0, 0 ,0,1};
//Open GL measures y from the bottom and CALayers measure from the top so at the
//end the entire projection must be flipped over the xz plane.
//When that happens the contents of the CALayer will get flipped upside down.
//To correct for that they are flipped updside down at the very beginning,
//they will then be flipped right side up at the end.
Matrix flipped = MatrixMakeFromProduct(modelView, flipY);
Matrix unscaled = MatrixMakeFromProduct(openGL_projection, flipped);
Matrix scaled = MatrixMakeFromProduct(scalingMatrix, unscaled);
//flip over xz plane to move origin to bottom instead of top
Matrix Final = SiMatrix4MakeFromProduct(flipY, scaled);
*transform = convert_your_matrix_object_to_CATransform3D(Final);
}
Run Code Online (Sandbox Code Playgroud)
此函数采用开放式GL投影和openGL视图大小,并使用它们为CALayer生成正确的变换.应以开放GL场景为单位指定CALayer大小.OpenGL视口实际上包含4个变量,[xoffset,yoffset,x,y],但前两个不相关,因为CALayer的原点放在屏幕的中心以对应OpenGL 3d Origin.
只需将Matrix替换为您有权访问的通用4x4列主矩阵类.任何工作只会确保您按正确的顺序乘以矩阵.所有这些基本上都在复制OpenGL管道(减去剪辑).
小智 1
两个可能的问题:
1) 连接顺序。经典的矩阵数学是从右到左。所以尝试一下
CATransform3DConcat(_projectionMatrix, transform)
Run Code Online (Sandbox Code Playgroud)
, 和
2)投影系数取值错误。您使用的值是什么?
希望这可以帮助。