我正在尝试使用GLKMathUnproject()
将屏幕坐标转换为几何图形,但我的例程总是返回屏幕中心的任何几何图形。
我的非项目代码如下所示:
+ (GLKVector3) gluUnproject: (GLKVector3) screenPoint
inView: (UIView*) view
withModelMatrix: (GLKMatrix4) model
projection: (GLKMatrix4) projection
{
CGSize viewSize = view.bounds.size;
int viewport[4];
viewport[0] = 0.0f;
viewport[1] = 0.0f;
viewport[2] = viewSize.width;
viewport[3] = viewSize.height;
bool success;
GLKVector3 result = GLKMathUnproject(screenPoint, model, projection, &viewport[0], &success);
return result;
}
我对它的调用看起来像这样:
- (void) handleSingleTap: (UIGestureRecognizer*) sender
{
UITapGestureRecognizer *tapper = (UITapGestureRecognizer*) sender;
CGPoint tapPoint = [tapper locationInView: self.view];
// Find tapped point on geometry
MyObject *bd = [worldObjects objectAtIndex: 0]; // the object on which I'm trying to sense the tap.
// NOTE: bd is planar, along X/Z, with Y=0. Visually, it's several little
// ..squares (like a big checkerboard), and I'm trying to determine
// ..in which square the user tapped.
// At this point. eyesAt is { someX, y, someZ } and lookAt is { someX, 0, someZ } and
// ..upVector is { 0, 0, -1 }. We Zoom our view of the board in/out by
// ..changing eyesAt.y
float tapZ = (self.eyesAt.y - self.zNear) / (self.zFar - self.zNear); // % of the Z-depth. eyesAt.y = distance to geometry.
GLKVector3 tapPoint3 = GLKVector3Make(tapPoint.x, tapPoint.y, tapZ);
GLKVector3 tapAt = [MFglkUtils gluUnproject: tapPoint3 inView: self.view withModelMatrix: bd.modelviewMatrix projection: [self projectionMatrix]];
// etc., snip -- do stuff with the tapAt point.
问题是:我的gluUnproject
总是返回屏幕中间任何位置的几何点,无论我在哪里点击。
修改 “总是靠近中心”问题是返回的X / Z值总是非常接近零,并且我的几何体以原点为中心。
看起来问题出在我的tapZ
值上。我的理解是,这应该是0-1的值,其中0表示“在nearZ平面”,1表示“在farZ平面”,中间值是介于两者之间的百分比。尝试了各种tapZ
值,我看到了:
// gives very-very small results
tapZ = (self.eyesAt.y - self.zNear) / (self.zFar - self.zNear); // % deep through the view frustum
// gives Z=0, and very small results
glReadPixels(viewPoint.x, viewPoint.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &tapZ);
// gives approximately-correct results
tapZ = 0.99943; // found through trial & error
// gives Z=1, and too-big results
glReadPixels(viewPoint.x, viewPoint.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &tapZ);
tapZ = 1. - tapZ;
显然,我需要传递正确的tapZ
值,但我不明白如何达到它!
答案 0 :(得分:0)
好的,哇!事实证明问题是我的tapZ值,问题与深度缓冲区Z值不是线性的事实有关。 (更多关于那种祸害here。)
无论如何,使用glProject()将一个有问题的几何体投影到屏幕上(记住,我正在处理一个平板棋盘的俯视图!),给我一个我想要的z值。最终结果代码如下:
- (GLKVector3) vectorFromTapPoint: (CGPoint) tapPoint
{
tapPoint.y = (self.view.bounds.size.height - tapPoint.y);
BlockDiagram *bd = [worldObjects objectAtIndex: 0];
// find Z-depth of center of board
GLKVector3 v3Zero = { 0, 0, 0 };
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
GLKVector3 worldZero = GLKMathProject(v3Zero, bd.modelviewMatrix, [self projectionMatrix], viewport);
// Find tapped point on geometry
float tapZ = worldZero.z;
GLKVector3 tapPoint3 = GLKVector3Make(tapPoint.x, tapPoint.y, tapZ);
GLKVector3 tapAt = [MFglkUtils gluUnproject: tapPoint3 inView: self.view withModelMatrix: bd.modelviewMatrix projection: [self projectionMatrix]];
return tapAt;
}
和gluUnProject被修改为:
+ (GLKVector3) gluUnproject: (GLKVector3) screenPoint
inView: (UIView*) view
withModelMatrix: (GLKMatrix4) model
projection: (GLKMatrix4) projection
{
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
bool success;
GLKVector3 result = GLKMathUnproject(screenPoint, model, projection, &viewport[0], &success);
return result;
}
注意:要求视口的glGet *()给出正确定位(我的应用是横向)值,这也很重要!