使用 glew

glew 全称是 OpengGL Extension Wrangler Library,它能够帮忙解决 OpengGL 不断扩展的问题。初始化 glew 之后,它将查询系统上所有可用的扩展功能并自动加载它们,然后提供一个头文件作为接口,我们直接通过头文件就可以使用这些扩展功能。
glew 的下载地址
http://glew.sourceforge.net/
下载之后进行解压,得到的目录结构

|-glew-2.1.0|-bin|-lib|-include|-doc

接下来开始配置环境,配置的方式有两种,第一种方式跟配置 glut 一样,系统级的配置,配置之后所有的 opengl 项目都不需要配置

  • 第一步,把 include 目录下的头文件放在 %VISUAL_STUDIO%\VC\include\gl 目录下
  • 第二步,把 lib 目录下的 lib 文件放在 %VISUAL_STUDIO%\VC\lib 目录下,然后在项目属性的 链接器 –> 输入 添加相应库的引用
  • 第三步,把 bin 目录下的 dll 文件放在 system32 目录下,同样的 64 位系统要放在 sysWOW64 目录下

这种方式虽然能够一劳永逸,但因为 win32 和 x64 的库文件名一样,所以无法做到兼容,即无法同时把 32 位的库文件和 64 位的库拷到系统路径;另外过多地把库文件拷到系统路径也不好,因此推荐使用第二种方式,即给每个创建的项目配置环境

  • 把头文件放在 $PROJECT_ROOT%\include\GL 目录下,然后在项目属性的 C/C++ –> 附加包含目录 中添加 .\include
  • 把静态库 lib 文件放在 $PROJECT_ROOT%\lib 目录下,然后在项目属性的 链接器 –> 常规 –> 附加库目录 中添加 .\lib,在 链接器 –> 输入 中添加相应库的引用
  • 把动态库 dll 文件放在可执行程序 exe 同级目录下

如果一个项目想同时编译 32 位和 64 位,则可以分别把 32 位的 lib 文件和 64 位的 lib 文件放在 .\lib\win32 和 .\lib\x64 目录下,然后分别修改附加库目录,再把相应的 dll 文件拷到编译后的 32 位程序和 64 位程序目录下。

GL context

在开始绘制图形之前,我们必须先了解 GL context 和 GL objects 这两个重要概念,参考文档 https://www.khronos.org/opengl/wiki/Main_Page

上一篇文章讲到 OpenGL 渲染是基于状态(state)的。OpenGL context 是一个重要的概念的,只有创建了 context,OpenGL 才存在,context 一旦被销毁了,OpenGL 就不存在了。context 存储了一个 OpenGL 实例的所有状态,类似于一个程序开辟的所有内存空间。context 可以看作进程在操作系统中的一个执行过程,一个进程可以创建多个 context,每一个 context 代表一个可视面,就像一个应用程序的一个界面一样。

简单来讲,context 保存了一个 OpenGL 实例的所有状态,在使用 OpenGL 之前必须先创建一个 context。

int main(int argc, char **argv)
{char *GL_version=(char *)glGetString(GL_VERSION);char *GL_vendor=(char *)glGetString(GL_VENDOR);char *GL_renderer=(char *)glGetString(GL_RENDERER);return 0;
}

这里是想获取一些系统信息,但得到的结果却全是空,这里因为此时还没有创建 context,OpenGL 相当于不存在。

int main(int argc, char** argv)
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowSize(400, 400);glutInitWindowPosition(100, 100);glutCreateWindow("Create Dot");//获取 OpenGL 版本号char *GL_version = (char *)glGetString(GL_VERSION);//获取本机提供 GL 支持的公司char *GL_vendor = (char *)glGetString(GL_VENDOR);//获取渲染器的名称char *GL_renderer = (char *)glGetString(GL_RENDERER);//获取着色器的版本号char* GL_shader_version =  (char*)glGetString(GL_SHADING_LANGUAGE_VERSION);//获取本机硬件支持的最大顶点属性数GLint max_vertex_attrib;glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attrib);return 0;
}

这样就可以正常获取信息了,因为 glutCreateWindow 创建一个窗口的同时就相当于已经创建了一个 context。

GL objects

再重申一遍,OpenGL 基于状态来渲染,可以说 OpenGL 被定义成“状态机”,所有的 API 都是修改状态、查询状态或者使用状态来渲染。GL Object 是一些状态的集合,这点看起来跟 GL Context 有点像,也可以这样类比,但要知道 object 和 context 的 state 是相互独立的,context 有一套状态,每个 object 也会有自己的一些状态。只有把 object 绑定到 context 上,它的状态都会映射到 context 上,绑定之后修改 context 的状态,object 也会受影响;相反基于 context 状态的函数也可以使用 object 的状态。

对象可以分成两大类,regular objectscontainer objects
regular object 包括 Buffer Objects,Query Objects,Renderbuffer Objects,Sampler Objects,Texture Objects
container objects 包括 Vertex Array Objects,Framebuffer Objects,Program Pipeline Objects,Transform Feedback Objects

对象创建、销毁和绑定

使用 glGen* 函数给对象生成一个名字,就是创建对象了。

 void glGen*(GLsizei n, GLuint *objects);

这个函数可以同时创建多个对象,只需要给定一个对象数组的指针;对象名是 Glsizei 类型,也就是一个 32 位无符号整型,这个整数并不是一个指针,只是对象的一个引用,用于标识这个对象。另外,整数 0 这个名字用于特殊对象,所以我们给对象起名时只能从 1 开始。

void glDelete*(GLsizei n, const GLuint *objects);

这个函数用于销毁对象,同样如果传进来的 object 是一个数组的话,可以批量销毁多个对象。关于对象销毁有几点要注意的

  • 如果对象已经绑定到 context ,则对象销毁后会自动解绑;但如果对象附加到另一个对象上,则这我种附加关系不会解除
  • 对象被 delete 之后并不会立即删除,它的名字还可以使用,但请不要用
void glBind*(GLenum target, GLuint object);

这个函数用于把对象绑定到 context。target 指明了对象的类型,有些对象可以绑定为多个类型,比如一个 buffer obejct 可以绑定为 array buffer,index buffer,pixel buffer,transform buffer 或者其它。

VAO && VBO

我们知道了 OpenGL 是一个状态机,使用 object 来保存数据和状态,钴绑定到 context,将 object 的状态和 context 的状态关联起来,然后使用 context 的状态进行渲染。接下来就着手准备绘制一个点,这里需要用到两个对象 VBO 和 VAO。

VAO 即 Vertex Array Object,它保存了所有顶点数据的状态,并没有保存顶点数据,而是保存了顶点数据的格式和所需 buffer 对象的引用。每一个状态属性都是可以开启和关闭的,使用下面两个函数

void glEnableVertexAttribArray(GLuint index);
void glDisableVertexAttribArray(GLuint index);

VBO,即 Vertex Buffer Object,在缓存区保存的就是顶点数据了。为了让 VAO 能使用 VBO 的数据,我们需要告诉 OpenGL,编号为 index 属性使用当前绑定到 GL_ARRAY_BUFFER 的 VBO

glVertexAttribPointer(index, size, type, normalized, stride, pointer);

index 是第几个属性,像顶点的第 0 个属性就是位置;size 指定构成属性的分量个数,像顶点位置由 x,y,z 三个分量组成,所以 size=3;type 指定属性值的类型,像顶点位置为 GL_FLOAT;normalized 指属性在管线中使用之前是否需要被规范化;stride 指两个相同属性值之间间隔的字节数,只有一个属性时间隔为 0;pointer 指存储数据的偏移值,同样只有一个属性时偏移值为 0。

绘制一个点

#include <gl/glew.h>
#include <gl/glut.h>
#include <math3d.h>
#include <iostream>using namespace std;void init();
void renderPerFrame();int main(int argc, char** argv)
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowSize(400, 400);glutInitWindowPosition(100, 100);glutCreateWindow("Create Dot");char *GL_version = (char *)glGetString(GL_VERSION);char *GL_vendor = (char *)glGetString(GL_VENDOR);char *GL_renderer = (char *)glGetString(GL_RENDERER);GLenum res = glewInit();if (GLEW_OK != res){cout << "glewInit failed: " << glewGetErrorString(res) << endl;system("pause");return 1;}init();glutDisplayFunc(renderPerFrame);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glutMainLoop();
}void init()
{//创建 buffer 对象GLuint VBO;glGenBuffers(1, &VBO);//绑定 buffer 对象glBindBuffer(GL_ARRAY_BUFFER, VBO);//定义数据M3DVector3f vertices[1];vertices[0][0] = 0.0f;vertices[0][1] = 0.0f;vertices[0][2] = 0.0f;//填充 buffer 的值glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
}void renderPerFrame()
{glClear(GL_COLOR_BUFFER_BIT);//开启顶点属性glEnableVertexAttribArray(0);//指定属性使用的 bufferglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);//绘制顶点 glDrawArrays(GL_POINTS, 0, 1);//关闭顶点属性glDisableVertexAttribArray(0);glutSwapBuffers();
}

总结一下这个过程:

首先,创建顶点缓冲对象,即 VBO;然后将顶点缓冲对象绑定到 context;最后给顶点缓冲对象赋顶点数据。

经过上面三步之后,在 context 中就已经有了一个顶点缓冲对象,这个对象保存了顶点数据。接下来就是在主回调函数中取顶点数据进行绘制,这里使用的是固定管线,所以不用 VAO,后面主要使用可编程管线。

绘制的时候是基于状态的,要绘制顶点,必须知道每个状态属性从哪里取数据,即把顶点对象(VAO)和顶点缓冲对象(VBO)关联起来。首先,要开启顶点对象的某个属性;然后指定该属性使用的 buffer 对象;然后开始绘制;最后关闭顶点对象属性。

【OpenGL】绘制一个点相关推荐

  1. OpenGL绘制一个三角形的实例

    OpenGL绘制一个橘黄色的三角形 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <glad/glad.h> #include &l ...

  2. OpenGL绘制一个三角形

    OpenGL绘制一个三角形 OpenGL绘制一个三角形简介 源代码剖析 主要源代码 OpenGL绘制一个三角形简介 在本课中,我们仍然不转换坐标,因此顶点仅在正方形内可见.从 Z 的反轴看,正方形如下 ...

  3. OpenGL(十八)——Qt OpenGL绘制一个3D世界

    OpenGL(十八)--Qt OpenGL绘制一个3D世界 一.说明 本篇介绍构建一个3D的世界. 二.简介 加载3D世界,并在其中漫游: 在这一课中,你将学会如何加载3D世界,并在3D世界中漫游. ...

  4. QT使用openGL绘制一个三角形

    对于opengl的学习来说,绘制一个三角形是学习一种计算机语言时的一个hello world级的入门程序,个人觉得相比主流语言的helloworld,openGL的入门确实是有一些劝退,虽然说有不错的 ...

  5. OpenGL绘制一个四边形

    学习自:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/ OpenGL没有直接绘制四边形的a ...

  6. opengl es3.0学习篇七:使用opengl绘制一个立方体

    2019独角兽企业重金招聘Python工程师标准>>> 这里简单运用之前所学的知识来实现一个对应的立方体: public class MainActivity extends App ...

  7. OpenGL绘制一个圆锥

    绘制圆锥暂时没有找到一个模型完整绘制,暂时使用两个物体拼接: 圆和锥面. 缺点:这需要绘制两次才能将圆锥体绘制成功. #include "cone.h" #include < ...

  8. WIN32 opengl绘制一个点

    在Win32程序中,使用到gluPerspective,而这个函数需要glut.h.故需要配置相关环境. #include "stdafx.h" #include "Wi ...

  9. OpenGl 绘制一个立方体

    https://www.cnblogs.com/icmzn/p/5049768.html https://blog.csdn.net/auccy/article/details/82392921

  10. OpenGL绘制桥梁模型

    本文主要讲述如何使用现代OpenGL绘制一个完整的桥梁模型,包括箱梁.盖梁和桥墩,关于OpenGL方面,主要添加的shader,使用phong光照模型实现. 一.绘制箱梁 1.1 箱梁的的截面和坐标系 ...

最新文章

  1. 二叉树的中序遍历(递归和非递归版本)
  2. 下拉菜单实现树状结构_二叉索引树(树状数组)的原理
  3. tcp 组播_华为组播理论知识详解(二)
  4. freebsd nginx php mysql_FreeBSD 安装配置Nginx+PHP+APC+MySQL
  5. SP2010开发和VS2010专家食谱--第四章节—列表定义和内容类型(7)--创建列表定义...
  6. Python:if语句
  7. 03-21 webview 性能分析
  8. 浙江大学_包家立计算生物学_神经网络
  9. 小米球Ngrok内网穿透教程
  10. 路由器下一跳地址怎么判断_三分钟了解路由器路由表
  11. K8S-四层负载均衡-Service解读
  12. Vue脚手架安装与使用
  13. 文件搜索工具ProFind for Mac
  14. 上海商报:超级表格创始人叫板Excel
  15. 动态规划(Dynamic Programming)与贪心算法(Greedy Algorithm)
  16. 预言机 - 区块链的触角
  17. OGL纹理之纹理过滤器和多级渐进纹理mipmap
  18. vscode 修改缩进格数
  19. 抖音全球购安心购服务规范|四川鹰迪
  20. win8发布,哪家ARM厂商能提前支持win8 RT版本的?

热门文章

  1. 英语六级写作必备短语词汇1
  2. 编程随想(编程学什么语言好)
  3. jupyter notebook打不开,Unable to create process using ‘“e:\python\python.exe“ “G:\python\Scripts\jupyt
  4. 零基础转行IT学习什么好?
  5. grid_map(五):grid_map函数定义、类型定义学习
  6. DOSBox debug中查看标志位
  7. QTableWidget点击空白处取消选中
  8. 使用Ajax实现百度下拉框
  9. 关于新冠疫情,常用的英文单词、语句有哪些?
  10. php画梯形,利用css来画出各种样式不同的梯形,html中梯形外框怎么做