【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形

以前都是用Cg的,现在改用GLSL,又要重新学,不过两种语言很多都是相通的。


下面的例子是实现绘制一个三角形的简单程序。采用了VBO(veretx buffer object)、VAO(vertex array object)等OpenGL的一些新特性。越往后发展,可编程管线肯定是大势所趋,OpenGL里原来的一些固定管线的内容肯定会被废弃掉。所以从现在开始写程序就要养成使用新特性、采用可编程管线技术的好习惯。


一、VAO、VBO介绍

随着OpenGL状态和固定管线模式的移除,我们不在用任何glEnable函数调用,而且也不会有glVertex、glColor等函数调用。这就意味着我们需要一种新的方式来将数据传输到图形卡以渲染图形。我们可以采用VBO,或者是在OpenGL3以上版本引入的新的特性,叫做VAO。通过它,我们可以把顶点数据和颜色存储在不同的VBO中,但是在同一个VAO中。对于法线数据或者其他的顶点信息也是一样。

VAO,是这样一种方式:把对象信息直接存储在图形卡中,而不是在当我们需要的时候传输到图形卡。这就是Direct3D所采用得方式,而在OpenGL中只有OpenGL3.X以上的版本中采用。这就意味着我们的应用程序不用将数据传输到图形卡或者是从图形卡输出,这样也就获得了额外的性能提升。

使用VAO并不难。我们不需要大量的glVertex调用,而是把顶点数据存储在数组中,然后放进VBO,最后在VAO中存储相关的状态。记住:VAO中并没有存储顶点的相关属性数据。OpenGL会在后台为我们完成其他的功能。

 

使用VAO的步骤:

1、产生VAO

void glGenVertexArrays(GLsizei n,
  GLuint *arrays);

n:要产生的VAO对象的数量。

arrays:存放产生的VAO对象的名称。

2、绑定VAO

void glBindVertexArray(GLuint array);

array:要绑定的顶点数组的名字。

3、产生VBOs

void glGenBuffers(GLsizei  n,
  GLuint *   buffers);

产生缓冲区对象的名称。

参数含义和glGenVertexArrays类似。

4、绑定VBOs

void glBindBuffer(GLenum  target,
  GLuint   buffer);

绑定一个缓冲区对象。

target可能取值是:GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, or GL_PIXEL_UNPACK_BUFFER.

当进行绑定之后,以前的绑定就失效了。

5、给VBO分配数据:

void glBufferData(   GLenum          target,

        GLsizeiptr      size,

        const GLvoid *        data,

        GLenum          usage);

target可能取值为:GL_ARRAY_BUFFER(表示顶点数据), GL_ELEMENT_ARRAY_BUFFER(表示索引数据),GL_PIXEL_PACK_BUFFER(表示从OpenGL获取的的像素数据), or GL_PIXEL_UNPACK_BUFFER(表示传递给OpenGL的像素数据).

参数含义:

size:缓冲区对象字节数

data:指针:指向用于拷贝到缓冲区对象的数据。或者是NULL,表示暂时不分配数据。

6、定义存放顶点属性数据的数组:

首先需要启用VAO中对应的顶点属性数组:

void glEnableVertexAttribArray(      GLuint    index);

index:指定了需要启用的顶点属性数组的索引

注意:它只在OpenGL2.0及其以上版本才有。

7、给对应的顶点属性数组指定数据:

void glVertexAttribPointer(      GLuint    index,

        GLint      size,

        GLenum          type,

        GLboolean     normalized,

        GLsizei  stride,

        const GLvoid *        pointer);

index:要指定数据的顶点属性数组的索引。

size:每个顶点属性的数据个数。可能的取值是1、2、3或者4.初始值是4.

type:数组中每个数据的类型。可能的取值是:GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, or GL_DOUBLE。初始值是GL_FLOAT。

normalized:指定顶点数在被访问的时候是否需要被归一化。

注意:如果有个非零的缓冲对象绑定到GL_ARRAY_BUFFER,那么pointer就是对应的缓冲区对象的偏移量。

 stride:两个连续顶点的属性之间的偏移量。

pointer:指向数组中的第一个顶点属性的第一个数据。

8、然后在进行渲染的时候,只需要绑定对应的VAO即可,操作起来十分方便。

glBindVertexArray(vaoHandle);

9、使用完毕之后需要清除绑定。

glBindVertexArray(0);


VAO参考资料:

VAO wiki

关于VAO的一篇博客

VAO

事实上,在这个简单的程序中,不用VAO,只用VBO也一样可以实现。只是采用VAO可以进一步提升性能,而且在较新版本的OpenGL中不用VAO的方式会被逐渐废弃。


二、GLSL入门

关于GLSL,可以参考红宝书的附录,上面介绍了GLSL的入门知识。

这里也有一个很好的入门教程,英文的:

GLSL入门tutorial



三、程序实例

下面贴出源代码(OpenGL,GLSL实现):

basic.vert:

  1. //强制要求支持一个特定版本的GLSL版本
  2. #version 400
  3. in vec3 VertexPosition;
  4. in vec3 VertexColor;
  5. out vec3 Color;
  6. void main()
  7. {
  8. Color =VertexColor;
  9. gl_Position = vec4(VertexPosition,1.0);
  10. }

basic.frag:

  1. #version 400
  2. in vec3 Color;
  3. out vec4 FragColor;
  4. void main()
  5. {
  6. FragColor = vec4(Color,1.0);
  7. }
主文件:

main.cpp:

  1. #pragma comment(lib,"glew32.lib")
  2. #include <GL/glew.h>
  3. #include "textfile.h"
  4. #include <GL/glut.h>
  5. #include <iostream>
  6. using namespace std;
  7. GLuint vShader,fShader;//顶点着色器对象
  8. //顶点位置数组
  9. float positionData[] = {
  10. -0.8f, -0.8f, 0.0f,
  11. 0.8f, -0.8f, 0.0f,
  12. 0.0f, 0.8f, 0.0f };
  13. //颜色数组
  14. float colorData[] = {
  15. 1.0f, 0.0f, 0.0f,
  16. 0.0f, 1.0f, 0.0f,
  17. 0.0f, 0.0f, 1.0f };
  18. GLuint vaoHandle;//vertex array object
  19. void initShader(const char *VShaderFile,const char *FShaderFile)
  20. {
  21. //1、查看GLSL和OpenGL的版本
  22. const GLubyte *renderer = glGetString( GL_RENDERER );
  23. const GLubyte *vendor = glGetString( GL_VENDOR );
  24. const GLubyte *version = glGetString( GL_VERSION );
  25. const GLubyte *glslVersion =
  26. glGetString( GL_SHADING_LANGUAGE_VERSION );
  27. GLint major, minor;
  28. glGetIntegerv(GL_MAJOR_VERSION, &major);
  29. glGetIntegerv(GL_MINOR_VERSION, &minor);
  30. cout << "GL Vendor :" << vendor << endl;
  31. cout << "GL Renderer : " << renderer << endl;
  32. cout << "GL Version (string) : " << version << endl;
  33. cout << "GL Version (integer) : " << major << "." << minor << endl;
  34. cout << "GLSL Version : " << glslVersion << endl;
  35. //2、编译着色器
  36. //创建着色器对象:顶点着色器
  37. vShader = glCreateShader(GL_VERTEX_SHADER);
  38. //错误检测
  39. if (0 == vShader)
  40. {
  41. cerr << "ERROR : Create vertex shader failed" << endl;
  42. exit(1);
  43. }
  44. //把着色器源代码和着色器对象相关联
  45. const GLchar *vShaderCode = textFileRead(VShaderFile);
  46. const GLchar *vCodeArray[1] = {vShaderCode};
  47. glShaderSource(vShader,1,vCodeArray,NULL);
  48. //编译着色器对象
  49. glCompileShader(vShader);
  50. //检查编译是否成功
  51. GLint compileResult;
  52. glGetShaderiv(vShader,GL_COMPILE_STATUS,&compileResult);
  53. if (GL_FALSE == compileResult)
  54. {
  55. GLint logLen;
  56. //得到编译日志长度
  57. glGetShaderiv(vShader,GL_INFO_LOG_LENGTH,&logLen);
  58. if (logLen > 0)
  59. {
  60. char *log = (char *)malloc(logLen);
  61. GLsizei written;
  62. //得到日志信息并输出
  63. glGetShaderInfoLog(vShader,logLen,&written,log);
  64. cerr << "vertex shader compile log : " << endl;
  65. cerr << log << endl;
  66. free(log);//释放空间
  67. }
  68. }
  69. //创建着色器对象:片断着色器
  70. fShader = glCreateShader(GL_FRAGMENT_SHADER);
  71. //错误检测
  72. if (0 == fShader)
  73. {
  74. cerr << "ERROR : Create fragment shader failed" << endl;
  75. exit(1);
  76. }
  77. //把着色器源代码和着色器对象相关联
  78. const GLchar *fShaderCode = textFileRead(FShaderFile);
  79. const GLchar *fCodeArray[1] = {fShaderCode};
  80. glShaderSource(fShader,1,fCodeArray,NULL);
  81. //编译着色器对象
  82. glCompileShader(fShader);
  83. //检查编译是否成功
  84. glGetShaderiv(fShader,GL_COMPILE_STATUS,&compileResult);
  85. if (GL_FALSE == compileResult)
  86. {
  87. GLint logLen;
  88. //得到编译日志长度
  89. glGetShaderiv(fShader,GL_INFO_LOG_LENGTH,&logLen);
  90. if (logLen > 0)
  91. {
  92. char *log = (char *)malloc(logLen);
  93. GLsizei written;
  94. //得到日志信息并输出
  95. glGetShaderInfoLog(fShader,logLen,&written,log);
  96. cerr << "fragment shader compile log : " << endl;
  97. cerr << log << endl;
  98. free(log);//释放空间
  99. }
  100. }
  101. //3、链接着色器对象
  102. //创建着色器程序
  103. GLuint programHandle = glCreateProgram();
  104. if (!programHandle)
  105. {
  106. cerr << "ERROR : create program failed" << endl;
  107. exit(1);
  108. }
  109. //将着色器程序链接到所创建的程序中
  110. glAttachShader(programHandle,vShader);
  111. glAttachShader(programHandle,fShader);
  112. //将这些对象链接成一个可执行程序
  113. glLinkProgram(programHandle);
  114. //查询链接的结果
  115. GLint linkStatus;
  116. glGetProgramiv(programHandle,GL_LINK_STATUS,&linkStatus);
  117. if (GL_FALSE == linkStatus)
  118. {
  119. cerr << "ERROR : link shader program failed" << endl;
  120. GLint logLen;
  121. glGetProgramiv(programHandle,GL_INFO_LOG_LENGTH,
  122. &logLen);
  123. if (logLen > 0)
  124. {
  125. char *log = (char *)malloc(logLen);
  126. GLsizei written;
  127. glGetProgramInfoLog(programHandle,logLen,
  128. &written,log);
  129. cerr << "Program log : " << endl;
  130. cerr << log << endl;
  131. }
  132. }
  133. else//链接成功,在OpenGL管线中使用渲染程序
  134. {
  135. glUseProgram(programHandle);
  136. }
  137. }
  138. void initVBO()
  139. {
  140. // Create and populate the buffer objects
  141. GLuint vboHandles[2];
  142. glGenBuffers(2, vboHandles);
  143. GLuint positionBufferHandle = vboHandles[0];
  144. GLuint colorBufferHandle = vboHandles[1];
  145. //绑定VBO以供使用
  146. glBindBuffer(GL_ARRAY_BUFFER,positionBufferHandle);
  147. //加载数据到VBO
  148. glBufferData(GL_ARRAY_BUFFER,9 * sizeof(float),
  149. positionData,GL_STATIC_DRAW);
  150. //绑定VBO以供使用
  151. glBindBuffer(GL_ARRAY_BUFFER,colorBufferHandle);
  152. //加载数据到VBO
  153. glBufferData(GL_ARRAY_BUFFER,9 * sizeof(float),
  154. colorData,GL_STATIC_DRAW);
  155. glGenVertexArrays(1,&vaoHandle);
  156. glBindVertexArray(vaoHandle);
  157. glEnableVertexAttribArray(0);//顶点坐标
  158. glEnableVertexAttribArray(1);//顶点颜色
  159. //调用glVertexAttribPointer之前需要进行绑定操作
  160. glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
  161. glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL );
  162. glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
  163. glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL );
  164. }
  165. void init()
  166. {
  167. //初始化glew扩展库
  168. GLenum err = glewInit();
  169. if( GLEW_OK != err )
  170. {
  171. cout <<"Error initializing GLEW: " << glewGetErrorString(err) << endl;
  172. }
  173. initShader("basic.vert","basic.frag");
  174. initVBO();
  175. glClearColor(0.0,0.0,0.0,0.0);
  176. //glShadeModel(GL_SMOOTH);
  177. }
  178. void display()
  179. {
  180. glClear(GL_COLOR_BUFFER_BIT);
  181. 绘制一个三角形(使用普通方法)
  182. //glBegin(GL_TRIANGLES);
  183. //glColor3f(0.0f,1.0f,0.0f);
  184. //glVertex3f(0.0f,1.0f,0.0f);
  185. //glColor3f(0.0f,1.0f,0.0f);
  186. //glVertex3f(-1.0f,-1.0f,0.0f);
  187. //glColor3f(0.0f,0.0f,1.0f);
  188. //glVertex3f(1.0f,-1.0f,0.0f);
  189. //glEnd();
  190. //使用VAO、VBO绘制
  191. glBindVertexArray(vaoHandle);
  192. glDrawArrays(GL_TRIANGLES,0,3);
  193. glBindVertexArray(0);
  194. glutSwapBuffers();
  195. }
  196. void keyboard(unsigned char key,int x,int y)
  197. {
  198. switch(key)
  199. {
  200. case 27:
  201. glDeleteShader(vShader);
  202. glUseProgram(0);
  203. break;
  204. }
  205. }
  206. int main(int argc,char** argv)
  207. {
  208. glutInit(&argc,argv);
  209. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  210. glutInitWindowSize(600,600);
  211. glutInitWindowPosition(100,100);
  212. glutCreateWindow("GLSL Test : Draw a triangle");
  213. init();
  214. glutDisplayFunc(display);
  215. glutKeyboardFunc(keyboard);
  216. glutMainLoop();
  217. return 0;
  218. }

读取shader文件的程序:

textfile.h:

  1. // textfile.h: interface for reading and writing text files
  2. #ifndef TEXTFILE_H
  3. #define TEXTFILE_H
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. char *textFileRead(const char *fn);
  8. int textFileWrite(char *fn, char *s);
  9. unsigned char *readDataFromFile(char *fn);
  10. #endif
textfile.cpp:
  1. // textfile.cpp
  2. // simple reading and writing for text files
  3. #include "textfile.h"
  4. unsigned char * readDataFromFile(char *fn)
  5. {
  6. FILE *fp;
  7. unsigned char *content = NULL;
  8. int count=0;
  9. if (fn != NULL) {
  10. fp = fopen(fn,"rb");
  11. if (fp != NULL) {
  12. fseek(fp, 0, SEEK_END);
  13. count = ftell(fp);
  14. rewind(fp);
  15. if (count > 0) {
  16. content = (unsigned char *)malloc(sizeof(unsigned char) * (count+1));
  17. count = fread(content,sizeof(unsigned char),count,fp);
  18. content[count] = '\0';
  19. }
  20. fclose(fp);
  21. }
  22. }
  23. return content;
  24. }
  25. char *textFileRead(const char *fn) {
  26. FILE *fp;
  27. char *content = NULL;
  28. int count=0;
  29. if (fn != NULL) {
  30. fp = fopen(fn,"rt");
  31. if (fp != NULL) {
  32. fseek(fp, 0, SEEK_END);
  33. count = ftell(fp);
  34. rewind(fp);
  35. if (count > 0) {
  36. content = (char *)malloc(sizeof(char) * (count+1));
  37. count = fread(content,sizeof(char),count,fp);
  38. content[count] = '\0';
  39. }
  40. fclose(fp);
  41. }
  42. }
  43. return content;
  44. }
  45. int textFileWrite(char *fn, char *s) {
  46. FILE *fp;
  47. int status = 0;
  48. if (fn != NULL) {
  49. fp = fopen(fn,"w");
  50. if (fp != NULL) {
  51. if (fwrite(s,sizeof(char),strlen(s),fp) == strlen(s))
  52. status = 1;
  53. fclose(fp);
  54. }
  55. }
  56. return(status);
  57. }
运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432333.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

catia linux下载64位,CATIA V5 CATSysDemon.exe缓冲区溢出漏洞

发布日期&#xff1a;2014-02-24更新日期&#xff1a;2014-02-25受影响系统&#xff1a;3ds catia-v5描述&#xff1a;--------------------------------------------------------------------------------CATIA是数字产品定义及生命周期管理使用的CAD、CAE、CAM应用集成软件包…

【Modern OpenGL】Shader

Shaders 正如在上一篇教程中提到的&#xff0c;shader是在GPU中运行的小程序。如上一个教程中实现的最简单的vertex shader和fragment shader&#xff0c;一个shader基本上负责图形渲染流水线中的一个阶段的功能。从根本上来说&#xff0c;shader就是将输入转化成输出的操作。而…

c语言编译的手机软件,C语言编译工具

软件介绍C语言编译工具app是一款功能十分强大的手机编译、更换代码的软件工具&#xff0c;C语言编译工具app可以快速进行代码翻译、代码查找、替换等&#xff0c;它支持多种代码语言&#xff0c;欢迎下载&#xff01;C语言编译工具app内容简单方便功能强大的代码编译器&#xf…

【Modern OpenGL】纹理 Textures

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址&#xff1a; http://blog.csdn.net/aganlengzi/article/details/50421006 纹理 Textures 为了使我们创建的…

HDU 2296 Ring AC自动机 + DP

题意&#xff1a;给你n个模式串&#xff0c;每个模式串有一个得分&#xff0c;让你构造出一个长度为N之内且分数最高的文本串;输出字典序列最小的。 解题思路&#xff1a; AC自动机 DP &#xff0c; 不过要输出字典序列最小&#xff0c;多开一个 一个三维字符串来辅助二维DP&…

【Modern OpenGL】转换 Transformations

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址&#xff1a; http://blog.csdn.net/aganlengzi/article/details/50421159 转换 Transformations 我们已经…

android studio adb 命令行,Android Studio如何配置adb以及经常使用命令

用Android Studio一年多了&#xff0c;都没有使用其调试adb,今天就分享adb配置的方法&#xff0c;分享给你们.android直接打开电脑-属性-高级配置-环境变量。web这里我用图示范给你们&#xff1a;sql这样经常使用adb就配置成功。shell紧接着还有平时经常使用的adb命令&#xff…

【Modern OpenGL】坐标系统 Coordinate Systems

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址&#xff1a; http://blog.csdn.net/aganlengzi/article/details/50448453 坐标系统 Coordinate Systems 在…

【Modern OpenGL】摄像机系统 Camera

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址&#xff1a;http://blog.csdn.net/aganlengzi/article/details/50448469 摄像机 Camera 在前面的教程中…

UE MATH

1. 求两点的单位向量

材质

1. 随摄像机变化的镜面放射效果 2. 给物体表面增加抛光度 3. 菲涅耳透镜效果

html keyup事件,jquery keyup事件为什么不执行?

先指出你的一个错误点$(#skillKey).on(click, tr, function () {$(this).css(color,red);$(this).keyup(function(){alert(123)});});你这样绑定事件&#xff0c;结果是点击一次tr绑定一次&#xff0c;点了多少次就绑定了多少次&#xff0c;这个例子还是不明显&#xff0c;你在…

cable

1. 建立一个actor&#xff0c;添加一个cable, 然后添加两个mesh作为cable的两个端点 2. 在编辑器中只能设置cable终点attach的mesh和mesh的socket, 因此需要在actor的构成函数里手动的设置 cable起点attach的mesh和socket

Android-将切换tabs的指示器合并到ActionBar上

最近比较忙&#xff0c;好久没更新过博客。国庆第一天没回家&#xff0c;闲下来可以把之前就想贴上来的东西写一下。 使用过Smooth和Fuubo这两个优秀的第三方微博客户端的同学应该见过他们的主页UI&#xff0c;如下图&#xff1a; 他们把切换tabs的指示器放在了ActionBar上&…

html5教学文档笔记,4.HTML 教程- (HTML5 基础)

HTML 教程- (HTML5 基础)1.HTML 标题HTML 标题(Heading)是通过- 标签来定义的.2.HTML 段落HTML 段落是通过标签 来定义的.3.HTML 链接HTML 链接是通过标签 来定义的.提示:在 href 属性中指定链接的地址。菜鸟教程(runoob.com)这是一个链接使用了 href 属性这是一个链接使用了 …

虚幻4渲染系统结构解析

本文根据小米互娱 VR 技术专家 房燕良在 MDCC 2016 移动开发者大会上的演讲整理而成&#xff0c;PPT 下载地址&#xff1a;http://download.csdn.net/detail/sinat_14921509/9639244。 小米互娱 VR 技术专家 房燕良 房燕良&#xff0c;从 2001 年开始&#xff0c;自主研发 3 代…

Windows FFMPEG开发环境配置

1.去FFMPEG网站上下载Dev版本的库&#xff0c;里面有我们需要的头文件和lib文件&#xff0c;然后下载Shared版本的库&#xff0c;里面有我们需要的dll文件 http://ffmpeg.zeranoe.com/builds/ 记得区分32位和64位的库&#xff0c;这里碰到一个大坑&#xff0c;就是我下载的是6…

Ant命令行操作

Ant命令行操作 Ant构建文件可以将项目编译&#xff0c;打包&#xff0c;測试&#xff0c;它是Apache软件基金会jakarta文件夹中的一个子项目&#xff0c;具有跨平台性&#xff0c;操作简单&#xff0c;并且非常easy上手。 关于Ant执行&#xff0c;能够在项目中找到build.xml直接…