将iPad坐标转换为OpenGL ES 2.0场景坐标? iOS版

时间:2013-10-18 13:37:19

标签: ios objective-c opengl-es matrix coordinate-systems

我有一个只包含2D对象的OpenGL ES 2.0场景。我正在应用以下两个矩阵:

width = 600;

CC3GLMatrix * projection = [CC3GLMatrix matrix];
height = width * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-width/2 andRight:width/2 andBottom:-height/2 andTop:height/2 andNear:4 andFar:10];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);

CC3GLMatrix * modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(xTranslation ,yTranslation, -7)];
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

在触摸开始的方法中,我试图将触摸点坐标映射到OpenGL ES 2.0场景坐标:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"Touches Began");
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self];

float differentialWidth = (768-width)/2; //Accounts for if OpenGL view is less than iPad width or height.
float differentialHeight = (1024-height)/2;
float openGlXPoint = ((touchPoint.x - differentialWidth) - (width/2));
float openGlYPoint = ((touchPoint.y - differentialHeight) - (width/2));
NSLog(@"X in Scene Touched is %f", openGlXPoint);

CGPoint finalPoint = CGPointMake(openGlXPoint, openGlYPoint);

for (SquareObject * square in squareArray) {
    if (CGRectContainsPoint(stand.bounds, finalPoint)) {
        NSString * messageSquare = (@"Object name is %@", square.Name);
        UIAlertView *message = [[UIAlertView alloc] initWithTitle:@"Touched"
                                                          message:messageSquare
                                                         delegate:nil
                                                cancelButtonTitle:@"OK"
                                                otherButtonTitles:nil];
        [message show];
    }
}
}

此代码的工作原理是它返回OpenGL坐标 - 例如,单击屏幕中间成功返回0,0。然而问题是(我认为)我在某种程度上需要考虑场景的缩放比例,因为用150,0的原点绘制的对象与我点击iPad的位置不匹配(返回112,0)使用上面的代码)。任何人都可以建议我如何纠正这个问题?

谢谢!

1 个答案:

答案 0 :(得分:2)

对于2D应用程序来说这可能有些过分,但对于3D应用程序通常这样做的方法是制作两个向量,一个“远点”和一个“近点”,使用GLKUnproject或其他任何一个来取消它们的投影。您想要的其他数学库,然后从远点减去近点以获得对象坐标中的光线,您可以使用该光线仅使用几何来测试交点,而无需担心投影或模型视图矩阵。这是一个例子

bool testResult;
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

GLKVector3 nearPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, tapLoc.y, 0.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);

GLKVector3 farPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, tapLoc.y, 1.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);

farPt = GLKVector3Subtract(farPt, nearPt);
//now you can test if the farPt ray intersects the geometry of interest, perhaps
//using a method like the one described here http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf

在您的情况下,投影矩阵可能是您在二维工作的身份,而modelViewMatrix是您应用于对象的比例,平移,旋转,剪切等。

此外,如果您不知道,您所询问的内容通常被称为“拣选”,如果您在Google中输入“OpenGL拣货”,您可能会发现有关此主题的更多信息,而不是您之前可能获得的信息。只需“转换坐标。”