У меня непонятная проблема с приложением iPhone 4 OpenGL ES, которую я пытался решать и выключать уже пару месяцев и зашел в тупик, несмотря на некоторые действительно полезные и заманчивые советы и предложения на этом сайте.
Я пишу 3d-игру, которая просто рисует блоки и позволяет пользователю перемещать их по различным схемам, а основная часть приложения написана на C ++.
Моя проблема в том, что я пытаюсь использовать GLuUnproject, исходный код которого я нашел здесь:
http://webcvs.freedesktop.org/mesa/Mesa/src/glu/mesa/project.c?view=markup
для интерпретации выбранной пользователем 3d-точки (и, следовательно, блока), чтобы переместить и повернуть ее, которую я перенес в плавающую точку, а не с двойной точностью.
Обратите внимание, что я сравнил этот источник с другими версиями в сети, и он выглядит согласованным.
Я использую следующий код для получения вектора луча:
Ray RenderingEngine::GetRayVector( vec2 winPos ) const
{
// Get the last matrices used
glGetFloatv( GL_MODELVIEW_MATRIX, __modelview );
glGetFloatv( GL_PROJECTION_MATRIX, __projection );
glGetIntegerv( GL_VIEWPORT, __viewport );
// Flip the y coordinate
winPos.y = (float)__viewport[3] - winPos.y;
// Create vectors to be set
vec3 nearPoint;
vec3 farPoint;
Ray rayVector;
//Retrieving position projected on near plan
gluUnProject( winPos.x, winPos.y , 0,
__modelview, __projection, __viewport,
&nearPoint.x, &nearPoint.y, &nearPoint.z);
//Retrieving position projected on far plan
gluUnProject( winPos.x, winPos.y, 1,
__modelview, __projection, __viewport,
&farPoint.x, &farPoint.y, &farPoint.z);
rayVector.nearPoint = nearPoint;
rayVector.farPoint = farPoint;
//Return the ray vector
return rayVector;
}
Векторный код для отслеживания возвращенного луча из ближней плоскости в дальнюю плоскость прост, и я обнаружил, что блоки в нижней части экрана идентифицированы правильно, но при перемещении вверх по экрану наблюдается растущее расхождение в сообщенных значениях y и ожидаемых значениях y для выбранных точек.
Я также попытался с помощью GLuProject вручную проверить, какие экранные координаты генерируются для моих координат мира, следующим образом:
vec3 RenderingEngine::GetScreenCoordinates( vec3 objectPos ) const
{
// Get the last matrices used
glGetFloatv( GL_MODELVIEW_MATRIX, __modelview );
glGetFloatv( GL_PROJECTION_MATRIX, __projection );
glGetIntegerv( GL_VIEWPORT, __viewport );
vec3 winPos;
gluProject(objectPos.x, objectPos.y, objectPos.z ,
__modelview, __projection, __viewport,
&winPos.x, &winPos.y, &winPos.z);
// Swap the y value
winPos.y = (float)__viewport[3] - winPos.y;
return winPos;
}
Опять же, результаты согласуются с подходом трассировки лучей в том смысле, что координата GLuProjected y становится все более неправильной, когда пользователь нажимает вверх по экрану.
Например, когда позиция щелчка, о которой напрямую сообщило событие touchesBegan, равна (246 190), вычисленная позиция равна (246, 215), при этом y равно 25.
Когда позиция щелчка, о которой напрямую сообщило событие touchesBegan, равна (246 398), вычисленная позиция равна (246, 405), y - несоответствие 7.
Кажется, что координата x точечная.
Я заметил, что layer.bounds.size.height сообщается как 436, когда высота области просмотра установлена на 480 (высота полного экрана). Ширина границ слоя указывается как 320, что также является шириной области просмотра.
Значение 436, по-видимому, является фиксированным независимо от того, какой размер области просмотра я использую или отображаю ли я экран состояния в верхней части окна.
Пробовали установить bounds.size.height равным 480 до следующего вызова:
[my_context
renderbufferStorage:GL_RENDERBUFFER
fromDrawable: eaglLayer];
Но это, кажется, игнорируется, и высота сообщается позже как 436 в вызове:
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_HEIGHT_OES, &height);
Я видел некоторое обсуждение разницы в точках и пикселях и возможной необходимости масштабирования, но изо всех сил пытался использовать эту информацию с пользой, поскольку они намекали на то, что различие было связано с разрешением экрана сетчатки iPhone 4 и с другим масштабированием потребуется для симулятора и фактического устройства. Однако, насколько я могу судить, симулятор и устройство ведут себя согласованно.
30-Aug-2011 Поскольку я не получаю отзывов об этом - могу ли я предоставить больше информации, чтобы сделать вопрос более податливым?
31 августа 2011 г. Настройка OpenGL и отображение кода следующим образом:
- (id) initWithCoder:(NSCoder*)coder
{
if ((self = [super initWithCoder:coder]))
{
// Create OpenGL friendly layer to draw in
CAEAGLLayer* eaglLayer = (CAEAGLLayer*) self.layer;
eaglLayer.opaque = YES;
// eaglLayer.bounds.size.width and eaglLayer.bounds.size.height are
// always 320 and 436 at this point
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES1;
m_context = [[EAGLContext alloc] initWithAPI:api];
// check have a context
if (!m_context || ![EAGLContext setCurrentContext:m_context]) {
[self release];
return nil;
}
glGenRenderbuffersOES(1, &m_colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
[m_context
renderbufferStorage:GL_RENDERBUFFER
fromDrawable: eaglLayer];
UIScreen *scr = [UIScreen mainScreen];
CGRect rect = scr.applicationFrame;
int width = CGRectGetWidth(rect); // Always 320
int height = CGRectGetHeight(rect); // Always 480 (status bar not displayed)
// Initialise the main code
m_applicationEngine->Initialise(width, height);
// This is the key c++ code invoked in Initialise call shown here indented
// Setup viewport
LowerLeft = ivec2(0,0);
ViewportSize = ivec2(width,height);
// Code to create vertex and index buffers not shown here
// …
// Extract width and height from the color buffer.
int width, height;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_WIDTH_OES, &width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_HEIGHT_OES, &height);
// Create a depth buffer that has the same size as the color buffer.
glGenRenderbuffersOES(1, &m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
width, height);
// Create the framebuffer object.
GLuint framebuffer;
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES, m_colorRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES,
GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
// Set up various GL states.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
// ...Back in initiWithCoder
// Do those things which need to happen when the main code is reset
m_applicationEngine->Reset();
// This is the key c++ code invoked in Reset call shown here indented
// Set initial camera position where
// eye=(0.7,8,-8), m_target=(0,4,0), CAMERA_UP=(0,-1,0)
m_main_camera = mat4::LookAt(eye, m_target, CAMERA_UP);
// ...Back in initiWithCoder
[self drawView: nil];
m_timestamp = CACurrentMediaTime();
// Create timer object that allows application to synchronise its
// drawing to the refresh rate of the display.
CADisplayLink* displayLink;
displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(drawView:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
return self;
}
- (void) drawView: (CADisplayLink*) displayLink
{
if (displayLink != nil) {
// Invoke main rendering code
m_applicationEngine->Render();
// This is the key c++ code invoked in Render call shown here indented
// Do the background
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// A set of objects are provided to this method
// for each one (called visual below) do the following:
// Set the viewport transform.
glViewport(LowerLeft.x, LowerLeft.y, ViewportSize.x, ViewportSize.y);
// Set the model view and projection transforms
// Frustum(T left, T right, T bottom, T top, T near, T far)
float h = 4.0f * size.y / size.x;
mat4 modelview = visual->Rotation * visual->Translation * m_main_camera;
mat4 projection = mat4::Frustum(-1.5, 1.5, h/2, -h/2, 4, 14);
// Load the model view matrix and initialise
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLoadMatrixf(modelview.Pointer());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glLoadMatrixf(projection.Pointer());
// Draw the surface - code not shown
// …
// ...Back in drawView
[m_context presentRenderbuffer:GL_RENDERBUFFER];
}
}