一篇搞懂什么是OpenGL,并基础画图(含代码)

本文介绍了为何学习OpenGL,强调了其跨平台、开放性和社区支持等优势,并对比了与DirectX的区别。文章还分享了学习路径、环境配置以及OpenGL的基础操作,包括窗口创建、GLFW和GLEW库的使用,以及缓冲区和着色器的概念。
摘要由CSDN通过智能技术生成

为什么我要学习OpenGL,首先学习 OpenGL 具有许多优势,尤其是在计算机图形学和图形编程领域,它是有开放性和跨平台这两个显著优点的,还有其他的优势比如强大的功能,广泛的支持和应用,在OpenGL之上有许多开发的比较完善的库,而且它是有社区众多维护者的,非常主流,当然最重要的一点就是学了它工作技能点又上去了,程序员当然是多多益善。

一、什么是OpenGL

百度解释:OpenGL是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)
自我理解:OpenGL是一套方便于用户使用的规范,而其本身包含了调用不同厂商直接在GPU中写好的程序接口,那些接口完成所有的功能实现,如完成2D、3D矢量图形渲染等功能。

二、OpenGL和DirectX的区别,如何选择使用

OpenGL(Open Graphics Library)和 DirectX 是两个用于图形渲染的开发接口。它们分别由不同的公司和组织开发,分别用于不同的操作系统和平台。以下是对这两者的简要比较:

OpenGL:
跨平台:
OpenGL 是一个跨平台的图形渲染 API,可以在多种操作系统上运行,包括 Windows、Linux 和 macOS。OpenGL 可以运行在各种图形硬件上,并且支持多种编程语言,如C++、Python等。

DirectX:
Windows 平台专用:
DirectX 是由 Microsoft 开发的,主要用于 Windows 平台。因此,它是 Windows 游戏开发的首选 API。由于其与 Windows 平台的深度集成,DirectX 在与 Windows 系统的协同工作和性能优化方面可能会更好。

DirectX 不仅包括图形渲染功能,还包括音频、输入、网络等功能,使其成为一个全面的多媒体开发套件。

如何选择:
一句话:如果你的应用程序需要在多个操作系统上运行,那么 OpenGL 可能是更好的选择。如果你专注于 Windows 游戏开发,DirectX 可能更适合。
在上面的选择条件下如果你的应用程序不仅仅涉及图形渲染,还包括音频、输入等方面,那么 DirectX 可能更合适。

三、学习的起始与流程

当我在决定学习OpenGL之后,首先要做的就是制定学习的计划,像这种主流的前沿的技术,一般是需要向国外学习的。最后选择跟着一位国外的大神学习,主要他讲的很基础,也很全,而且他不仅有OpenGL的教学,还有学习了OpenGL之后的,想要深入游戏引擎的教学,这就很全面了,不至于学了之后,感兴趣却不得不换一个人学习的尴尬之地。

由于作者本身是c++开发出身,所以c++基础勉强能跟上,如果c++不是很了解的话,建议的学习流程是

  1. C/C++基础
  2. Visual Studio的使用
  3. OpenGL
  4. OpenGL在游戏引擎的应用

话不多说,我把我看的视频链接贴出来,下面的笔记都是由视频学习而来,或者有些自己的补充吧。

跟着这个小哥的教学视频学的(YouTube原视频,科学上网AI字幕) ►                     http://bit.ly/2lt7ccM
这个是哔哩哔哩网站有人搬运的 ►https://www.bilibili.com/video/BV1MJ411u7Bc/?share_source=copy_web&vd_source=80ce9fa9cc5a33fdc2b9a467859dd047

四、环境准备与OpenGL第一次调用

环境:

Visual Studio 2019

Win11

1. 调试通过OpenGL最基础的窗口和画三角形(老方法)

首先VS创建一个空项目,然后用最简单的HellowWorld输出打印能通过

然后引入GLFW库,全称是(Graphics Library Framework)是一个专门用于创建窗口和处理用户输入的开源库。它提供了一个简单而强大的接口,使得创建图形应用程序变得更加容易。

就是它可以创建一个窗口,然后里面的图像可以利用OpenGL机制来渲染。

我们通过官网获取这个库

GLFW ► https://www.glfw.org/

这里提一下视频教学中提了,对于我们自己用或者是快速的使用这些库,可以下载已经编译好的二进制文件及现成的库,但是如果是要开发项目或者是良好习惯最好是能下载源码,嵌入到自己的项目中,然后跟着项目一起编译,这样在遇到问题的时候可以直接跟踪到源码里面去看,也可以更加深入的学习。
还有关于32bit 和 64bit 这个也是根据需求和自身需要来下载,因为32在32和64机器上都能跑,而64则不能再32机器上跑,所以这里就选择通用一点的32下载。

当链接库时,连接静态库.lib后缀的库的时候,有时候会有两个名字非常类似的库,在选择的时候,去连接那个比较大的,因为比较小的可能是用于连接动态库的静态库,这种有些库名字上不太会体现的很明显。如图

然后利用VS链接静态库,最后使用传统的画图方法,画出三角形如下图

2. 利用库GLEW使用缓冲区和着色器的概念来画三角形

之后我们就利用GLEW,全称(OpenGL Extension Wrangler)是一个用于管理OpenGL扩展的库。它的主要目的是简化OpenGL的扩展加载过程,允许你更轻松地访问OpenGL的所有功能,包括最新的扩展。

人话就是让我们几乎可以用这些封装好的接口和函数,方便简单的调到OpenGL的所有内容,我记得OpenGL本身的程序是在GPU中,如果我们一个一个去看原始的那些函数,将会很麻烦,所以看这些封装好的接口就比较简单和快速了,不过官方文档还是不能错过。

我们通过官网获取这个库

GLEW ► http://glew.sourceforge.net/

和GLFW一样的方式导入,链接静态库,然后这里有许多注意事项,也是视频教学中提到的,在引用头文件的时候,#include < GL/glew.h>要在#include <GLFW/glfw3.h>之前,不然会报错,而且GLEW官方文档第一句提到的,你所要初始化的位置一定是要有渲染上下文的,不然就会初始化失败。

所以是要放在这个位置初始化才能成功的。

然后就是OpenGL操作GPU的现代化方式了,这里就需要引出两个东西:缓冲区和着色器

因为c++写的程序都是在cpu上运行的,但是OpenGL的接口是在GPU上运行的,而且OpenGL并不能凭空做程序中的数据或者是取代一些程序上的事,它是一种状态机,程序从cpu发数据到缓冲区并且告诉GPU你从哪一块缓冲区取数据画什么,然后提前设计好的着色器开始根据数据画图最后显示在显示器上。

画图渲染的顺序如下

  1. 声明一个缓冲区
  2. 声明之后需要绑定,因为在GPU中的缓冲区都是有编号的,或者说是有管理的
  3. 现在要给一个缓冲区塞数据,每个接口函数都可以通过说明文档来查看参数的意义和使用
  4. 我们需要告诉着色器我们的数据是怎么样的, 或者说是怎么处理这些数据

这里有一个些比较重要概念和一个接口函数和​​​​​​
void glVertexAttribPointer(GLuint , indexGLint , sizeGLenum , typeGLboolean , normalizedGLsizei , strideconst GLvoid * pointer);

人话就是:

  • index:我们从第几个顶点开始访问
  • size:一个顶点属性值里面有几个数值
  • type:每个值的数据类型
  • normalized:是否要转化为统一的值
  • stride:步幅 每个顶点属性值的大小,就是到下一个顶点的开始的字节偏移量。
  • pointer:在开始访问到顶点属性值的时候开始的指针位置(注意和Index的区别)

其实你就是把顶点属性值想象成结构体就行了,然后多个结构体一起存,和网络传输一样,我发送给了另一边需要解析网络包,是不是需要找我结构体开始的位置,然后一个结构体的大小,然后结构体对齐里面有什么,分别解析,还有步幅指针,我还可以跳过结构体,是一样的道理。

如图:

 

最后加上 可用的顶点从第几个开始的这个 glEnableVertexAttribArray(0); 函数。就可以打印出来三角形了。

五、附上视频1-5的学习代码(但是会有崩溃,暂时写到这,之后会更改的

#include <iostream>
#include < GL/glew.h>
#include <GLFW/glfw3.h>


int main()
{
	//std::cout << "Hello OpenGL" << std::endl;
	//std::cin.get();

	GLFWwindow* window;

	/* Initialize the library */
	if (!glfwInit())
		return -1;

	//if (glewInit() != GLEW_OK)
	//	std::cout << "GLEWInit ERROR!" << std::endl;

	/* Create a windowed mode window and its OpenGL context */
	window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}

	/* Make the window's context current */
	glfwMakeContextCurrent(window);

	if (glewInit() != GLEW_OK)
		std::cout << "GLEWInit ERROR!" << std::endl;
	std::cout << "OpenGL的版本是:" << glGetString(GL_VERSION) << std::endl;

	//声明一个float数组,顶点属性列表
	float positions[6] = {
		-0.5f, -0.5f,
		 0.0f,  0.5f,
		 0.5f, -0.5f
	};

	//这里声明一个缓冲区
	unsigned int buffer;
	glGenBuffers(1, &buffer);
	//声明之后需要绑定,因为在GPU中的缓冲区都是有编号的,或者说是有管理的
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	//现在要给一个缓冲区塞数据,每个接口函数都可以通过说明文档来查看参数的意义和使用
	glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);

	//可用的顶点从第几个开始
	glEnableVertexAttribArray(0);
	//index:我们从第几个顶点开始访问
	//size:一个顶点属性值里面有几个数值
	//type:每个值的数据类型
	//normalized:是否要转化为统一的值
	//stride:步幅 每个顶点属性值的大小,就是到下一个顶点的开始的字节偏移量。
	//pointer:在开始访问到顶点属性值的时候开始的指针位置(注意和Index的区别)
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

	/* Loop until the user closes the window */
	while (!glfwWindowShouldClose(window))
	{
		/* Render here */
		glClear(GL_COLOR_BUFFER_BIT);

		//我们需要告诉着色器我们的数据是怎么样的, 或者说是怎么处理这些数据
		glDrawArrays(GL_TRIANGLES, 0, 3);

		传统OpenGL的调用和使用方式
		//glBegin(GL_TRIANGLES); //三角形 
		这里坐标在三角形的正中心0,0
		//glVertex2f(-0.5f, -0.5f); //左
		//glVertex2f( 0.0f,  0.5f); //中
		//glVertex2f( 0.5f, -0.5f); //右
		//glEnd();

		/* Swap front and back buffers */
		glfwSwapBuffers(window);

		/* Poll for and process events */
		glfwPollEvents();
	}

	glfwTerminate();
	return 0;
}

最后就是很多的OpenGL方法都是需要自己熟悉的,这里要锻炼一下自己的看说明文档的能力。OpenGL API 说明文档,包含了大量的opengl的接口函数使用方法和说明等等。
OpenGL Documentation ► http://docs.gl

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值