OpenGL中的Shader
http://blog.csdn.net/huangcanjun187/article/details/52474365
学习总结自:http://learnopengl.com/#!Getting-started/Hello-Triangle
http://learnopengl.com/#!Getting-started/Shaders
继上篇文章中提到,OpenGL是为了在GPU上同时跑成千上万个程序,在GPU上跑的这些小程序,称为Shader。
准备
我们在运行GPU程序前,得准备几样东西:1)输入数据。2)数据缓冲区。3)Shader程序。4)GLSL(OpenGL Shade Language)主程序。
以画一个三角形为例,
1)输入数据包括:a. 三点顶点的坐标。b. 三个顶点的颜色。
GLfloat vertices[] = {
// 坐标 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下角
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶点
};
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
2)数据缓存区包括:a. 数据怎么识别。哪一块是坐标数据?哪一块是颜色数据? b. 哪一块数据是第一个三角形的数据?哪一块数据是第二个三角形的数据?
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);// 首先绑定VAO结构。一个VAO对应一个形状对象,包含了一个形状的所有属性,包括颜色、坐标等等。用shader程序调用VAO这个结构,可以画出对应的图像来。
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//在绑定VAO之后,绑定VBO结构。**这样VBO就属于之前被绑定VAO的一部分。**里面包含了预先定义好的数组vertices,vertices就是一个浮点数组,包含具体的坐标、颜色值。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);// 坐标属性。让Vertex Shader将这部分数据作为坐标导入。
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);// 颜色属性。让Vertex Shader将这部分数据作为坐标颜色值导入。
glBindVertexArray(0); // Unbind VAO
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
3)Shader 程序。将导入GPU的数据,为对应的坐标点画上对应的颜色。
// Shaders
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"//location = 0,与之前绑定VAO步骤中的函数glEnableVertexAttribArray(0)对应,把坐标数据导入到 vec3 position 这个shader中的坐标变量。
"layout (location = 1) in vec3 color;\n"//location = 1,与之前绑定VAO步骤中的函数glEnableVertexAttribArray(1)对应,把坐标数据导入到 vec3 color这个shader中的颜色变量。
"out vec3 ourColor;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position, 1.0);\n"
"ourColor = color;\n"//将颜色值直接赋值给输出的变量ourColor,在Fragment Shader中也有一个同名的变量,所有最终像素的颜色就是此颜色值。
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"in vec3 ourColor;\n" //OpenGL Shader程序会直接将同名的变量联系到一起,这个ourColor就是vertex shader中的输出的ourColor
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(ourColor, 1.0f);\n"
"}\n\0";
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
4)GLSL 主程序
GLuint shaderProgram = glCreateProgram(); //创建一个GLSL主程序
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);//将两个shader挂载到主程序上
glLinkProgram(shaderProgram);//链接shader程序。编译shader的步骤在此之前。接下来会详细介绍
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
步骤
为何要将1)输入数据。2)数据缓冲区。3)Shader程序。4)GLSL(OpenGL Shade Language)主程序。这个几个模块分开介绍呢?
因为这几块相互独立,这是OpenGL比较明显的特点。详细说,就是GLSL主程序可以链接任意一个编译好的shader程序,编译好的shader程序可以装载不同的VAO(Vertext Array Object,它是VBO的老大,Shader 调用的时候是直接调VAO,VBO包含了数据,VAO包含了VBO以及如何让Shader识别这些VBO数据的一些属性),VAO又可以用不同的方式装载不同的数据。
以这段代码为例,只粘贴了比较关键的代码,完整源码请参考:
http://learnopengl.com/code_viewer.php?code=getting-started/shaders-interpolated
程序的结果就是对三角形的三个顶点画上红、绿、蓝三种颜色,三角形中间区域的颜色OpenGL会自动插值出来,这是OpenGL的神奇之处(我也还没懂原理)。
//--------------这不是完整源码,着重介绍重要的几个步骤------------------//
//---------编写shader 程序----------//
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 color;\n"
"out vec3 ourColor;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position, 1.0);\n"
"ourColor = color;\n"
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"in vec3 ourColor;\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(ourColor, 1.0f);\n"
"}\n\0";//简单易懂的Shader源码
//---------编译和链接shader程序----------//
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader); //因为shader程序是在GPU上跑,所以不是和CPP文件一起编译。Shader程序如果有BUG,在编译CPP的时候不会出错,而是在运行CPP工程的时候报错。
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram); //将shader程序与GLSL主程序链接到一起
//---------编写VAO,VBO以及具体导入的数据----------//
GLfloat vertices[] = {
// Positions // Colors
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // Bottom Left
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // Top
};//三个顶点的坐标和颜色值
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);//可以生成多个VAO和多个VBO。一个只能对应一个VBO。画多个图形,就得用不同的VAO包含不同的VBO
glBindVertexArray(VAO);//绑定VAO之后,接下来的所有操作都被记录到此VAO当中,直到这个VAO被解除绑定为止。VAO就是画一个图形所需要的所有属性。绑定完这个VAO之后,可以接着绑定其它的VAO。
glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定VBO到当前VAO中,注意GL_ARRAY_BUFFER这个类型只能绑定一个VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//绑定数据到VBO对象当中
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);//坐标位置在vertices数组中起始点为0,步长为6个FLOAT数据的长度
glEnableVertexAttribArray(0);//用vertex shader中的Location0来导入数据,Location0就是坐标数据
// Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));//坐标位置在vertices数组中起始点为3,步长为6个FLOAT数据的长度
glEnableVertexAttribArray(1);//用vertex shader中的Location1来导入数据,Location0就是颜色标数据
glBindVertexArray(0); // 解除绑定VAO,对这个VAO的所有操作到此为止,之前的操作被全部保存
// 循环画图
while (!glfwWindowShouldClose(window))
{
// 检测是否有键盘触发事件
glfwPollEvents();
// Render
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置背景颜色
glClear(GL_COLOR_BUFFER_BIT);
// Draw the triangle
glUseProgram(shaderProgram);//导入一个GLSL主程序
glBindVertexArray(VAO);//导入其中一个VAO,一个主程序可以链接多个VAO,在画完这个VAO之后,可以接着画另外一个VAO代表的图形。这是OpenGL比较明显的特征
glDrawArrays(GL_TRIANGLES, 0, 3);//画三角形
glBindVertexArray(0); //glBindVertexArray()将VAO属性复位,也就是不绑定任意一个VAO
// Swap the screen buffers
glfwSwapBuffers(window);
}
OpenGL中的Shader的更多相关文章
- GLSL 在OpenGL中向shader传递信息【转】
http://blog.csdn.net/hgl868/article/details/7872219 引言 一个OpenGL程序可以用多种方式和shader通信.注意这种通信是单向的,因为shade ...
- 【GLSL教程】(三)在OpenGL中向shader传递信息 【转】
http://blog.csdn.net/racehorse/article/details/6634830 引言 一个OpenGL程序可以用多种方式和shader通信.注意这种通信是单向的,因为sh ...
- [Modern OpenGL系列(四)]在OpenGL中使用Shader
本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51347440 在上一篇文章中已经介绍了OpenGL窗口的创建.本文接着说如 ...
- 通过cocos2d-x的CCGLProgram和CCShaderCache的实现来分析OpenGL ES中的Shader编程
在OpenGL ES中,Shader是着色器,包括两种:顶点着色器(Vertex Shader)和片元着色器(Fragment Shader).每个program对象有且仅有一个Vertex Shad ...
- OpenGL中shader读取实现
1.需要shader在OpenGL中工作,必须经过如下过程 2.代码实现 /********** * loadshader.h **********/ #pragma once #define _CR ...
- CSharpGL(6)在OpenGL中绘制UI元素
CSharpGL(6)在OpenGL中绘制UI元素 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo,更适合入 ...
- OpenGL中glVertex、显示列表(glCallList)、顶点数组(Vertex array)、VBO及VAO区别
OpenGL中glVertex.显示列表(glCallList).顶点数组(Vertex array).VBO及VAO区别 1.glVertex 最原始的设置顶点方法,在glBegin和glEnd之间 ...
- OpenGL中的数据——Buffer
OpenGL中主要包括了两种数据——Buffer和Texture. Buffer用于储存线性数无类型据块,可以看成普通的内存块,而Texture则用于储存多维数据,一般储存图像或者其他数据. Buff ...
- 【GLSL教程】(二)在OpenGL中使用GLSL 【转】
http://blog.csdn.net/racehorse/article/details/6616256 设置GLSL 这一节讲述在OpenGL中配置GLSL,假设你已经写好了顶点shader和像 ...
随机推荐
- gcc/g++实战之动态链接库与静态链接库编写
函数库一般分为静态库和动态库两种. 静态库: 是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了.其后缀名一般为”.a”. 动态库: 与之相反, ...
- linux用户与组管理命令的基本操作
用户账号管理命令 为了提高系统的利用率,避免因多个用户共用一个root账号而造成不必要要的系统安全隐患,通常需要为 新用户添加账户.在Linux系统中,添加用户只能由超级用户来完成,也就是说,只能由r ...
- cocos2d 粒子效果以及Particle Designer粒子工具的学习
最近在学习cocos2d中的粒子效果吧,下面就把学到的和大家分享下吧! Now!我们先了解下类结构吧 -- CCParticleSystem(所有粒子系统的父类) -- CCParticleSyste ...
- vijos P1740 聪明的质检员
题目链接:传送门 题目大意:给你n个物品,每件物品有重量 W 和价值 V,给m个区间,和一个标准值.(n,m最大200000) 要求找到一个值x,使得m个所有区间的权值和与标准值的差的绝对值最小.单个 ...
- spring boot rabbitmq 多MQ配置 自动 创建 队列 RPC
源码地址:https://github.com/hutuchong518/RabbitmqStudy 需求: spring boot 整合 rabbitmq rpc功能, 需要将 请求和响应 ...
- css 横线中间添加文字
demoline01.02选一个用足够了 <style> .demo_line_01 { width: 200px;/*这指的是文字的宽度*/ padding: 0 20px 0; m ...
- Less-@import 导入选项
//@import 导入选项 --@import 可以至于任何你需要导入的地方 在标准的CSS,@import在规则必须先于所有其他类型的规则.但Less.js不关心 example: .test() ...
- Html5-Canvas 与 SVG 的比较
Canvas 与 SVG 的比较 Canvas 依赖分辨率 不支持事件处理器 弱的文本渲染能力 能够以 .png 或 .jpg 格式保存结果图像 最适合图像密集型的游戏,其中的许多对象会被频繁重绘 S ...
- POJ 3037 Skiing(Dijkstra)
Skiing Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4668 Accepted: 1242 Special ...
- Android 短信箱操作
package blackice.android.product; import java.sql.Date; import java.text.SimpleDateFormat; import ja ...