OpenGL学习笔记之绘制三角形

参考https://learnopengl.com/

1、创建窗口

glfw是一个针对OpenGL的窗口管理库,这里使用glfw库创建窗口并处理输入,glfw库可以在它的官网上下载,提供了动态库和静态库供选择,也可以下载源码自己编译。

以官方下载的静态库glfw3.lib为例,将下载的静态库复制到自己方便管理的路径,这里放在工程路径下的lib文件夹内,并将该文件路径添加到工程属性的依赖库里

OpenGL学习笔记之绘制三角形_第1张图片

将glfw3.h复制到工程目录下的glfw文件夹内,并在.cpp文件内包含该头文件#include "glfw/glfw3.h"
创建窗口的步骤:
(1)初始化glfw
glfwInit();
(2)配置OpenGL属性项
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint设置相应的属性,GLFW_CONTEXT_VERSION_MAJOR和GLFW_CONTEXT_VERSION_MINOR设置需要使用的OpenGL版本,这里选择3.3版本,GLFW_OPENGL_CORE_PROFILE表示我们使用core-profile版本,不需要兼容低版本特性
(3)创建窗口
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);//创建一个800x600大小的窗口
if (window == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//将window设置为当前窗口
(4)显示窗口并处理消息
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwWindowShouldClose判断窗口是否要关闭,点击关闭按钮的时候返回true,也就是退出循环
glfwSwapBuffers交换缓冲区,将要显示的像素颜色显示到屏幕
glfwPollEvents处理消息
(5)结束
最后调用glfwTerminate()即可。
最后代码合起来

#include "glfw/glfw3.h"
int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL", NULL, NULL);
	if (window == NULL)
	{
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	while (!glfwWindowShouldClose(window))
	{
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwTerminate();
	return 0;
}


2、画三角形

窗口创建后就可以在窗口上画出三角形了,这里需要用到OpenGL的api接口,如果自己写代码获取OpenGL动态库中的函数就太麻烦了,而且OpenGL有很多版本,不同版本的api也有区别。
使用glad库可以解决这个问题,glad中包含了OpenGL不同版本的API,使用上面的glfwWindowHint指定版本后,就可以获取到指定版本的所有函数了。
glad文件获取:打开网址http://glad.dav1d.de/,如下图
OpenGL学习笔记之绘制三角形_第2张图片

Language选择C/C++,Specification选择OpenGL,gl选择你需要的版本,这里是Version 3.3,Profile选择Core,勾选Generate a loader,点击GENERATE按钮就会生成glad.zip文件。
将zip文件解压出来有src和include文件夹,分别有glad解压出来有src和include文件夹,分别有glad.h、khrplatform.h和glad.c,将include下面的两个文件夹glad和KHR复制到工程的包含目录,例如VS安装目录下的VC\inlcude目录,glad.c文件添加到工程中。
之后只要在需要使用的地方加上头文件包含#include "glad/glad.h",并在使用OpenGL函数之前加载所有函数指针gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)就可以了,glfwGetProcAddress位于glfw3.h中。
接下来就可以开始准备画三角形了
(1)编写顶点着色器(vertex shader)和片段着色器(fragment shader)
顶点着色器和片断着色器都是使用着色器编程语言GLSL编写
//顶点着色器代码:
#version 330 core	//版本
layout (location = 0) in vec3 vertexPos;	//顶点位置,由程序传入
void main()//着色器程序执行main函数
{
   gl_Position = vec4(vertexPos, 1.0);//gl_Position为内部定义变量,表示顶点的位置
}
//片段着色代码:
#version 330 core
void main()
{
   gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);//gl_FragColor为内部定义变量,表示像素的颜色
}
(2)创建和编译着色器
为了方便,将着色器创建和编译放到CreateShader函数内

GLuint CreateShader(GLuint type,const GLchar* source)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);
	GLint success;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);//获取编译结果
	if (!success)
	{
		char infoLog[512];
		glGetShaderInfoLog(shader, 512, NULL, infoLog);//获取具体错误描述infoLog
		std::cout << infoLog << std::endl;
	}
	return shader;
}
假设顶点着色器程序字符串为const GLchar* vsSource,片段着色器程序字符串为const GLchar* fsSource,则创建顶点着色器和片断着色器的代码分别为
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER,vsSource);
GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER,fsSource);
(3)创建着色器程序
这里将创建和编译着色器以及创建着色器程序一起放到CreateShaderProgram函数内

GLuint CreateShaderProgram(const GLchar* vsSource,const GLchar* fsSource)
{
	GLuint vertexShader = CreateShader(GL_VERTEX_SHADER,vsSource);
	GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER,fsSource);
	GLuint program = glCreateProgram();
	glAttachShader(program, vertexShader);
	glAttachShader(program, fragmentShader);
	glLinkProgram(program);
	GLint success;
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	if (!success) 
	{
		char infoLog[512];
		glGetProgramInfoLog(program, 512, NULL, infoLog);
		std::cout << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	return program;
}
(4)将三角形顶点数据传入着色器
GLfloat vertices[] = 
{
	-0.5f,  0.5f, 0.0f,  // 1
	-0.5f, -0.5f, 0.0f,  // 2
	0.5f, -0.5f, 0.0f,  // 3
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);//创建顶点数组对象
glGenBuffers(1, &VBO);//创建顶点缓冲
glBindVertexArray(VAO);//设置当前顶点数组对象为VAO
{
	glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定VBO到GL_ARRAY_BUFFER
	{
		//将定点数据赋值给GL_ARRAY_BUFFER,也就是VBO
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
		//将缓冲中的顶点数据和vertexPos关联起来,这里是通过第一个参数0和着色器中的location=0关联的
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
		glEnableVertexAttribArray(0);
	}
	glBindBuffer(GL_ARRAY_BUFFER, 0);//取消VBO绑定
}
glBindVertexArray(0);//取消VAO绑定
为了看起来清晰,将部分代码用{}括起来,后面只要使用VAO就可以获取到顶点数据,OpenGL的坐标范围为-1到1
glVertexAttribPointer参数说明:
第一个参数表示变量的位置,也就是着色器中的location=n中的n;
第二个参数表示一个顶点的数据个数,这里是3个;
第三个参数为数据类型,这里为GL_FLOAT;
第四个参数表示数据是否要做标准化处理,如果为true,数据将被映射到-1到1之间,false则不做处理;
第五个参数为顶点数据间隔,就是相邻两个数据的起始地址之间的间隔,这里一个顶点3个GLfloat数据,所以间隔也是3*sizeof(GLfloat);
第六个参数为顶点数据起始地址偏移,这里从0位置开始所以就是(void*)0;
(5)渲染三角形
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//设置清除颜色
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);//shaderProgram为CreateShaderProgram返回的着色器程序
glBindVertexArray(VAO);		//绑定VAO
glDrawArrays(GL_TRIANGLES, 0, 3);//画三角形
(6)结束
程序退出前执行相应的清理工作,这里只要删除VAO、VBO和shaderProgram
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);

运行结果:

OpenGL学习笔记之绘制三角形_第3张图片

附上完整代码:
#include "glad/glad.h"
#include "glfw/glfw3.h"
#include

const GLchar *vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 vertexPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(vertexPos, 1.0);\n"
"}\0";
const GLchar *fragmentShaderSource =
"#version 330 core\n"
"void main()\n"
"{\n"
"   gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
"}\n\0";

GLuint CreateShader(GLuint type, const GLchar* source)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);
	GLint success;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		char infoLog[512];
		glGetShaderInfoLog(shader, 512, NULL, infoLog);
		std::cout << infoLog << std::endl;
	}
	return shader;
}

GLuint CreateShaderProgram(const GLchar* vsSource, const GLchar* fsSource)
{
	GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, vsSource);
	GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER, fsSource);
	GLuint program = glCreateProgram();
	glAttachShader(program, vertexShader);
	glAttachShader(program, fragmentShader);
	glLinkProgram(program);
	GLint success;
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	if (!success)
	{
		char infoLog[512];
		glGetProgramInfoLog(program, 512, NULL, infoLog);
		std::cout << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	return program;
}

int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		return -1;
	}
	GLuint shaderProgram = CreateShaderProgram(vertexShaderSource,fragmentShaderSource);
	GLfloat vertices[] = {
		-0.5f,  0.5f, 0.0f,  // 1
		-0.5f, -0.5f, 0.0f,  // 2
		0.5f, -0.5f, 0.0f,  // 3
	};
	GLuint VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);
	{
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		{
			glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
			glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
			glEnableVertexAttribArray(0);
		}
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}
	glBindVertexArray(0);

	while (!glfwWindowShouldClose(window))
	{
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		glUseProgram(shaderProgram);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteProgram(shaderProgram);
	glfwTerminate();
	return 0;
}




你可能感兴趣的:(OpenGL)