OpenGL ES 教程-初稿-00
原始贴的位置: http://www.cocoachina.com/bbs/read.php?tid-5306.html
关于iPhone的 OpenGL ES是建立在Xcode下,苹果推出的sdk版本中包含这个模板。我们要做的的就是帮助您建立这个模板,并在真正需要的地方方便快捷的添加有用的代码。这就是我们今天要做的。 打开 XCode并创建一个新的工程。选择”OpenGL ES Application”,并且保存工程在你经常使用的位置。
好吧,我要承认一点,你之前可能快速浏览过模板,或者看过模板的运行程序。我们要做的就是删除自旋的彩色立方体的代码,并添加用深度缓冲来转换视图(让它看起来更象是一个真的3d)。这将为我们的教程提供一个空间。 在3d空间里的2d 象这个苹果的模板一样,大多数的OpenGL教程都是从忽略深度(缓冲)开始,通常使用2点的坐标系统(x,y),而不是更为标准的3点的坐标系(x,y,z)。
你可能已经注意到了,苹果模板里的立方体的顶点只使用了(x,y)的坐标,这是因为他们没有使用深度。 这就是所谓的正投影。本教程系列的目的就是让你掌握3d,我将不会在正投影做重复介绍;当然,以后也许会。但现在,我们把精力保持在3d上。 启用深度缓冲 第一件事我们需要启动深度缓冲。苹果的例子中,正方形只是一个2d的物体,所以实际上不需要深度缓冲。我们需要深度所以我们启用它。苹果热心的提供了关于设置深度缓冲的代码,所以我们只需要利用它。
打开 EAGLView.m在编辑区,看下面这行代码:
#define USE_DEPTH_BUFFER 0
不用说,将0修改为1。这将打开视窗里的设置区域并创建深度缓冲。
这个代码包含在createFrameBuffer这个函数中。此刻不要对这个函数担心太多。这是苹果写的,必然支持这样的写法。 现在,我们需要在OpenGL内部启用深度缓冲。要做到这一点,我们需要创建一个新的函数,这个函数将被启用在我们视窗工作的时候。
我们开始创建一个新的函数,叫 setupView 并且将下列的代码添加到这个新的函数里。
- (void)setupView
{
const GLfloat zNear = 0.1, zFar = 1000.0, fieldOfView = 60.0;
GLfloat size;
// This enables the Depth Testing in OpenGL
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
// This give us the size of the iPhone display
CGRect rect = self.bounds;
glFrustumf(-size, size, -size/(rect.size.width/rect.size.height),size/(rect.size.width/rect.size.height), zNear,zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
// defining what colour to use when we clear the screen
glClearColor(0.0f,0.0f,0.0f,1.0f);
}
所有的这些代码的作用是设置OpenGl的参数,它将操作于创建一个视窗端口正在被映射到我们显示的实际大小。就象我说的一样,我将详细谈这点,但现在,只需要注意以下内容: glEnable(GL_DEPTH_TEST); 这将在OpenGL中启用深度测试。你必须记得,一旦你在OpenGL中将某些事物改为“开启”,你必须在不要使用它的时候关闭它。我们开启了深度测试并且不再关闭它,它可以在视窗的这里设置。
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 我们要做的就是用默认的颜色去清除屏幕。
在OpenGL ES中使用的所有颜色都必须是是RGBA值,而不是在OpenGL中的RGB值,所以当我们清除屏幕,OpenGL ES就知道我们要用黑色来清除屏幕。它将继续使用这个颜色直到我们改变它。 这个颜色的值范围,浮点是0-1,无符号数是0-255。这个颜色的值越高,这个颜色的强度也越高。
Ok,返回文件的开头,到我们刚才修改的 #define的地方。我们需要在这里定义一个宏,这个宏将在 setupView函数中使用到。
#define USE_DEPTH_BUFFER 1
#define DEGREES_TO_RADIANS(__ANGLE) ((__ANGLE) / 180.0 * M_PI) Draw View
-绘制函数 现在,到下面的 drawView 函数。在我们的教程中,发生的所有事都在这里。你可以在这里看到,苹果给了我们一个事实上的指针,这正是我们需要做的工作。 首先,删除一切这个函数中的代码,并用我们下面的代码去填充它。
-(void)drawView
{
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
上面的头三行代码,就是设置我们的绘制空间。后面两行代码,将我们的绘制空间与屏幕显示空间互换。如果你之前做过动画或游戏的编程,你会知道,这就是所谓的“双缓冲”。 对于那些不知道的朋友呢,我们再解释一下,我们创建了两个缓冲界面,一个用于给用户显示,一个我们清除掉并且我们在它上面进行绘制。当我们完成绘制后,我们就翻转视窗,那么用户就看到了新的视窗。为什么我们要搞的这么麻烦呢?这是为了要动画流畅。 此刻,我们不要为了显示添加任何代码了,我们仍然要做一些设置工作。 首先,在dealloc函数之前,插入以下的代码:
- (void)checkGLError:(BOOL)visibleCheck{
GLenum error = glGetError();
switch (error) {
case GL_INVALID_ENUM:
NSLog(@"GL Error: Enum argument is out of range");
break;
case GL_INVALID_VALUE:
NSLog(@"GL Error: Numeric value is out of range");
break;
case GL_INVALID_OPERATION:
NSLog(@"GL Error: Operation illegal in current state");
break;
case GL_STACK_OVERFLOW:
NSLog(@"GL Error: Command would cause a stack overflow");
break;
case GL_STACK_UNDERFLOW:
NSLog(@"GL Error: Command would cause a stack underflow");
break;
case GL_OUT_OF_MEMORY:
NSLog(@"GL Error: Not enough memory to execute command");
break;
case GL_NO_ERROR:
if (visibleCheck) {
NSLog(@"No GL Error");
}
break;
default:
NSLog(@"Unknown GL Error");
break;
}
}
OpenGL 有一个错误检测的函数,叫做(glGetError()),但是这个函数返回的出错信息,我们要手动转换下,不然开发者将无法阅读。这个就是上面这个函数的作用。 这个bool参数“visibleCheck”只能在这,有时候你可以检测并且看到这个例子调用,并且这时候他们没有错误。
最后一件事,我们需要回到 EAGLView.m 文件中,进入initWithCoder函数,并且调用我们之前创建的”setupView”函数。接下来设置” animationInterval”的值,插入下列代码来调用setupView函数。
[self setupView];
需要注意下,我们当然可以将setupView函数代码直接写在initWithCoder函数中而不是创建一个新的函数,这样的方式通常仅仅适用于只调用一次的情况下。
好了,关掉EAGLView.m,看 EAGLView.h EAGLView.h 幸运的是,我们不需要在这里做很多的工作。
我们只需要创建两个函数的原型,代码如下:
- (void)setupView;
- (void)checkGLError:(BOOL)visibleCheck;
本教程结束