计算机图形学实验

  计算机图形学实验笔记   计算机视觉学累了就看看计算机图形学…反向消化…   理论看累了就敲敲代码   说不弃坑,就不弃坑|( ´・∧・`)

实验:搭建OpenGL环境

  OpenGL版本:3.3

GLFW

  GLFW是一个OpenGL的C语言库,是对之前固定管线常用的GLUT的一种改进。   官网下载源代码包(推荐),或者下载32位的预编译的二进制版本。

编译glfw3.lib

  我下载的最新3.3版,下载后解压。并新建一个build文件夹。   下载CMake,安装Win32版本。

  找到bin文件夹下cmake-gui.exe,   填入源代码路径和build文件夹路径:   Where is the source code: E:/glfw-3.3   Where to build the binaries: E:/glfw-3.3/build

  点击Configure按钮,选择合适的生成器(我选择的是VS2015)。点Finish。   再次点击Configure按钮保存设置。   点击Generate按钮,生成工程文件。

  在build文件夹打开GLFW.sln文件,并且生成解决方案。   在E:\glfw-3.3\build\src\Debug中所需要的glfw3.lib就有了。

配置

  方便起见,我专门建立了一个文件夹OpenGLFiles用来存放相关的头文件和库文件。   在文件夹下新建include文件夹和lib文件夹。

  将glfw-3.3\include下的文件复制到新建的include文件夹中,将glfw3.lib复制到新建的lib文件夹中。

  新建项目所需工程文件,创建空项目。   打开工程属性页,选择VC++目录-包含目录中加上:   E:\OpenGLFiles\include   库目录加上:   E:\OpenGLFiles\lib

  链接器-输入,附加依赖项加上:   glfw3.lib

GLAD

  开发者需要在OpenGL运行时获取函数地址并保存在一个函数指针中,取地址方法因平台而异,而GLAD库能简化该过程。

  通过GLAD在线服务,language选择C/C++,gl选择3.3,Profile选择Core,Options选中Generate a loader。   点击Generate,下载压缩包。解压后,将include文件夹下的文件复制到我新建的include文件夹里,并且将src下的glad.c添加到工程中。

  环境搭好了!


slug: EWPQxiwc aliases: [‘2019/05/12/计算机图形学实验/’] title: 计算机图形学实验 字数统计: WordCount date: 2019-05-12 17:25:58 updated: 2019-05-16 17:33:36 tags: [计算机图形学] categories: 互联网

实验:绘制三角形

初始化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
	//初始化GLFW
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_RESIZABLE, FALSE);

	//创建窗口
	auto window = glfwCreateWindow(screen_width, screen_height, "Triangle",
		nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to Create OpenGL Context" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	//初始化GLAD
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	//指定当前视口尺寸 
	glViewport(0, 0, screen_width, screen_height);

顶点输入

  三角形顶点数据是标准化的设备坐标,即x,y,z轴坐标映射到[-1,1]之间。

1
2
3
4
5
6
	const float triangle[]=
	{
		-0.5f,-0.5f,0.0f;//左下
		0.5f, -0.5f, 0.0f;//右下
		0.0f, 0.5f, 0.0f;//正上
	};

数据处理

VBO

  将顶点数据发送到GPU处理。生成一个顶点缓冲对象VBO,将其绑定到顶点缓冲对象上。   作用:不用将顶点数据逐个发送至显卡,可借助VBO一次性发送过去。   再使用glBufferData将顶点数据绑定到当前默认的缓冲上。

1
2
3
4
5
6
	//生成并绑定VBO
	GLuint vertex_buffer_object;
	glGenBuffers(1, &vertex_buffer_object);
	glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);
	//将顶点数据绑定到当前默认的缓冲中
	glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);

VAO

  作用:核心模式需要使用VAO,渲染时只需调用一次VAO即可,之前的数据对应存储在VAO中,不用再调用VBO。

1
2
3
	GLuint vertex_array_object;
	glGenVertexArrays(1, &vertex_array_object);
	glBindVertexArray(vertex_array_object);

顶点属性

  告诉OpenGL如何解释顶点数据。

1
2
3
	//设置顶点属性指针
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

  glVertexAttribPointer函数参数含义:   1-顶点着色器位置值   2-顶点属性是一个三分量的向量   3-顶点类型   4-数据是否被标准化(映射到0-1之间)   5-步长(这里表示下组数据在3个float之后)   6-数据偏移量(此处位置属性在数组开头,因此为0)

  glEnableVertexAttribArray表示开启0这个通道,默认状态是关闭的。

  此时需要解绑VAO和VBO。   原因:   1. 防止继续绑定VAO时影响当前VAO。   2. 使代码更具灵活性,在渲染需要时会再次绑定VAO。

1
2
	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

顶点着色器和片段着色器

顶点着色器

  GLSL语言,类似C语言。   源码:

1
2
3
4
5
6
7
	const char *vertex_shader_source =
		"#version 330 core\n"
		"layout (location = 0) in vec3 aPos;\n"
		"void main()\n"
		"{\n"
		"	gl_Position = vec4(aPos, 1.0);\n"
		"}\n\0";

  第一行:使用OpenGL3.3核心模式   第二行:上面提到的位置值 in表示输入变量   main函数中将顶点数据直接输出到GLSL定义好的内建变量gl_Position中,这是顶点着色器的输出。   (即在顶点着色器这儿上面都没做,只是将顶点位置作为顶点着色器的输出。)

片段着色器

  源码:

1
2
3
4
5
6
7
	const char *fragment_shader_source =
		"#version 330 core\n"
		"out vec4 FragColor;\n"
		"void main()\n"
		"{\n"
		"	FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
		"}\n\0";

  前两行类似上面,out表示输出变量。四分量是RGBA。

生成和编译

  目的是为了得到着色器程序,所以首先生成和编译着色器,再链接到着色器程序中。   生成并编译顶点着色器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
	int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
	glCompileShader(vertex_shader);
	int success;
	char info_log[512];
	//是否成功编译
	glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
		std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
	}

  生成并编译片段着色器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
	int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
	glCompileShader(fragment_shader);
	//是否成功编译
	glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
		std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
	}

  链接顶点和片段着色器至一个着色器程序,并删除着色器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
	int shader_program = glCreateProgram();
	glAttachShader(shader_program, vertex_shader);
	glAttachShader(shader_program, fragment_shader);
	glLinkProgram(shader_program);
	//是否成功链接
	glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
	if (!success)
	{
		glGetProgramInfoLog(shader_program, 512, NULL, info_log);
		std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
	}

	//删除着色器
	glDeleteShader(vertex_shader);
	glDeleteShader(fragment_shader);

渲染

  渲染时只需使用链接好的着色器程序就行,不再需要使用顶点和片段着色器。   窗口未关闭就一直进行渲染。

1
2
3
4
while (!glfwWindowShouldClose(window))
{
	//渲染操作
}

  这里使用蓝色背景色清空屏幕颜色缓冲。

1
2
		glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

  接下来使用链接好的着色器和VAO来绘制三角形。

1
2
3
4
5
6
		//使用着色器程序
		glUseProgram(shader_program);
		//绘制三角形
		glBindVertexArray(vertex_array_object);
		glDrawArrays(GL_TRIANGLES, 0, 3);
		glBindVertexArray(0);

  其实绘制本身只是一个glDrawArrays函数,参数1表示三角形,参数2表示顶点数组起始索引值,参数3表示要绘制的顶点数量。  绘制结束后解除绑定。   双缓冲技术:

1
2
3
4
		//交换缓冲
		glfwSwapBuffers(window);
		//检查是否有触发事件(键盘输入、鼠标移动等)
		glfwPollEvents();

善后工作

1
2
3
4
5
6
	//删除VAO和VBO
	glDeleteVertexArrays(1, &vertex_array_object);
	glDeleteBuffers(1, &vertex_buffer_object);

	//退出
	glfwTerminate();

实验效果

三角形

完整代码

https://github.com/hubojing/ComputerGraphics/blob/master/Triangle

总结:

  • 初始化。
  • 数据处理:给定顶点数据,生成并绑定VAO和VBO,准备在GPU处理,设置顶点属性指针(告诉OpenGL怎么处理数据)。
  • 着色器:生成并编译顶点和片段着色器,链接为着色器程序。
  • 渲染绘制三角形。

下一个实验准备中…

使用 Hugo 构建
主题 StackJimmy 设计