[LearnOpenGL]C1:OpenGL简介

在开始我们的图形学之旅之前,我们首先要了解OpenGL究竟是什么。OpenGL主要被人们看作一个API(Application Programming Interface 应用编程接口),为我们提供了大量的函数,我们可以利用这些函数接口来进行图形图像的操作。然而OpenGl本身并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范(Specification)。
OpenGL规范清楚地解释了每个函数的标准输出结果以及规范的执行过程。这取决于开发者如何利用这些规范,如何执行这些函数来获得特定的解决方案。正是由于OpenGL规范并没有给出具体的实现细节,因此真正开发的OpenGL版本有着多种不同的实现方式,只要功能和结果与规范相符即可。从用户的角度来说,他们不会感受到效果上的差异。
真正开发OpenGL库的人通常是那些显卡制造商。你所购买的显卡支持的OpenGL版本都是专门为这款显卡开发的。当我们使用苹果系统时,它的OpenGL库都是由苹果公司维护的。在Linux下,有显卡生产商提供的OpenGL库,也有一些爱好者改编的版本。这也意味着任何时候OpenGL库表现的行为与规范规定的不一致时,基本都是库的开发者留下的bug。
注:由于OpenGL的大多数实现都是由显卡厂商编写的,当产生一个bug时通常可以通过升级显卡驱动来解决。这些驱动会包括你的显卡能支持的最新版本的OpenGL,这也是为什么总是建议你偶尔更新一下显卡驱动。
在本次教程中,我们使用的版本时OpenGL3.3,感兴趣的读者可以找到这个版本的规范文档阅读。

核心模式与立即模式

在早些年间,使用OpenGL意味着在立即模式下开发,这通常指的是使用固定函数管线来绘制,这种模式对于绘制几何图形是简单直接的。但是,大部分的OpenGL功能在立即模式下被隐藏了,开发者并没有在OpenGL的计算中获得自由。因此,立即模式并非是高效的。从OpenGL3.2开始,规范开始鼓励开发者取探索OpenGL的核心机制,从这个版本起,OpenGL移除了所有的旧的特性。
当使用OpenGL的核心模式时,OpenGL迫使我们使用现代的函数。当我们试图使用一个已废弃的函数时,OpenGL会抛出一个错误并终止绘图。现代函数的优势是更高的灵活性和效率,然而也更难于学习。立即渲染模式从OpenGL实际运作中抽象掉了很多细节,因此它在易于学习的同时,也很难让人去把握OpenGL具体是如何运作的。现代函数要求使用者真正理解OpenGL和图形编程,它有一些难度,然而提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。
现今,更高版本的OpenGL已经发布(发布教程时最新版本为4.5),你可能会问:既然OpenGL 4.5 都出来了,为什么我们还要学习OpenGL 3.3?答案很简单,所有OpenGL的更高的版本都是在3.3的基础上,引入了额外的功能,并没有改动核心架构。新版本只是引入了一些更有效率或更有用的方式去完成同样的功能。因此,所有的概念和技术在现代OpenGL版本里都保持一致。当你的经验足够,你可以轻松使用来自更高版本OpenGL的新特性。当使用新版本的OpenGL特性时,只有新一代的显卡能够支持你的应用程序。这也是为什么大多数开发者基于较低版本的OpenGL编写程序,并只提供选项启用新版本的特性。在有些教程里你会看见更现代的特性,它们同样会以这种红色注释方式标明。

拓展

OpenGL非常好的一个特点是支持拓展(Extensions)。当一个图形公司开发出新的技术或者对绘制管线做了大量优化的时候,我们通常能在显卡驱动的拓展中找到这些改进。如果硬件支持这些拓展,开发者就能进行更高级更高效的图形开发。通过这种方式,一个图形开发者可以不用等待OpenGL更新版本,通过拓展使用这些新的技术。通常,当一个拓展非常流行或者非常有用的时候,就会纳入OpenGL新版本的一部分。
开发者可以查询是否某些拓展可用,如以下代码:

if(GL_ARB_extension_name)
{
    // Do cool new and modern stuff supported by hardware
}
else
{
    // Extension not supported: do it the old way
}

OpenGL3.3很少需要拓展,但必要的时候教程中会提供。

状态机

OpenGL自身是一个大的状态机,它集合了所有的定义当前OpenGL如何执行的变量。OpenGL当前的状态通常被认为是OpenGL context上下文。当使用OpenGL时,我们经常通过设置一些选项来改变OpenGL的状态,对当前的缓冲区进行操作,使用当前的上下文来进行绘制。
举例来说,如果我们告诉OpenGL现在想要画线而不是三角形,我们通过修改一些有关OpenGL绘制命令的上下文变量来改变当前的状态。一旦我们告诉OpenGL状态已经修改,在下一个命令中OpenGL就会开始画线。
我们将会接触到几个与状态改变相关的函数,这些函数改变了上下文和状态使用函数,这些函数基于当前的OpenGL状态执行了一些基本操作。无论如何,我们都要记住OpenGL本质上大状态机的性质,就能更容易理解其大部分性质。

对象

OpenGL库是用C语言编写的,允许其他语言的派生,但核心仍然是基于C语言库的。由于C的一些语言结构不易被翻译到其它的高级语言,因此OpenGL开发的时候引入了一些抽象层。“对象(Object)”就是其中一个。
在OpenGL中一个对象是指一些选项的集合,它代表OpenGL状态的一个子集。比如,我们可以用一个对象来代表绘图窗口的设置,之后我们就可以设置它的大小、支持的颜色位数等等。可以把对象看做一个C风格的结构体(Struct):

struct object_name {
    float  option1;
    int    option2;
    char[] name;
};

当我们使用一个对象时,通常看起来像如下一样(把OpenGL上下文看作一个大的结构体):

// The State of OpenGL
struct OpenGL_Context {
    ...
    object* object_Window_Target;
    ...     
}
// create object
unsigned int objectId = 0;
glGenObject(1, &objectId);
// bind object to context
glBindObject(GL_WINDOW_TARGET, objectId);
// set options of object currently bound to GL_WINDOW_TARGET
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
// set context target back to default
glBindObject(GL_WINDOW_TARGET, 0);

以上一段代码展示了OpenGL常见的工作流。收钱创建一个对象,使用一个id保存它的引用(实际数据被存储在后台)。然后我们将对象绑定到上下文的目标位置,例如窗口对象的位置被定义成GL_WINDOW_TARGET。接下来设置窗口属性。最后将目标位置的对象id设为0,解绑这个对象。设置的选项属性将会被保存在ObjectId所引用的对象中,一旦我们重新绑定这个对象到GL_WINDOW_TARGET位置,这些选项就会重新生效。

参考资料

1.opengl.org: OpenGL的官方网站。
2.OpenGL registry: 包含了所有OpenGL版本的规范和支持的拓展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值