刚入门opengl的时候最烦的就是各种库的配置,glut, freeglut, glfw, glew, glad, gl3w 等等,简直要晕了. 最后查阅网上的资料大概得出了这样的结论:
opengl仅仅是一个标准/规范,但是具体利用opengl开发对应的应用则需要依赖具体的开发环境例如windows, linux等, 而最常见的就是窗口, IO控制等交互逻辑,因此glut, freeglut, glfw这类的库便产生了
-
glut (Opengl Utility Tool)
- 定义以及控制视窗
- 侦测并处理键盘和鼠标事件
- 以一个函数呼叫绘制某些常用立体图形,如长方体,球,犹他茶壶
- 提供了简单选单列的实现
所有glut的库函数均已glut开头, 例如glutPostRedisplay(). 后来以及停止维护了
-
freeglut
glut的替代品,最新稳定的版本是Freeglut3.0.0 (2015年3月7日)
-
glfw (Graphics Library Framework)
- 创建管理窗口和opengl的上下文
- 处理手柄,键盘,鼠标输入
目前glfw还在维护,可以说glfw库可以是代替glut和freeglut的库的
opengl是一个标准/规范, 具体的实现是由驱动开发商针对特定的显卡而实现.支持opengl的驱动版本众多,大多数函数的地址(内存地址)无法在编译时候确定下来,需要运行的时候查询.所以在运行的时候获取函数的内存地址并把其保存在一个函数指针中供后续使用. glew, glad, gl3w基本都是实现类似的功能
-
glad
//glad.h /////////////////////////////////////////////////////////////////// /*#55 定义一个函数指针,为GLADloadproc类型,这种函数是以一个const char*为参数并返回void*的类型,在glad.c中便用GLADloadproc load来声明了一个GLADloadproc 类型的函数load, 所以load函数的参数为(const char *name)返回值为void* */ typedef void* (* GLADloadproc)(const char *name); //////////////////////////////////////////////////////////////////////// //这里的APIENTRYP(API_entry_pointer即api条目指针) 表示 APIENTRY *, 而APIENTRY表示 __stdcall #define GLAPI extern #define APIENTRY __stdcall #define APIENTRYP APIENTRY * /////////////////////////////////////////////////////////////////////// /*#1806, 定义函数指针,为PFNGLGENBUFFERSPROC类型,参数为(GLsizei n, GLuint *buffers), 返回值为void的类型*/ typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); /*用为PFNGLGENBUFFERSPROC类型来定义一个函数指针名字为glad_glGenBuffers, 类型是extern*/ GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; #define glGenBuffers glad_glGenBuffers // glGenBuffers的宏定义,使用glGenBuffers函数时候其实就是调用的glad_glGenBuffers //////////////////////////////////////////////////////////////////////// //glad.c PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;//#452 声明和定义glad_glGenBuffers这个函数指针为NULL glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers");//#1086, 使用glad_glGenBuffers函数的时候就去load名字为glGenBuffers的函数
具体怎么找函数的流程:
openg工程中main函数里面有gladLoadGLLoader, gladLoadGLLoader里面把从opengl1.0到目前最高opengl4.6的函数都读入
-
在glad.c中有一个函数
static int open_gl(void) { #ifndef IS_UWP libGL = LoadLibraryW(L"opengl32.dll"); if(libGL != NULL) { void (* tmp)(void); tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress"); gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp; return gladGetProcAddressPtr != NULL; } #endif
去系统中加载opengl32.dll这个库,然后GetProcAddress检索指定的动态链接库(DLL)中的输出库函数地址.
而[根据某位知乎网友的解答][https://www.zhihu.com/question/30130562/answer/46983748] ,opengl32.dll仅仅为用户提供了统一API的接口以及扩展这些接口的可能, opengl32.dll被加载后尝试调用更底层的ICD驱动程序,从而完成具体的图形操作. 而GLEW这些库,根据opengl的接口说明,从动态库(opengl32.dll)中请求对应的函数接口,如果能得到有效地址,那么这个函数是被当前驱动所支持的,就可以用,否则就无法支持.实际上,你也可以根据你当前应用中使用到的函数(通常一个小的演示demo,如显示一个三角形,并没有使用到很多的gl函数)而获取函数接口也是完全可行的. glew,glad,gl3w这些库帮助用户完成了所有接口的查询和获取.
glad, gl3w的作用类似不做更多叙述.
但是gl3w是利用python开发的, 因此需要安装python库进行编译生成相关的文件,具体的流程可以参考基于GLFW和GL3W库的OPEN GL环境配置
结论: 可以用上面两类的库进行组合,例如我自己常用的是glfw + glad来进行opengl的开发, 也有很多开发者使用的是glfw + gl3w, 或者 glfw + glew