What You’ll Learn in This Chapter(你将会学到啥)
- How to create and compile shader code(如何创建和编译shader代码)
- How to draw with OpenGL(如何使用OpenGL画画)
- How to use the book’s application framework to initialize your programs and clean up after yourself(如何使用本书的程序框架)
In this chapter, we introduce the simple application framework that is used for almost all of the samples in this book(在本小节,我们将介绍一个简单的应用程序框架). This shows you how to create the main window with the book’s application framework and how to render simple graphics into it(这里介绍如何创建一个主窗口和渲染简单的图像到那上面去). You’ll also see what a very simple GLSL shader looks like(你也将看到简单的shader长的什么样子的,如何编译他们,以及如何使用他们渲染简单的点), how to compile it, and how to use it to render simple points. The chapter concludes with your very first OpenGL triangle(本章节最后将绘制一个最简单的OpenGL的三角形)
Creating a Simple Application(创建一个简单的程序)
To introduce the application framework that’ll be used in the remainder of this book(为了介绍我们要使用的框架,我们将以一个极端简单的例子为开始), we’ll start with an extremely simple example application. Of course, to write a largescale OpenGL program you don’t have to use our framework(当然,你在写一个很牛逼的OpenGL程序的时候,你不用使用我们的框架)—in fact, we wouldn’t recommend it, as it’s quite simple(实际上,我们也不推荐你们使用我们的框架,因为它太简单了). However, it does simplify things a little and allows you to get to writing OpenGL code sooner(不过,它还是让整个创建OpenGL环境的过程得到简化,并让你能更快速的接触到OpenGL的代码)
The application framework is brought into your application by including sb7.h in your source code(你只需要包含sb7.h就可以把整个框架引入到你的代码中). This is a C++ header file that defines a namespace called sb7 that includes the declaration of an application class, sb7::application, from which we can derive our examples(这个头文件中有一个叫做sb7的命名空间,里面包含了我们的应用程序类的申明,sb7::application可以驱动我们样本代码). The framework also includes a number of utility functions and a simple math library called vmath to help you with some of the number crunching involved in OpenGL (这个框架也包含了一些工具函数和简单的数学库,因为OpenGL的操作会调用这些东西啦)
To create an application, we simply include sb7.h, derive a class from sb7::application(我们只需要包含sb7.h并且从sb7::application派生出一个类就可以创建一个程序了), and, in exactly one of our source files, include an instance of the DECLARE_MAIN macro(然后随便挑一个源代码文件,然后包含一个DECLARE_MAIN的宏的实例就好了). This defines the main entry point of our application(这玩意定义了应用程序的入口), which creates an instance of our class (the type of which is passed as a parameter to the macro) and calls its run() method(这个入口创建了我们的类的实例并调用了run方法), which implements the application’s main loop(在这份run方法中,有我们应用程序主循环的实现). In turn, this performs some initialization by first calling the startup() method(并且这个家伙调用了某种初始化的方法,并第一时间调用startup方法) and then calling the render() method in a loop(然后在主循环中调用render这个函数). In the default implementation, both methods are defined as virtual functions with empty bodies(在缺省的实现中,这俩方法都是一个虚函数,并且函数体什么都不干). We override the render() method in our derived class and write our drawing code inside it(在我们的程序中,我们重写render函数,然后写上咱的绘图代码). The application framework takes care of creating a window, handling input(应用程序框架会处理创建窗口以及输入事件), and displaying the rendered results to the user(并且将渲染结果显示给用户看). The complete source code for our first example is given in Listing 2.1 and its output is shown in Figure 2.1(第一个例子的完整代码如listing2.1所示,并且运行程序的结果截图如图2.1所示)
// Include the "sb7.h" header file #include "sb7.h" // Derive my_application from sb7::application class my_application : public sb7::application { public: // Our rendering function void render(double currentTime) { // Simply clear the window with red static const GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f }; glClearBufferfv(GL_COLOR, 0, red); } }; // Our one and only instance of DECLARE_MAIN DECLARE_MAIN(my_application);
Listing 2.1: Our first OpenGL application
The example shown in Listing 2.1 simply clears the whole screen to red(这个例子就如同Listing2.1所示,简单的使用红色擦除整个屏幕). This introduces our first OpenGL function(这就使用鸟咱们第一个OpenGL的API:glClearBufferffer), glClearBufferfv(). The prototype of glClearBufferfv() is(该函数的定义如下)
void glClearBufferfv(GLenum buffer, GLint drawBuffer, const GLfloat * value);
All OpenGL functions start with gl and follow a number of naming conventions(所有的OpenGL的API都是以gl开头,后面跟个什么玩意的组合方式), such as encoding some of their parameter types as suffixes on the end of the function names(函数名字的末尾跟着的东西有可能代表着该函数里应该传入啥类型的参数之类的信息). This allows a limited form of overloading even in languages that don’t directly support this ability(这种命名可以让函数具备类似于重载的效果,即便那个编程语言本身不支持重载). In this case, the suffix fv means that the function consumes a vector (v) of floating-point (f) values(这种情况下,以fv结尾的函数意味着函数接收的参数是浮点类型的向量), where arrays (generally referenced by pointers in languages like C) and vectors are used interchangeably by OpenGL(在OpenGL数组和向量是一样的). The glClearBufferfv() function tells OpenGL to clear the buffer specified by the first parameter (in this case GL_COLOR) to the value specified in its third parameter. (glClearBufferfv告诉OpenGL去使用第三个参数指定的那些值去擦除第一个参数指定的类型的缓冲区。) The second parameter, drawBuffer, is used when there are multiple output buffers that could be cleared(第二个参数只有在多目标渲染的时候才用得上,用于指定擦除第几个输出缓冲区). Because we’re using only one here and drawBuffer is a zerobased index, we’ll just set it to 0 in this example(由于咱这里只有一个输出的颜色缓冲区,咱这里写0就好了). Here, that color is stored in the array red, which contains four floating-point values—one each for red, green, blue, and alpha, in that order(在这里,颜色存放在一个数组里,分别是r、g、b、a)
The red, green, and blue terms should be self-explanatory(这里r、g、b是无需多介绍的). Alpha is a fourth component that is associated with a color and is often used to encode the opacity of a fragment(a分量指的是alpha,控制像素的透明度). When used this way, setting alpha to 0 will make the fragment completely transparent(当设置a为0时,像素为完全透明的状态), and setting it to 1 will make it completely opaque(当a设置成为1的时候,将变得完全不透明). The alpha value can also be stored in the output image and used in some parts of OpenGL’s calculations(alpha值也可以存储在输出的图像中,并在其他的地方被用来计算,即便你无法看见这个像素), even though you can’t see it. You can see that we set both the red and alpha values to 1 and the others to 0(你可以看到,现在我们把r和a设置成了1,把g、b设置成了0). This specifies an opaque red color(这个设置下,就是一个红色). The result of running this application is shown in Figure 2.1.(此时程序的运行结果如图2.1所示) This initial application isn’t particularly interesting(应用程序的初始化并不是怎么有趣),1 as all it does is fill the window with a solid red color. You will notice that our render() function takes a single parameter—currentTime(你也注意到了render函数只有一个参数currentTime). This contains the number of seconds since the application was started(这个参数指代的是从应用程序启动开始,经历了多少时间), and we can use it to create a simple animation(有了这个参数,我们就可以制作一些简单的动画). In this case, we can use it to change the color that we use to clear the window(我们可以基于这个时间对颜色进行修改,并使用修改后的颜色去擦除窗口). Our modified render() function2 is shown in Listing 2.2(我们修改后的render函数如Listing2.2所示)
- This sample is especially uninteresting if you are reading this book in black and white!(如果你读的书本是非彩色版本的话,这个例子是没什么卵味的)
- If you’re copying this code into your own example, you’ll need to include to get the declarations of sin() and cos()(如果你把咱书本里的代码拷贝到你的程序里,你还需要包含math.h这个头文件,因为我们程序中使用了三角函数)
// Our rendering function void render(double currentTime) { const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f, (float)cos(currentTime) * 0.5f + 0.5f, 0.0f, 1.0f }; glClearBufferfv(GL_COLOR, 0, color); }
Listing 2.2: Animating color over time
Now our window fades from red through yellow, orange, green, and back to red again. Still not that exciting, but at least it does something.(现在我们的窗口的颜色在变化了,虽然还不是怎么牛叉,但是至少,这个程序还是干了点什么了吧)
本日的翻译就到这里,明天见,拜拜~~
第一时间获取最新桥段,请关注东汉书院以及图形之心公众号
东汉书院,等你来玩哦