gluPerspective 和 gluLookAt 的奇怪行为
Strange behaviour with gluPerspective and gluLookAt
对于一个项目,我需要实现一个 NSOpenGLView。我找到了一些资源(教程、苹果文档......)可以开始,但是当我尝试使用 gluPerspective 和 GluLookAt 时,我有一些奇怪的行为(我的立方体的顶点被截断,并且面被绘制在彼此上方作为如果没有深度缓冲区)。这是我的 OpenGLView (NSOpenGLView class) 的实现。
注意 1 : 我需要我的应用程序与 OSX 10.6 兼容,这意味着我必须使用 OpenGL 2.1。
注意 2 : 我无法使用 Interface Builder。我需要以编程方式初始化 NSOpenGLView。
更新:gluPerspective zNear 和 zFar,以及 gluLookAt 眼睛参数已被修改以更正顶点被截断的问题。但是画错脸的问题依然存在。这里有图片来说明:
更新 2:最后我通过阅读标题为 "OpenGL GL_DEPTH_TEST not working" 的问题找到了答案。解决方案是:如果您想在没有 Interface Builder 的情况下创建 NSOpenGLView,则必须以编程方式设置 pixelFormat。我为遇到同样问题的人更正我的代码。
OpenGLView.m
#import "OpenGLView.h"
@interface OpenGLView ()
{
NSTimer *updateTimer;
float cubeRotationAngle;
}
@end
@implementation OpenGLView
-(id)initWithFrame:(NSRect)contentRect pixelFormat:(NSOpenGLPixelFormat *)format
{
if(self = [super initWithFrame:(NSRect)contentRect pixelFormat:format])
{
[self setFrame:contentRect];
updateTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(redraw) userInfo:nil repeats:YES] retain];
[[NSRunLoop currentRunLoop] addTimer:updateTimer forMode:NSRunLoopCommonModes];
}
return self;
}
- (void)prepareOpenGL
{
[[self openGLContext] makeCurrentContext];
}
- (void)drawRect:(NSRect)rect
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 1.0, 1.0, 10.0);
glEnable(GL_DEPTH_TEST);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLdouble eyeX = 2.0;
GLdouble eyeY = 2.0;
GLdouble eyeZ = 2.0;
GLdouble targetX = 0.0;
GLdouble targetY = 0.0;
GLdouble targetZ = 0.0;
GLdouble verticalVectorX = 0.0;
GLdouble verticalVectorY = 0.0;
GLdouble verticalVectorZ = 1.0;
gluLookAt(eyeX, eyeY, eyeZ, targetX, targetY, targetZ, verticalVectorX, verticalVectorY, verticalVectorZ);
cubeRotationAngle = cubeRotationAngle + 0.5;
glRotatef(cubeRotationAngle, 2.0, 0.5, 0.5);
float size = 0.4;
glBegin(GL_QUADS);
{
//Blue face
glColor3f(0, 0, 1);
glVertex3f(-1*size, 1*size, -1*size);
glVertex3f( 1*size, 1*size, -1*size);
glVertex3f( 1*size, -1*size, -1*size);
glVertex3f(-1*size, -1*size, -1*size);
//Red face
glColor3f(1, 0, 0);
glVertex3f(-1*size, -1*size, -1*size);
glVertex3f( 1*size, -1*size, -1*size);
glVertex3f( 1*size, -1*size, 1*size);
glVertex3f(-1*size, -1*size, 1*size);
//Green face
glColor3f(0, 1, 0);
glVertex3f(-1*size, 1*size, 1*size);
glVertex3f( 1*size, 1*size, 1*size);
glVertex3f( 1*size, -1*size, 1*size);
glVertex3f(-1*size, -1*size, 1*size);
//Yellow face
glColor3f(1, 1, 0);
glVertex3f(-1*size, 1*size, 1*size);
glVertex3f(-1*size, 1*size, -1*size);
glVertex3f(-1*size, -1*size, -1*size);
glVertex3f(-1*size, -1*size, 1*size);
//Pink face
glColor3f(1, 0, 1);
glVertex3f(-1*size, 1*size, 1*size);
glVertex3f( 1*size, 1*size, 1*size);
glVertex3f( 1*size, 1*size, -1*size);
glVertex3f(-1*size, 1*size, -1*size);
//light blue face
glColor3f(0, 1, 1);
glVertex3f( 1*size, 1*size, -1*size);
glVertex3f( 1*size, 1*size, 1*size);
glVertex3f( 1*size, -1*size, 1*size);
glVertex3f( 1*size, -1*size, -1*size);
}
glEnd();
glPopMatrix();
glFlush();
}
- (void)redraw
{
[self setNeedsDisplay:YES];
}
然后你必须像这样实例化 OpenGLView :
NSOpenGLPixelFormatAttribute attrs[] = {NSOpenGLPFADepthSize, 32, 0};
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
openGLView = [[OpenGLView alloc] initWithFrame:NSMakeRect(20, 20, 760, 560) pixelFormat:format];
您的 gluPerspective
调用无效,因此只会产生错误并保持当前矩阵不变。
near
和 far
参数都必须是 positive,并且它们也不能彼此相等(因此您的注释值无效)。
这些值定义了从投影中心到近裁剪平面和远裁剪平面的符号距离,因此负值将参考相机后面的规格,这不会使最轻微的感觉(并且也会 运行 在几个与相机平面相交的图元的裁剪相关问题中)。
对于一个项目,我需要实现一个 NSOpenGLView。我找到了一些资源(教程、苹果文档......)可以开始,但是当我尝试使用 gluPerspective 和 GluLookAt 时,我有一些奇怪的行为(我的立方体的顶点被截断,并且面被绘制在彼此上方作为如果没有深度缓冲区)。这是我的 OpenGLView (NSOpenGLView class) 的实现。
注意 1 : 我需要我的应用程序与 OSX 10.6 兼容,这意味着我必须使用 OpenGL 2.1。
注意 2 : 我无法使用 Interface Builder。我需要以编程方式初始化 NSOpenGLView。
更新:gluPerspective zNear 和 zFar,以及 gluLookAt 眼睛参数已被修改以更正顶点被截断的问题。但是画错脸的问题依然存在。这里有图片来说明:
更新 2:最后我通过阅读标题为 "OpenGL GL_DEPTH_TEST not working" 的问题找到了答案。解决方案是:如果您想在没有 Interface Builder 的情况下创建 NSOpenGLView,则必须以编程方式设置 pixelFormat。我为遇到同样问题的人更正我的代码。
OpenGLView.m
#import "OpenGLView.h"
@interface OpenGLView ()
{
NSTimer *updateTimer;
float cubeRotationAngle;
}
@end
@implementation OpenGLView
-(id)initWithFrame:(NSRect)contentRect pixelFormat:(NSOpenGLPixelFormat *)format
{
if(self = [super initWithFrame:(NSRect)contentRect pixelFormat:format])
{
[self setFrame:contentRect];
updateTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(redraw) userInfo:nil repeats:YES] retain];
[[NSRunLoop currentRunLoop] addTimer:updateTimer forMode:NSRunLoopCommonModes];
}
return self;
}
- (void)prepareOpenGL
{
[[self openGLContext] makeCurrentContext];
}
- (void)drawRect:(NSRect)rect
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 1.0, 1.0, 10.0);
glEnable(GL_DEPTH_TEST);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLdouble eyeX = 2.0;
GLdouble eyeY = 2.0;
GLdouble eyeZ = 2.0;
GLdouble targetX = 0.0;
GLdouble targetY = 0.0;
GLdouble targetZ = 0.0;
GLdouble verticalVectorX = 0.0;
GLdouble verticalVectorY = 0.0;
GLdouble verticalVectorZ = 1.0;
gluLookAt(eyeX, eyeY, eyeZ, targetX, targetY, targetZ, verticalVectorX, verticalVectorY, verticalVectorZ);
cubeRotationAngle = cubeRotationAngle + 0.5;
glRotatef(cubeRotationAngle, 2.0, 0.5, 0.5);
float size = 0.4;
glBegin(GL_QUADS);
{
//Blue face
glColor3f(0, 0, 1);
glVertex3f(-1*size, 1*size, -1*size);
glVertex3f( 1*size, 1*size, -1*size);
glVertex3f( 1*size, -1*size, -1*size);
glVertex3f(-1*size, -1*size, -1*size);
//Red face
glColor3f(1, 0, 0);
glVertex3f(-1*size, -1*size, -1*size);
glVertex3f( 1*size, -1*size, -1*size);
glVertex3f( 1*size, -1*size, 1*size);
glVertex3f(-1*size, -1*size, 1*size);
//Green face
glColor3f(0, 1, 0);
glVertex3f(-1*size, 1*size, 1*size);
glVertex3f( 1*size, 1*size, 1*size);
glVertex3f( 1*size, -1*size, 1*size);
glVertex3f(-1*size, -1*size, 1*size);
//Yellow face
glColor3f(1, 1, 0);
glVertex3f(-1*size, 1*size, 1*size);
glVertex3f(-1*size, 1*size, -1*size);
glVertex3f(-1*size, -1*size, -1*size);
glVertex3f(-1*size, -1*size, 1*size);
//Pink face
glColor3f(1, 0, 1);
glVertex3f(-1*size, 1*size, 1*size);
glVertex3f( 1*size, 1*size, 1*size);
glVertex3f( 1*size, 1*size, -1*size);
glVertex3f(-1*size, 1*size, -1*size);
//light blue face
glColor3f(0, 1, 1);
glVertex3f( 1*size, 1*size, -1*size);
glVertex3f( 1*size, 1*size, 1*size);
glVertex3f( 1*size, -1*size, 1*size);
glVertex3f( 1*size, -1*size, -1*size);
}
glEnd();
glPopMatrix();
glFlush();
}
- (void)redraw
{
[self setNeedsDisplay:YES];
}
然后你必须像这样实例化 OpenGLView :
NSOpenGLPixelFormatAttribute attrs[] = {NSOpenGLPFADepthSize, 32, 0};
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
openGLView = [[OpenGLView alloc] initWithFrame:NSMakeRect(20, 20, 760, 560) pixelFormat:format];
您的 gluPerspective
调用无效,因此只会产生错误并保持当前矩阵不变。
near
和 far
参数都必须是 positive,并且它们也不能彼此相等(因此您的注释值无效)。
这些值定义了从投影中心到近裁剪平面和远裁剪平面的符号距离,因此负值将参考相机后面的规格,这不会使最轻微的感觉(并且也会 运行 在几个与相机平面相交的图元的裁剪相关问题中)。