Мой GLKMathUnproject всегда возвращает геометрию, которая находится в центре экрана
Я пытаюсь использовать 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
ценность, но я не понимаю, как к этому прийти!
1 ответ
Хорошо, вот так! Оказывается, что проблема была в моем значении tapZ, и проблема связана с тем, что значения Z буфера глубины не являются линейными. (Подробнее об этом чудаке здесь.)
В любом случае, используя 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*() для области просмотра дал правильно ориентированные (мое приложение - альбомная) значения, что также имеет значение!