学习OpenGL建议从32位学起,因为64位有些细节可能需要特殊处理,因此初学者可以暂不考虑这些特殊情况,从简单开始入手,减少不必要的麻烦。

1.渲染模式:立即渲染模式和核心模式

立即渲染模式(Immediate mode,也就是固定渲染管线),这个模式下绘制图形很方便。立即渲染模式确实容易使用和理解,但是效率太低,现在已经废弃。 核心模式迫使我们使用现代的函数,现代函数的优势是更高的灵活性和效率,然而也更难于学习。

2.状态机

OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行。OpenGL的状态通常被称为OpenGL上下文(Context)。我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲。最后,我们使用当前OpenGL上下文来渲染。

3.对象

OpenGL开发的时候引入了一些抽象层。“对象(Object)”就是其中一个。在OpenGL中一个对象是指一些选项的集合,它代表OpenGL状态的一个子集。在我们想绘制其中任何一个模型的时候,只需绑定一个包含对应模型数据的对象就可以了(当然,我们需要先创建并设置对象的选项)。

4.使用vs2015搭建opengl+glfw3+glad环境

4.1 opengl

opengl库在vs2015的SDK中自带,不需要安装

4.2 glfw3

glfw3的项目地址:https://www.glfw.org/download.html 该网址有现成的库文件,作为初学者,我建议自己编译。 怎么编译?答:使用CMake(不会的找几篇文章看看就会了,用不了10分钟肯定能学会) (1)下载源码,并解压 (2)打开cmd,进入源码目录,执行:cmake . (3)上一步执行成功后,会生成visual studio工程(具体是vs2015还是2017,cmake根据你的开发环境帮你自动配置),进入源码目录,打开FLFW.sln,如果学习的话,编译32位的Release版本就够了。 (4)把include和glfw3.lib(静态库)拷贝出来,备用。

4.3 glad

这个最简单,直接配置就可以,配置地址:https://glad.dav1d.de/ 只填一个gl版本就行(根据自己显卡确认,如果确定不了,就选3.3版本,其他新版本都是基于3.3扩展而来的,核心未变,可以兼容),最后点GENERATE,然后直接下载glad.zip,里面一个include一个glad.c,include加载到vs2015工程,glad.c直接作为源码加入你的opengl工程。

5.第一个opengl+glfw3+glad工程

新建一个控制台空项目,控制台可以用printf或cout打印,便于自己调试。 先把glad.c加入到工程 把glfw3和glad的include添加到工程的附加目录 在依赖库里面新增2个新的:opengl32.lib和glfw3.lib 新建一个文件HelloWorld.cpp文件,copy下面源码进去编译,然后运行程序即可。代码来自opengl学习网站,我自己加了一点点注释。


#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

#define GL_PRINT(S) (printf("%s\n",#S),S)

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

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
	// glfw: initialize and configure
	// ------------------------------
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

	// glfw window creation
	// --------------------
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);//将该窗口作为当前线程的主上下文
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//注册回调函数,这里是窗口大小改变时候调用framebuffer_size_callback,该函数还可以注册其他相关硬件的回调函数

	// glad: load all OpenGL function pointers
	// ---------------------------------------
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))//初始化glad库,只要用glad库都这么写,没什么可说的,glfwGetProcAddress这个函数返回指定的OpenGL或OpenGL ES核心或扩展函数的地址,如果它被当前上下文所支持的话。
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	// render loop
	// -----------
	while (!glfwWindowShouldClose(window))//不阻塞,循环会一直执行
	{
		// input
		// -----
		processInput(window);

		// render
		// ------
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
		// -------------------------------------------------------------------------------
		glfwSwapBuffers(window);//交换缓冲区,这里用了双缓冲技术,用两个内存区域来保存数据,分为前缓冲区和后缓冲区,前缓冲区用于展示屏幕上的内容,而后缓冲区就用来绘制,然后每一帧开始的时候,将两个缓冲区交换,这样后缓冲区又可以画新的内容
		glfwPollEvents();//轮询事件(如: 鼠标键盘事件)
	}

	// glfw: terminate, clearing all previously allocated GLFW resources.
	// ------------------------------------------------------------------
	glfwTerminate();
	return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	// make sure the viewport matches the new window dimensions; note that width and 
	// height will be significantly larger than specified on retina displays.
	glViewport(0, 0, width, height);
	GL_PRINT("Window Resize!");
}