Opengl
Opengl即Open graphic library开源图形库,然后他本身并非是一个函数库,而仅仅是一个接口规范,各家厂商由于并不愿意公开自己的源码,但是又有开发需求(游戏工作室要进行开发),所以依照这个规范进行设计,方便开发人员的调用。
作为开发人员,Opengl提供了一些命令,让我们调用这些命令就可以完成我们对应想要完成的操作。例如,使用这个命令,我们就可以画出一个光源,就可以设置颜色,但是具体的实现是由各个厂商设计完成的。
在使用Opengl前,还需要简单了解三个部分的知识,Cmake,GLFW库,以及GLAD库。
Cmake
cmake是一个开源的跨平台工具集合,通过cmake我们可以根据自己所在的平台,编译环境控制软件的编译过程。具体介绍可以看
cmake官网:https://cmake.org/
cmake指导手册:https://cmake.org/cmake/help/latest/module/FetchContent.html
这里我们只需要了解一个部分,我们下载下来的软件包,里面包含了一个CmakeList.txt文件,该文件告诉Cmake该如何构建这个软件包,例如我们“输入”这是VS平台,那他就会按照VS进行软件构建。可以简单的使用图形化界面操作。
GLFW
由于Opengl作为一个接口规范,肯定要在各个平台上有相同的作用效果,那么就不能涉及到图形化界面,用户输入输出这些交互处理部分,因为这些操作在不同平台,不同系统是不统一的,需要程序员自己在所在平台上编写交互命令。但是这无疑增加了负担,对于一般学习Opengl,又想要通过界面更好的观察运行效果,其实没有必要单独编写,使用GLFW库,就可以帮我们很好的解决这个问题。允许我们绑定Opengl上下文,进行窗口创建,处理用户的输入输出等。
GLFW下载地址:www.glfw.org/download.html
下载之后使用cmake进行特定平台的构建,就可以使用了。
GLAD
Opengl作为一个接口规范,具体的实现是由厂商编写保存在某个地方,这个函数的地址我们是不知道的。那么该如何调用我们需要的函数呢。使用函数指针的方法:
// define the function’s prototype
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// find the function and assign it to a function pointer
GL_GENBUFFERS glGenBuffers =
(GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// function can now be called as normal
unsigned int buffer;
glGenBuffers(1, &buffer);
Windows平台提供了wglGetProcAddress(string name);通过传入我们想要调用的函数名字,就会返回该函数的地址,通过该函数指针就可以使用该函数功能。但是如果每一个函数都需要用以上代码调用的化,一行调用代码变为了三行,非常浪费时间。但是我们在编译期间不知道具体函数的地址的,GLAD就是解决这个问题,他会在编译期间得到所有的函数指针,我们就可以直接使用。在https://glad.dav1d.de/,可以根据我们需要的Opengl版本号和平台自动生成GLAD库,下载即可。
Glad的使用很简单:
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
这一步骤加载函数会根据你的Opengl版本号(在你生成的时候已经选择好了),加载所有支持的Opengl函数,以加载Opengl3.3版本的函数为例。
static void load_GL_VERSION_3_3(GLADloadproc load) {
if(!GLAD_GL_VERSION_3_3) return;
glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed");
glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex");
glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers");
glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers");
glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler");
glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler");
glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri");
glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv");
glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf");
glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv");
glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv");
glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv");
glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv");
glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv");
glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv");
glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv");
glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter");
glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v");
glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v");
glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor");
glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui");
glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv");
glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui");
glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv");
glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui");
glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv");
glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui");
glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv");
glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui");
glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv");
glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui");
glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv");
glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui");
glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv");
glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui");
glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv");
glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui");
glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv");
glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui");
glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv");
glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui");
glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv");
glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui");
glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv");
glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui");
glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv");
glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui");
glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv");
glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui");
glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv");
glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui");
glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv");
glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui");
glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv");
glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui");
glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv");
glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv");
}
可以看到GLAD将所有的函数地址预先获得保存下来(保存格式为原本函数名加上glad_前缀)。但是使用的时候是直接按照原名称来使用的,例如我们会用glColorP4uiv,而不是glad_glColorP4uiv。这是为什么呢,看glad.h可以发现,他做了非常多的宏定义:
#define glNormal3s glad_glNormal3s
所以我们使用的函数其实已经是glad的宏定义常量,本质上值还是加上了glad前缀。这样就可以在程序中直接使用我们想用的函数,而不需要繁琐的绑定了。