mirror of
https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git
synced 2025-08-23 04:35:28 +08:00
Time to revive this project
This commit is contained in:
@@ -7,11 +7,11 @@
|
|||||||
校对 | Geequlim
|
校对 | Geequlim
|
||||||
|
|
||||||
|
|
||||||
在开始这段旅程之前我们先了解一下OpenGL到底是什么。一般它被认为是一个**应用程序编程接口**(Application Programming Interface, API),它包含了一系列可以操作图形、图像的方法。然而,OpenGL本身并不是一个API,仅仅是一个规范,由[Khronos组织](http://www.khronos.org/)制定并维护。
|
在开始这段旅程之前我们先了解一下OpenGL到底是什么。一般它被认为是一个**API**(Application Programming Interface, 应用程序编程接口),包含了一系列可以操作图形、图像的方法。然而,OpenGL本身并不是一个API,它仅仅是一个由[Khronos组织](http://www.khronos.org/)制定并维护的规范(Specification)。
|
||||||
|
|
||||||
OpenGL严格规定了每个函数该如何执行,以及它们该如何返回。至于内部具体每个函数是如何实现的,将由OpenGL库的开发者自行决定(注:这里开发者是指编写OpenGL库的人)。因为OpenGL规范并没有规定实现的细节,具体的OpenGL库允许使用不同的实现,只要其功能和结果与规范相匹配(亦即,作为用户不会感受到功能上的差异)。
|
OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现(Implement)的,将由OpenGL库的开发者自行决定(注:这里开发者是指编写OpenGL库的人)。因为OpenGL规范并没有规定实现的细节,具体的OpenGL库允许使用不同的实现,只要其功能和结果与规范相匹配(亦即,作为用户不会感受到功能上的差异)。
|
||||||
|
|
||||||
实际的OpenGL库的开发者通常是显卡的生产商。每个你购买的显卡都会支持特定版本的OpenGL,通常是为一个系列的显卡专门开发的。当你使用苹果系统的时候,OpenGL库是由苹果自身维护的。在Linux下,有显卡生产商提供的OpenGL库,也有一些爱好者改编的版本。这也意味着任何时候OpenGL库表现的行为与规范规定的不一致时,基本都是库的开发者留下的bug。(快甩锅)
|
实际的OpenGL库的开发者通常是显卡的生产商。你购买的显卡所支持的OpenGL版本都为这个系列的显卡专门开发的。当你使用Apple系统的时候,OpenGL库是由Apple自身维护的。在Linux下,有显卡生产商提供的OpenGL库,也有一些爱好者改编的版本。这也意味着任何时候OpenGL库表现的行为与规范规定的不一致时,基本都是库的开发者留下的bug。
|
||||||
|
|
||||||
|
|
||||||
!!! Important
|
!!! Important
|
||||||
@@ -19,28 +19,27 @@ OpenGL严格规定了每个函数该如何执行,以及它们该如何返回
|
|||||||
由于OpenGL的大多数实现都是由显卡厂商编写的,当产生一个bug时通常可以通过升级显卡驱动来解决。这些驱动会包括你的显卡能支持的最新版本的OpenGL,这也是为什么总是建议你偶尔更新一下显卡驱动。
|
由于OpenGL的大多数实现都是由显卡厂商编写的,当产生一个bug时通常可以通过升级显卡驱动来解决。这些驱动会包括你的显卡能支持的最新版本的OpenGL,这也是为什么总是建议你偶尔更新一下显卡驱动。
|
||||||
|
|
||||||
|
|
||||||
所有版本的OpenGL规范书都被寄存在Khronos那里,并且都是公开的。有兴趣的读者可以找到OpenGL3.3(我们将要使用的版本)的[规范书](https://www.opengl.org/registry/doc/glspec33.core.20100311.withchanges.pdf)。如果你想深入到OpenGL的细节(只关心函数的功能描述而不是函数的实现),这是个很好的选择。该规范还提供一个强大的可以寻找到每个函数具体功能的参考。
|
所有版本的OpenGL规范文档都被公开的寄存在Khronos那里。有兴趣的读者可以找到OpenGL3.3(我们将要使用的版本)的[规范文档](https://www.opengl.org/registry/doc/glspec33.core.20100311.withchanges.pdf)。如果你想深入到OpenGL的细节(只关心函数功能的描述而不是函数的实现),这是个很好的选择。如果你想知道每个函数**具体的**运作方式,这个规范也是一个很棒的参考。
|
||||||
|
|
||||||
## 核心模式(Core-profile)与立即渲染模式(Immediate mode)
|
## 核心模式(Core-profile)与立即渲染模式(Immediate mode)
|
||||||
|
|
||||||
早期的OpenGL使用**立即渲染模式**(也就是**固定渲染管线**),这个模式下绘制图形很方便。OpenGL的大多数功能都被库隐藏起来,开发者很少能控制OpenGL如何进行计算。而开发者希望更多的灵活性。随着时间推移,规范越来越灵活,开发者也能更多的控制绘图细节。立即渲染模式确实容易使用和理解,但是效率太低。因此从OpenGL3.2开始,规范书开始废弃立即渲染模式,推出核心模式,这个模式完全移除了旧的特性。
|
早期的OpenGL使用**立即渲染模式**(也就是**固定渲染管线**),这个模式下绘制图形很方便。OpenGL的大多数功能都被库隐藏起来,开发者很少能控制OpenGL如何进行计算的自由。而开发者迫切希望能有更多的灵活性。随着时间推移,规范越来越灵活,开发者对绘图细节有了更多的掌控。立即渲染模式确实容易使用和理解,但是效率太低。因此从OpenGL3.2开始,规范书开始废弃立即渲染模式,推出核心模式,这个模式完全移除了旧的特性。
|
||||||
|
|
||||||
当使用核心模式时,OpenGL迫使我们使用现代的做法。当我们试图使用一个废弃的函数时,OpenGL会抛出一个错误并终止绘图。现代做法的优势是更高的灵活性和效率,然而也更难于学习。立即渲染模式从OpenGL实际操作中抽象掉了很多细节,因而它易于学习的同时,也很难去把握OpenGL具体是如何操作的。现代做法要求使用者真正理解OpenGL和图形编程,它有一些难度,然而提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。
|
当使用OpenGl的核心模式时,OpenGL迫使我们使用现代的函数。当我们试图使用一个已废弃的函数时,OpenGL会抛出一个错误并终止绘图。现代函数的优势是更高的灵活性和效率,然而也更难于学习。立即渲染模式从OpenGL**实际**运作中抽象掉了很多细节,因而它易于学习的同时,也很难去把握OpenGL具体是如何运作的。现代函数要求使用者真正理解OpenGL和图形编程,它有一些难度,然而提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。
|
||||||
|
|
||||||
这也是为什么我们的教程面向OpenGL3.3的核心模式。虽然上手更困难,但是值得去努力。
|
这也是为什么我们的教程面向OpenGL3.3的核心模式。虽然上手更困难,但是值得去努力。
|
||||||
|
|
||||||
现今更高版本的OpenGL已经发布(目前最新是4.5),你可能会问:为什么我们还要学习3.3?答案很简单,所有OpenGL的更高的版本都是在3.3的基础上,添加了额外的功能,并不更改进核心架构。新版本只是引入了一些更有效率或更有用的方式去完成同样的功能。因此所有的概念和技术在现代OpenGL版本里都保持一致。当你的经验足够,你可以轻松使用来自更高版本OpenGL的新特性。
|
现今,更高版本的OpenGL已经发布(写作时最新版本为4.5),你可能会问:既然OpenGL 4.5 都出来了,为什么我们还要学习OpenGL 3.3?答案很简单,所有OpenGL的更高的版本都是在3.3的基础上,引入了额外的功能,并没有改动核心架构。新版本只是引入了一些更有效率或更有用的方式去完成同样的功能。因此,所有的概念和技术在现代OpenGL版本里都保持一致。当你的经验足够,你可以轻松使用来自更高版本OpenGL的新特性。
|
||||||
|
|
||||||
|
|
||||||
!!! Attention
|
!!! Attention
|
||||||
|
|
||||||
当使用新版本的OpenGL特性时,只有新一代的显卡能够支持你的应用程序。这也是为什么大多数开发者基于较低版本的OpenGL编写程序,并有选择的启用新特性。
|
当使用新版本的OpenGL特性时,只有新一代的显卡能够支持你的应用程序。这也是为什么大多数开发者基于较低版本的OpenGL编写程序,并只提供选项启用新版本的特性。
|
||||||
|
|
||||||
在有些教程里你会发现像如下方式注明的新特性。
|
在有些教程里你会看见更现代的特性,它们会以这种红色注释方式标明。
|
||||||
|
|
||||||
## 扩展(Extension)
|
## 扩展(Extension)
|
||||||
|
|
||||||
OpenGL的一大特性就是对扩展的支持,当一个显卡公司提出一个新特性或者渲染上的大优化,通常会以扩展的方式在驱动中实现。如果一个程序在支持这个扩展的显卡上运行,开发者可以使用这个扩展提供的一些更先进更有效的图形功能。通过这种方式,开发者不必等待一个新的OpenGL规范面世,就可以方便的检查显卡是否支持此扩展。通常,当一个扩展非常流行或有用的时候,它将最终成为未来的OpenGL规范的一部分。
|
OpenGL的一大特性就是对扩展的支持,当一个显卡公司提出一个新特性或者渲染上的大优化,通常会以**扩展**的方式在驱动中实现。如果一个程序在支持这个扩展的显卡上运行,开发者可以使用这个扩展提供的一些更先进更有效的图形功能。通过这种方式,开发者不必等待一个新的OpenGL规范面世,就可以使用这些新的渲染特性了,只需要简单地检查一下显卡是否支持此扩展。通常,当一个扩展非常流行或者非常有用的时候,它将最终成为未来的OpenGL规范的一部分。
|
||||||
|
|
||||||
使用扩展的代码大多看上去如下:
|
使用扩展的代码大多看上去如下:
|
||||||
|
|
||||||
@@ -55,21 +54,21 @@ else
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
使用OpenGL3.3时,我们很少需要使用扩展来完成大多数功能,但是掌握这种方式是必须的。
|
使用OpenGL3.3时,我们很少需要使用扩展来完成大多数功能,当需要的时候,本教程将提供适当的指示。
|
||||||
|
|
||||||
## 状态机(State Machine)
|
## 状态机(State Machine)
|
||||||
|
|
||||||
OpenGL自身是一个巨大的状态机:一个描述OpenGL该如何操作的所有变量的大集合。OpenGL的状态通常被称为OpenGL**上下文(Context)**。我们通常使用如下途径去更改OpenGL状态:设置一些选项,操作一些缓冲。最后,我们使用当前OpenGL上下文来渲染。
|
OpenGL自身是一个巨大的状态机:一系列的变量描述OpenGL此刻应当如何运行。OpenGL的状态通常被称为OpenGL**上下文(Context)**。我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲。最后,我们使用当前OpenGL上下文来渲染。
|
||||||
|
|
||||||
假设当我们想告诉OpenGL去画线而不是三角形的时候,我们通过改变一些上下文变量来改变OpenGL状态,从而告诉OpenGL如何去绘图。一旦我们改变了OpenGL的状态为绘制线段,下一个绘制命令就会画出线段而不是三角形。
|
假设当我们想告诉OpenGL去画线段而不是三角形的时候,我们通过改变一些上下文变量来改变OpenGL状态,从而告诉OpenGL如何去绘图。一旦我们改变了OpenGL的状态为绘制线段,下一个绘制命令就会画出线段而不是三角形。
|
||||||
|
|
||||||
用OpenGL工作时,我们会遇到一些**状态设置函数**(State-changing Function),以及一些在这些状态的基础上**状态应用的函数**(State-using Function)。只要你记住OpenGL本质上是个大状态机,就能更容易理解它的大部分特性。
|
当使用OpenGL的时候,我们会遇到一些**状态设置**函数(State-changing Function),这类函数将会改变上下文。以及**状态应用**函数(State-using Function),这类函数会根据当前OpenGL的状态执行一些操作。只要你记住OpenGL本质上是个大状态机,就能更容易理解它的大部分特性。
|
||||||
|
|
||||||
## 对象(Object)
|
## 对象(Object)
|
||||||
|
|
||||||
OpenGL库是用C语言写的,同时也支持多种语言的派生,但是核心是一个C库。一些C语言的结构不易被翻译到其他高层语言,因此OpenGL设计的时候引入了一些抽象概念。“对象”就是其中一个。
|
OpenGL库是用C语言写的,同时也支持多种语言的派生,但其内核仍是一个C库。由于C的一些语言结构不易被翻译到其它的高级语言,因此OpenGL开发的时候引入了一些抽象层。“对象”就是其中一个。
|
||||||
|
|
||||||
在OpenGL中一个对象是指一些选项的集合,代表OpenGL状态的一个子集。比如,我们可以用一个对象来代表绘图窗口的设置,可以设置它的大小、支持的颜色位数等等。可以把对象看做一个C风格的结构体:
|
在OpenGL中一个**对象**是指一些选项的集合,它代表OpenGL状态的一个子集。比如,我们可以用一个对象来代表绘图窗口的设置,之后我们就可以设置它的大小、支持的颜色位数等等。可以把对象看做一个C风格的结构体(Struct):
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
struct object_name {
|
struct object_name {
|
||||||
@@ -81,10 +80,10 @@ struct object_name {
|
|||||||
|
|
||||||
!!! Important
|
!!! Important
|
||||||
|
|
||||||
**原始类型(Primitive Type)**
|
**基本数据类型(Primitive Type)**
|
||||||
使用OpenGL时,建议使用OpenGL定义的原始类型。比如使用`float`时我们加上前缀GL(因此写作`GLfloat`)。`int`,`uint`,`char`,`bool`等等类似。OpenGL定义的这些GL原始类型是平台无关的内存排列方式。而int等原始类型在不同平台上可能有不同的内存排列方式。使用GL原始类型可以保证你的程序在不同的平台上工作一致。
|
使用OpenGL时,建议使用OpenGL定义的基本数据类型。比如使用`float`时我们加上前缀`GL`(因此写作`GLfloat`)。`int`、`uint`、`char`、`bool`等等也类似。OpenGL定义的这些GL基本数据类型的内存布局是与平台无关的,而int等基本数据类型在不同操作系统上可能有不同的内存布局。使用GL基本数据类型可以保证你的程序在不同的平台上工作一致。
|
||||||
|
|
||||||
当我们使用一个对象时,通常看起来像如下一样(把OpenGL上下文比作一个大的结构体):
|
当我们使用一个对象时,通常看起来像如下一样(把OpenGL上下文看作一个大的结构体):
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
// OpenGL的状态
|
// OpenGL的状态
|
||||||
@@ -102,27 +101,27 @@ GLuint objectId = 0;
|
|||||||
glGenObject(1, &objectId);
|
glGenObject(1, &objectId);
|
||||||
// 绑定对象至上下文
|
// 绑定对象至上下文
|
||||||
glBindObject(GL_WINDOW_TARGET, objectId);
|
glBindObject(GL_WINDOW_TARGET, objectId);
|
||||||
// 设置GL_WINDOW_TARGET对象的一些选项
|
// 设置绑定到GL_WINDOW_TARGET的对象的一些选项
|
||||||
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
|
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
|
||||||
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
|
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
|
||||||
// 将上下文的GL_WINDOW_TARGET对象设回默认
|
// 将上下文对象设回默认
|
||||||
glBindObject(GL_WINDOW_TARGET, 0);
|
glBindObject(GL_WINDOW_TARGET, 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
这一小片代码将会是以后使用OpenGL时常见的工作流。我们首先创建一个对象,然后用一个id保存它的引用(实际数据被储存在后台)。然后我们将对象绑定至上下文的目标位置(例子里窗口对象的目标位置被定义成`GL_WINDOW_TARGET`)。接下来我们设置窗口的选项。最后我们通过将目标位置的对象id设回0的方式解绑这个对象。设置的选项被保存在`objectId`代表的对象中,一旦我们重新绑定这个对象到`GL_WINDOW_TARGET`位置,这些选项就会重新生效。
|
这一小段代码展现了你以后使用OpenGL时常见的工作流。我们首先创建一个对象,然后用一个id保存它的引用(实际数据被储存在后台)。然后我们将对象绑定至上下文的目标位置(例子里窗口对象目标的位置被定义成`GL_WINDOW_TARGET`)。接下来我们设置窗口的选项。最后我们将目标位置的对象id设回0,解绑这个对象。设置的选项将被保存在`objectId`所引用的对象中,一旦我们重新绑定这个对象到`GL_WINDOW_TARGET`位置,这些选项就会重新生效。
|
||||||
|
|
||||||
|
|
||||||
!!! Attention
|
!!! Attention
|
||||||
|
|
||||||
目前提供的示例代码只是OpenGL如何操作的一个大致描述,通过阅读以后的教程你会遇到很多实际的例子。
|
目前提供的示例代码只是OpenGL如何操作的一个大致描述,通过阅读以后的教程你会遇到很多实际的例子。
|
||||||
|
|
||||||
使用对象的一个好处是我们在程序中不止可以定义一个对象并且设置他们的状态,在我们需要进行一个操作的时候,只需要绑定预设了需要设置的对象即可。比如,有一个作为3D模型的数据(一栋房子或一个人物,由多个子模型构成)容器对象,在我们想绘制其中任何一个3D模型的时候,只需绑定相应的子模型数据的对象(我们预先创建并设置好了它们的选项)就可以了。拥有数个这样的对象允许我们指定多个模型,在想画其中任何一个的时候,简单的将相应的对象绑定上去,便不需要再进行重复的设置选项的操作了。
|
使用对象的一个好处是在程序中,我们不止可以定义一个对象,设置它们的状态。在我们执行一个使用OpenGL状态的操作的时候,只需要绑定对象到需要的设置上即可。比如,有一些作为3D模型数据(一栋房子或一个人物)的容器对象,在我们想绘制其中任何一个对象的时候,只需绑定一个对象包含相应的模型数据就可以了(先创建并设置对象的选项)。拥有数个这样的对象允许我们指定多个模型,在想画其中任何一个的时候,直接将对应的对象绑定上去,便不需要再重复设置选项了。
|
||||||
|
|
||||||
## 让我们开始吧
|
## 让我们开始吧
|
||||||
|
|
||||||
你现在已经知道一些OpenGL的相关知识了,包括OpenGL作为规范和库,OpenGL大致的操作流程,以及一些使用扩展的小技巧。不要担心你还没有完全消化它们,通过后面的教程我们会仔细地讲解每一步,你会通过足够的例子来把握OpenGL。如果你已经做好了开始下一步的准备,我们可以开始建立OpenGL上下文以及我们的第一个窗口了。[点击这里](http://learnopengl-cn.readthedocs.org/zh/latest/01%20Getting%20started/02%20Creating%20a%20window/)(第一章第二节)
|
你现在已经知道一些OpenGL的相关知识了,OpenGL规范和库,OpenGL幕后大致的运作流程,以及OpenGL使用的一些小技巧。不要担心你还没有完全消化它们,后面的教程我们会仔细地讲解每一个步骤,你会通过足够的例子来真正掌握OpenGL。如果你已经做好了开始下一步的准备,我们可以在[这里](02 Creating a window.md)开始建立OpenGL上下文以及我们的第一个窗口了。
|
||||||
|
|
||||||
## 额外的资源
|
## 附加资源
|
||||||
|
|
||||||
- [opengl.org](https://www.opengl.org/): OpenGL官方网站。
|
- [opengl.org](https://www.opengl.org/):OpenGL官方网站。
|
||||||
- [OpenGL registry](https://www.opengl.org/registry/): OpenGL各版本的规范和扩展的主站。
|
- [OpenGL registry](https://www.opengl.org/registry/):包含OpenGL各版本的规范和扩展。
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
# 校对指南(Styleguide)
|
# 校对指南(Styleguide)
|
||||||
|
|
||||||
- **对照原文**
|
- **对照原文**
|
||||||
- 使用中文的标点符号: 逗号,双引号
|
- 使用中文的标点符号: 逗号、句号、双引号
|
||||||
- 使用英文的标点符号: 括号(去讨论下剩下的,像句号之类的)
|
- 使用英文的标点符号: 括号
|
||||||
- 文本中常量/代码用``加注为代码
|
- 文本中常量/代码用``加注为代码
|
||||||
- 代码块不使用Tab标注,改为用```式标注
|
- 代码块不使用Tab标注,改为用```式标注
|
||||||
- 每一节标题使用`#` (h1)标题(到后面会有几节有很多小节的,太小的标题不明显)
|
- 每一节标题使用`#` (h1)标题(到后面会有几节有很多小节的,太小的标题不明显)
|
||||||
@@ -24,15 +24,15 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
- 翻译注释
|
- 翻译注释
|
||||||
- 原文中的斜体一律用加粗表示(中文并不存在斜体)
|
- 原文中的斜体一律用加粗表示(中文并不存在斜体),粗体也用粗体表示,注意不要自己添加粗体
|
||||||
- 每一节前面加上
|
- 每一节前面加上
|
||||||
|
|
||||||
```
|
```
|
||||||
原文 | [英文标题](原文地址)
|
原文 | [英文标题](原文地址)
|
||||||
---|---
|
---|---
|
||||||
作者 | 作者
|
作者 | [作者]
|
||||||
翻译 | 翻译
|
翻译 | [翻译]
|
||||||
校对 | 校对
|
校对 | [校对]
|
||||||
```
|
```
|
||||||
|
|
||||||
- 公式用[http://latex2png.com/](http://latex2png.com/)转换,文本中的公式Resolution为150,单独的公式为200
|
- 公式用[http://latex2png.com/](http://latex2png.com/)转换,文本中的公式Resolution为150,单独的公式为200
|
||||||
@@ -52,6 +52,7 @@ xxxx(([译注x])
|
|||||||
```
|
```
|
||||||
效果会像这样([译注1])
|
效果会像这样([译注1])
|
||||||
|
|
||||||
|
- “Additional resources”译作“附加资源”,“Exercises”译作“练习”,“Solution”译作“参考解答”
|
||||||
|
|
||||||
**如果有不全的继续加**
|
**如果有不全的继续加**
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user