#define GLEW_STATIC
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include<iostream>
using namespace std; //函数原型
void key_callback(GLFWwindow* window, int key, int scancode,
int action, int mode); //窗口大小
const GLuint WIDTH = , HEIGHT = ; const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x,position.y,position.z,1.0);\n"
"}\0"; const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f,0.5f,0.2f,1.0f);\n"
"}\n\0"; int main(){
//初始化 GLFW
glfwInit(); //设置GLFW需要的选项
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); //创建一个窗口对象
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "test2", nullptr, nullptr);
glfwMakeContextCurrent(window); //设置徐亚的回调函数
glfwSetKeyCallback(window, key_callback); glewExperimental = GL_TRUE; glewInit(); int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(, , width, height); //定点着色器
GLuint vertextShader;
vertextShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertextShader, , &vertexShaderSource, NULL);
glCompileShader(vertextShader); //用于判断一个着色器是否编译成功
GLint success;
GLchar infoLog[];
glGetShaderiv(vertextShader, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(vertextShader, , NULL, infoLog);
cout << "vertextShader COMPILE FAILED" << endl;
} //像素着色器
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, , &fragmentShaderSource, NULL);
glCompileShader(fragmentShader); //用于判断一个着色器是否编译成功
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(fragmentShader, , NULL, infoLog);
cout << "fragmentShader COMPILE FAILED" << endl;
} //创建一个着色器程序对象:多个着色器最后链接的版本
GLuint shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertextShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success){
glGetProgramInfoLog(shaderProgram, , NULL, infoLog);
}
glDeleteShader(vertextShader);
glDeleteShader(fragmentShader); //创建定点数据
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
//创建 VBO 顶点缓冲数据,并把数据赋值到内存中
GLuint VBO;
glGenBuffers(, &VBO);
//VAO顶点数组对象
GLuint VAO;
glGenVertexArrays(, &VAO); //绑定VAO
glBindVertexArray(VAO); //复制顶点数据到缓冲中提供给OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //设置顶点属性指针
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(GLfloat), (GLvoid *));
glEnableVertexAttribArray(); //解绑VBO
glBindBuffer(GL_ARRAY_BUFFER, ); //解绑VAO
glBindVertexArray(); while (!glfwWindowShouldClose(window)){
glfwPollEvents(); //释放颜色缓存
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); //绘制物体
//当打算渲染一个物体使用使用着色器程序
glUseProgram(shaderProgram);
glBindVertexArray(VAO); //绘制函数
glDrawArrays(GL_TRIANGLES, , );
glBindVertexArray(); glfwSwapBuffers(window);
} glDeleteVertexArrays(, &VAO);
glDeleteBuffers(, &VBO); glfwTerminate();
return ;
}
void key_callback(GLFWwindow* window, int key, int scancode,
int action, int mode){
if (key == GLFW_KEY_L && action == GLFW_PRESS){
glfwSetWindowShouldClose(window, GL_TRUE);
}
}

首先,在发该贴的时候,这个程序依旧没有跑起来,因为GLFW、GLEW等库的原因,鉴于GLUT是上个时代的产物,所以学到后面看到的一些案例都是用的GLEW、GLFW、GLAD等库,一时半会儿没有配置成功,但是,这并不能影响我们根据其中的代码来理解着色器程序(shader)。

下面,我们主要来看一下其中的着色器代码部分:

一、两个着色器程序

const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x,position.y,position.z,1.0);\n"
"}\0"; const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f,0.5f,0.2f,1.0f);\n"
"}\n\0";

首先第一个是顶点着色器(vertexShader):

顶点着色器用于读取顶点(坐标)数据,所以这个position参数是从外部数据源读取的,在main方法中将外部读取的顶点数据转化为四维坐标(x,y,z,w),并且赋值给全局变量:gl_Position。

第二个是片元着色器(fragmentShader):

这里注意了,片元着色器隐式地对所有的gl_Position中的坐标点进行着色并且将颜色输出。所以这个color参数是输出的,可能你也看到了,输出的颜色是个vec4,分别代表RGBA,最后一个1.0f表示alpha通道值为1.0f(浮点型)

二、着色器程序的编译

//定点着色器
GLuint vertextShader;
vertextShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertextShader, , &vertexShaderSource, NULL);
glCompileShader(vertextShader); //用于判断一个着色器是否编译成功
GLint success;
GLchar infoLog[];
glGetShaderiv(vertextShader, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(vertextShader, , NULL, infoLog);
cout << "vertextShader COMPILE FAILED" << endl;
} //片元着色器
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, , &fragmentShaderSource, NULL);
glCompileShader(fragmentShader); //用于判断一个着色器是否编译成功
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(fragmentShader, , NULL, infoLog);
cout << "fragmentShader COMPILE FAILED" << endl;
}

这一块也不难理解:

1st,定义一个着色器(顶点着色器或者片元着色器);

2nd,为这个着色器对象加载着色器程序片段;

3rd,编译这个着色器;

当然,案例程序还加了一段编译成功与否的判断,这是有必要的,方便调试。

三、多个着色器连接

//创建一个着色器程序对象:多个着色器最后链接的版本
GLuint shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertextShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success){
glGetProgramInfoLog(shaderProgram, , NULL, infoLog);
}
glDeleteShader(vertextShader);
glDeleteShader(fragmentShader);

这块也不难理解,新建一个shaderProgram,并且通过glAttachShader() API将之前的两个着色器进行连接,这样顶点着色器输出的四维坐标就能供片元着色器使用了。

两个着色器进行连接之后,对之前的着色器进行删除。

四、将外部顶点数据进行绑定(用户自定义数据)

//创建定点数据
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
//创建 VBO 顶点缓冲数据,并把数据赋值到内存中
GLuint VBO;
glGenBuffers(, &VBO);
//VAO顶点数组对象
GLuint VAO;
glGenVertexArrays(, &VAO); //绑定VAO
glBindVertexArray(VAO); //复制顶点数据到缓冲中提供给OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //设置顶点属性指针
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(GLfloat), (GLvoid *));
glEnableVertexAttribArray(); //解绑VBO
glBindBuffer(GL_ARRAY_BUFFER, ); //解绑VAO
glBindVertexArray();

不难看出,用户自定义顶点数据为三个顶点(-0.5,-0.5,0)(0.5,-0.5,0)和(0,0.5,0);

新建VAO、VBO对象并将其放到内存中;

将用户自定义数据赋值到VBO中;

后面的VAO相关操作没有看懂,这一块不是直接用VBO(顶点缓存对象)么,并没有用到VAO啊???

glVertexAttribPointer()我的理解就是为这些顶点(坐标)设置相应的指针好让程序知道如何操作。

五、渲染

//释放颜色缓存
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); //绘制物体
//当打算渲染一个物体使用使用着色器程序
glUseProgram(shaderProgram);
glBindVertexArray(VAO); //绘制函数
glDrawArrays(GL_TRIANGLES, , );
glBindVertexArray(); glfwSwapBuffers(window);

首先,清空屏幕;

然后调用之前的shaderProgram,并为其绑定数据(??不是已经绑定数据了么)

openGL之着色器程序的使用的更多相关文章

  1. OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)

    OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ...

  2. OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)和varying,uniform,attribute修饰范围

    OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)   所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符. ...

  3. OpenGL ES着色器语言之着色概览(官方文档)

    OpenGL ES着色器语言之着色概览(官方文档第二章) 事实上,OpenGL ES着色语言是两种紧密关联的语言.这些语言用来在OpenGL ES处理管线的可编程处理器创建着色器. 在本文档中,除非另 ...

  4. GLSL 着色器程序

    除了使用Cg/HSL 着色器程序以外, OpenGL 着色器语言(GLSL)着色器可以直接书写shader. 然而,使用原生的GLSL只推荐作为测试使用,或者你清晰的知道你的目标平台是 Mac OS ...

  5. OpenGL ES着色器语言之操作数(官方文档第五章)

    OpenGL ES着色器语言之操作数(官方文档第五章) 5.1操作数 OpenGL ES着色器语言包含如下操作符. 5.2数组下标 数组元素通过数组下标操作符([ ])进行访问.这是操作数组的唯一操作 ...

  6. OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)

    OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...

  7. OpenGL ES着色器语言之静态使用(static use)和预处理

    OpenGL ES着色器语言之静态使用(static use) 在OpenGL ES中有一个术语叫静态使用(static use),什么叫静态使用呢? 在写代码中,对于一个变量可能具有以下三种情况: ...

  8. Android OpenGL ES 开发(八): OpenGL ES 着色器语言GLSL

    前面的文章主要是整理的Android 官方文档对OpenGL ES支持的介绍.通过之前的文章,我们基本上可以完成的基本的形状的绘制. 这是本人做的整理笔记: https://github.com/re ...

  9. OpenGL中着色器,渲染管线,光栅化

    https://www.zhihu.com/question/29163054   光栅(shan一声)化(Rasterize/rasteriztion).这个词儿Adobe官方翻译成栅格化或者像素化 ...

随机推荐

  1. Python学习开发资源大全列表

    1 机器学习和计算机视觉 Crab:灵活.快速的推荐引擎 gensim:人性化的话题建模库 hebel:GPU 加速的深度学习库 NuPIC:智能计算 Numenta 平台 pattern:Pytho ...

  2. openSession()与getCurrentSession()的区别

    getCurrentSession创建的session会和绑定到当前线程,而openSession不会. getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSes ...

  3. java操作Word总结

    import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; import com.jacob.com.Varia ...

  4. C# 使用 wkhtmltopdf 把HTML文本或文件转换为PDF

    一.简介 之前也记录过一篇关于把 HTML 文本或 HTML 文件转换为 PDF 的博客,只是之前那种方法有些局限性. 后来又了解到 wkhtmltopdf.exe 这个工具,这个工具比起之前的那种方 ...

  5. js中var a={}什么意思

    创建一个变量a, 并给a赋值:{}是一个空的对象,是 new Object();的简写.

  6. SQL: coalesce()函数

    ①用途: 将空值替换成其他值 返回第一个非空值 ②表达式: COALESCE是一个函数, (expression_1, expression_2, ...,expression_n)依次参考各参数表达 ...

  7. PHP搞笑注释代码-佛祖配美女

    //////////////////////////////////////////////////////////////////// // _ooOoo_ // // o8888888o // / ...

  8. tcpdump 的正确食用方法

    目录 tcpdump 使用笔记 重要报文头 字段表 ip header tcp header 基础使用 高级版本 指定ttl(通过ttl能够确定系统的类型) tcpdump 使用笔记 重要报文头 字段 ...

  9. .Net频繁访问数据库的优化探究(一)

    知识点:DataTable.Linq.lamda表达式.Cache 场景:查询部门的所有员工和管理员,并分配相应的权限 实现过程一般为:查询部门,遍历部门(查询员工.分配权限.查询管理员.分配权限) ...

  10. Anaconda中常用的用法

    Anaconda中常用的用法 conda 是开源包(packages)和虚拟环境(environment)的管理系统. packages 管理: 可以使用 conda 来安装.更新 .卸载工具包 ,并 ...