你好,窗口
本文整理自LearnOpenGL 及LearnOpenGL CN ,后者为前者的中文版, 完整学习的话建议前往原网站。
检测GLFW能否正常运行
// GLEW
#define GLEW_STATIC
#include <GL/glew.h> //要放在其他OpenGL头文件的前面
// GLFW
#include <GLFW/glfw3.h>
int main()
{
glfwInit(); //初始化窗口
设置要使用的OpenGL版本为3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //次版本号
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //核心模式
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); //不允许调整窗口大小
return 0;
}
GLEW
GLEW是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLEW。
glewExperimental = GL_TRUE; //让GLEW使用现代化的技术
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
视口(Viewport)
就是窗口中用来显示图形的一块矩形区域,它可以和窗口等大,也可以比窗口大或者小。只有绘制在视口区域中的图形才能被显示,如果图形有一部分超出了视口区域,那么那一部分是看不到的。
告诉OpenGL渲染窗口的尺寸大小,这样OpenGL才只能知道怎样相对于窗口大小显示数据和坐标。我们可以通过调用glViewport函数来设置窗口的维度(Dimension)。
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素),这里我们是直接从GLFW中获取的。我们从GLFW中获取视口的维度而不设置为800*600是为了让它在高DPI的屏幕上(比如说Apple的视网膜显示屏)也能正常工作。
OpenGL幕后使用glViewport中定义的位置和宽高进行2D坐标的转换,将OpenGL中的位置坐标转换为你的屏幕坐标。例如,OpenGL中的坐标(-0.5, 0.5)有可能(最终)被映射为屏幕中的坐标(200,450)。注意,处理过的OpenGL坐标范围只为-1到1,因此我们事实上将(-1到1)范围内的坐标映射到(0, 800)和(0, 600)。
准备好你的引擎
我们希望程序在我们明确地关闭它之前不断绘制图像并能够接受用户输入。因此,我们需要在程序中添加一个while循环,我们可以把它称之为游戏循环(Game Loop),它能在我们让GLFW退出前一直保持运行。
while(!glfwWindowShouldClose(window)) //检查是否被要求退出
{
glfwPollEvents(); //检查是否触发事件,然后调用对应的回调函数
//glfwSwapBuffers函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
glfwSwapBuffers(window);
}
双缓冲(Double Buffer)
应用程序使用单缓冲绘图时可能会存在图像闪烁的问题。 这是因为生成的图像不是一下子被绘制出来的,而是按照从左到右,由上而下逐像素地绘制而成的。最终图像不是在瞬间显示给用户,而是通过一步一步生成的,这会导致渲染的结果很不真实。为了规避这些问题,我们应用双缓冲渲染窗口应用程序。前缓冲保存着最终输出的图像,它会在屏幕上显示;而所有的的渲染指令都会在后缓冲上绘制。当所有的渲染指令执行完毕后,我们交换(Swap)前缓冲和后缓冲,这样图像就立即呈显出来,之前提到的不真实感就消除了。
最后
释放/删除之前的分配的所有资源(GLFW分配的)。
glfwTerminate();
return 0;
输入
GLFW可以实现函数回调,回调函数事实上是一个函数指针。
函数原型
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
按键回调函数接受一个GLFWwindow指针作为它的第一个参数;第二个整形参数用来表示按下的按键;action参数表示这个按键是被按下还是释放;最后一个整形参数表示是否有Ctrl、Shift、Alt、Super等按钮的操作。GLFW会在合适的时候调用它,并为各个参数传入适当的值。
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
// 当用户按下ESC键,我们设置window窗口的WindowShouldClose属性为true
// 关闭应用程序
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
渲染
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //使用自定义的颜色来清空屏幕
glClear(GL_COLOR_BUFFER_BIT);
当调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色。
glClearColor函数是一个状态设置函数,而glClear函数则是一个状态应用的函数。