OpenGL开始之前的准备

60 阅读3分钟

开始之前

配置好glfw和glew/glad之后,仍需要一些初始环境,首先需要在main中实例化GLFW的窗口。

int main()
{
    glfwInit();		//初始化
    //配置GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);	
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    return 0;
}

这是初始化GLFW的内容,然后创建一个窗口对象

GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
    std::cout << "Failed to create GLFW window" << std::endl;
    glfwTerminate();
    return -1;
}
glfwMakeContextCurrent(window);

然后初始化GLAD/GLEW,之后就可以使用OpenGL的函数

//GLEW
if (glewInit() != GLEW_OK)
	{
		std::cout << "Error" << std::endl;
	}
//GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
    std::cout << "Failed to initialize GLAD" << std::endl;
    return -1;
}

视口

Viewport,定义渲染输出的区域,视口将窗口坐标映射到裁剪空间坐标,从而决定了渲染内容在窗口中的显示位置和大小,在开始渲染之前需要指定,可以将视口的维度设置的小于GLFW的维度,这样实际渲染的内容将在更小的窗口内,这样就可以将一些其他元素显示在OpenGL视口之外,默认则是整个GLFW。

glViewport(0, 0, 800, 600);

视口需要会随着窗口大小改变,所以可以对窗口注册一个回调函数来处理:

void framebuffer_size_callback(GLFWwindow* window, int width, int height);

在函数中定义

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	int viewportwidth = width - 100;
	glViewport(0, 0, viewportwidth, height);
}

接下来就可以注册这个回调函数

glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

当窗口被第一次显示的时候framebuffer_size_callback也会被调用

设置视口是有必要的,如果没有设置视口,那么拖动窗口的效果将是

设置视口之后:

效果很明显,视口定义了窗口坐标到裁剪空间坐标的映射关系。如果不设置视口,当窗口大小改变时,OpenGL仍然使用初始的视口设置,这会导致渲染内容无法正确适应新的窗口尺寸,从而出现内容缺失或变形的情况。

循环

之前的都只是设置窗口,设置显示,设置GLFW,接下来为渲染做准备工作。图形渲染需要一个RenderLoop

/* Loop until the user closes the window */
	while (!glfwWindowShouldClose(window))
	{
		/* Render here */
		glClear(GL_COLOR_BUFFER_BIT);//每个渲染迭代钱总是清屏
        
		/* Swap front and back buffers */
		glfwSwapBuffers(window);//交换颜色缓冲

		/* Poll for and process events */
		glfwPollEvents();//检查有没有触发事件/更新窗口状态/调用回调
	}

事后

渲染循环结束后我们需要正确释放/删除之前的分配的所有资源。我们可以在main函数的最后调用glfwTerminate函数来完成。

glfwTerminate();
return 0;

输入

希望能够在GLFW中实现一些输入控制,这可以通过使用GLFW的几个输入函数来完成。我们将会使用GLFW的glfwGetKey函数,它需要一个窗口以及一个按键作为输入。这个函数将会返回这个按键是否正在被按下。我们将创建一个processInput函数来让所有的输入代码保持整洁。

比如,想要在按下esc之后退出

void processInput(GLFWwindow* window)
{
	if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS)
	{
		glfwSetWindowShouldClose(window, true);		//设置关闭状态为true
	}
}

之后只需要在循环内调用该函数即可。

渲染

将所有的渲染操作放在渲染循环中

// 渲染循环
while(!glfwWindowShouldClose(window))
{
    glClear(GL_COLOR_BUFFER_BIT);
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    // 输入
    processInput(window);

    // 渲染指令
    ...

    // 检查并调用事件,交换缓冲
    glfwPollEvents();
    glfwSwapBuffers(window);
}

learnopengl-cn.github.io/01%20Gettin…