我开始开发3D粒子系统编辑器和演化器。我过去用OpenGL做过类似的事情,但这次我要做一个macosx可可应用程序。我只是有几个关于我在设置OpenGL时不断遇到的一些代码的问题。
1) 为什么我在网上看到很多人在使用。。。
[self setNeedsDisplay:YES];
这是让OpenGL渲染的正确方法吗?我现在知道这会导致drawRect被调用,但这是正确的方法吗?
2) drawRect是我应该为渲染帧方法覆盖的正确方法吗?
以下是我在网上不断遇到的代码:
-(void) prepareOpenGL {
[[self window] makeFirstResponder:self];
glClearColor(1.0f, 1.0f, 0.0f, 10.f);
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0/60.0 target:self selector:@selector(idle:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
-(void)idle:(NSTimer *)timer {
if(![[NSApplication sharedApplication] isHidden])
[self setNeedsDisplay:YES];
}
-(void) drawRect:(NSRect)dirtyRect {
glClear(GL_COLOR_BUFFER_BIT);
}
您还没有指明是在NSOpenGLView还是CAOpenGLLayer中绘制OpenGL内容。这两种更新内容以显示在屏幕上的方式略有不同。
对于NSOpenGLView,不需要在其-drawRect:
方法中更新视图。事实上,我认为您不希望触发-setNeedsDisplay:
来刷新NSView,因为这可能会产生一些开销。在我的一个应用程序中,我使用CVDisplayLink在NSOpenGLView中的自定义渲染方法中以60 FPS触发更新。这些都不涉及-drawRect:
。帧在调用[[self openGLContext] flushBuffer]
时显示在屏幕上,而不是通过强制重新绘制NSView。
CAOpenGLLayers有点不同,因为您使用自定义渲染代码覆盖- drawInCGLContext:pixelFormat:forLayerTime:displayTime:
。此方法是响应手动-setNeedsDisplay
而触发的,或者如果其asynchronous
属性设置为YES,则由CAOpenGLLayer本身触发。它通过您为响应-canDrawInCGLContext:pixelFormat:forLayerTime:displayTime:
而提供的布尔值来知道何时准备好呈现新内容。
这两种我都用过,每种都有优点。CAOpenGLLayers使在OpenGL渲染中覆盖其他UI元素变得更加容易,但它们的渲染方法可能很难从后台线程中正确工作。NSOpenGLViews可以使用CVDisplayLink在后台线程上轻松更新,但很难覆盖内容。