iPhone4 OpenGL GLUES项目返回错误的y坐标
几个月来,我一直在断断续续地尝试解决iPhone 4 OpenGL ES应用程序的一个令人困惑的问题,尽管在这个网站上有一些非常有用和诱人的提示和建议,但它已经走到了死胡同iPhone4 OpenGL GLUES项目返回错误的y坐标,iphone,opengl-es,3d,glu,Iphone,Opengl Es,3d,Glu,几个月来,我一直在断断续续地尝试解决iPhone 4 OpenGL ES应用程序的一个令人困惑的问题,尽管在这个网站上有一些非常有用和诱人的提示和建议,但它已经走到了死胡同 我正在编写一个3D游戏,它简单地绘制块,并允许用户将它们移动到不同的排列中,并且大部分的应用程序是用C++编写的。 我的问题是我试图使用GLuUnproject,我在这里找到了源代码: 为了解释用户选择的3d点(以及块),以便移动和旋转它,我将其转换为浮点,而不是双精度 请注意,我已经将此源代码与网络上的其他版本进行了比较
我正在编写一个3D游戏,它简单地绘制块,并允许用户将它们移动到不同的排列中,并且大部分的应用程序是用C++编写的。 我的问题是我试图使用GLuUnproject,我在这里找到了源代码:
为了解释用户选择的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;
}
- (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];
}
}
同样,结果与光线跟踪方法一致,即当用户在屏幕上方单击时,投影的y坐标变得越来越错误
例如,当ToucheSStart事件直接报告的单击位置为(246190)时,计算位置为(246215),y偏差为25
当ToucheSStart事件直接报告的点击位置为(246398)时,计算位置为(246405),y偏差为7
x坐标似乎很准确
我注意到,当视口高度设置为480(全屏高度)时,layer.bounds.size.height报告为436。层边界宽度报告为320,这也是视口的宽度
436的值似乎是固定的,无论我使用什么视口大小,也不管我是否在窗口顶部显示状态屏幕
在以下调用之前,已尝试将bounds.size.height设置为480:
[my_context
renderbufferStorage:GL_RENDERBUFFER
fromDrawable: eaglLayer];
但这似乎被忽略了,后来在电话中报告高度为436:
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_HEIGHT_OES, &height);
我看过一些关于点和像素差异以及可能需要缩放的讨论,但我一直在努力有效地使用这些信息,因为这些信息暗示差异是由于iPhone4的视网膜显示分辨率,模拟器和实际设备需要不同的缩放。然而,据我所知,模拟器和设备的行为是一致的
2011年8月30日由于没有收到任何反馈,我是否可以提供更多信息,使问题更容易处理
2011年8月31日OpenGL设置和显示代码如下:
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;
}
- (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];
}
}
当保存渲染器的视图调整大小时,将通过以下方式通知它:
- (void) layoutSubviews
{
[renderer resizeFromLayer:(CAEAGLLayer*)self.layer];
[self drawView:nil];
}
- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer
{
// Allocate color buffer backing based on the current layer size
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderBuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer];
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
{
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
[self recreatePerspectiveProjectionMatrix];
return YES;
}
请注意,由于视图端口大小已更改,应正确重新创建透视矩阵。这将对联合国项目的结果产生影响
与规模问题相关:
内部视图初始化获取比例因子:
CGFloat scale = 1;
if ([self respondsToSelector:@selector(getContentScaleFactor:)])
{
self.contentScaleFactor = [[UIScreen mainScreen] scale];
scale = self.contentScaleFactor;
}
在标准和视网膜显示器上,视图的大小实际上是相同的,320像素宽,但对于640像素的视网膜,渲染层的大小将增加一倍。在opengl渲染器空间和视图空间之间转换时,应考虑比例因子
添加:
尝试更改初始化代码中获取和设置宽度和高度参数的顺序:
与此相反:
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);
尝试此顺序(不要使用视图中的尺寸):
另外,请确保已为全屏布局设置UIController参数:
self.wantsFullScreenLayout = YES;
之后,对于iPhone4,宽度和高度应该正好是640x960,contentScaleFactor应该是2
但是,还要注意,LayoutSubview是标准的UIView功能,它是我获取屏幕大小和调整投影或平截头体矩阵的唯一地方。嗯……我现在觉得有点愚蠢 问题是,我使用的视图实际上是436像素高,这是我在很久以前尝试在主窗口上为我不再使用的公共导航栏留出空间时设置的 将其设置回480解决了问题 向那些看到这一点的人道歉,尤其是那些作出回应的人
在经历了几个月的挫折之后,我现在要去把自己从痛苦中解脱出来 你怎么会在屏幕上出现一个骗局?如果您已经围绕它构建了一个UIView,它有什么框架?436与426惊人地相似-您确定您的视图或代码没有在某个地方假设或试图强制使用4:3的纵横比吗?@Tommy。谢谢你的提问。我有一个名为GLView的自定义类,上面添加了方法(从函数调用调用的一些代码以内联方式显示,以便于理解)。感谢您的反馈,但我不确定如何使用它。初始化后,视口大小不会更改。也许我现在提供的附加代码将更好地显示我正在尝试做什么?我尝试添加您在initWithCoder方法中提供的缩放代码,它总是返回1,但这是因为if语句不满足。Oops。很抱歉我从头开始写。将getContentScaleFactor替换为setContentScaleFactor。我查了我的资料来源。另请看我的最新评论。再次感谢-仍在挣扎-道歉。已包含对缩放检查的更改,现在将调用此项,但返回值1以恢复缩放。根据建议计算宽度/高度(而不是框架大小)似乎使两个测试用例的y形下降率都增加了15