openGL之着色器程序的使用
#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之着色器程序的使用的更多相关文章
- OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)
OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ...
- OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)和varying,uniform,attribute修饰范围
OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章) 所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符. ...
- OpenGL ES着色器语言之着色概览(官方文档)
OpenGL ES着色器语言之着色概览(官方文档第二章) 事实上,OpenGL ES着色语言是两种紧密关联的语言.这些语言用来在OpenGL ES处理管线的可编程处理器创建着色器. 在本文档中,除非另 ...
- GLSL 着色器程序
除了使用Cg/HSL 着色器程序以外, OpenGL 着色器语言(GLSL)着色器可以直接书写shader. 然而,使用原生的GLSL只推荐作为测试使用,或者你清晰的知道你的目标平台是 Mac OS ...
- OpenGL ES着色器语言之操作数(官方文档第五章)
OpenGL ES着色器语言之操作数(官方文档第五章) 5.1操作数 OpenGL ES着色器语言包含如下操作符. 5.2数组下标 数组元素通过数组下标操作符([ ])进行访问.这是操作数组的唯一操作 ...
- OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)
OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...
- OpenGL ES着色器语言之静态使用(static use)和预处理
OpenGL ES着色器语言之静态使用(static use) 在OpenGL ES中有一个术语叫静态使用(static use),什么叫静态使用呢? 在写代码中,对于一个变量可能具有以下三种情况: ...
- Android OpenGL ES 开发(八): OpenGL ES 着色器语言GLSL
前面的文章主要是整理的Android 官方文档对OpenGL ES支持的介绍.通过之前的文章,我们基本上可以完成的基本的形状的绘制. 这是本人做的整理笔记: https://github.com/re ...
- OpenGL中着色器,渲染管线,光栅化
https://www.zhihu.com/question/29163054 光栅(shan一声)化(Rasterize/rasteriztion).这个词儿Adobe官方翻译成栅格化或者像素化 ...
随机推荐
- js-jquery-SweetAlert2【二】配置与方法
一.配置 Argument Default value Description title null 模态对话框的标题.它可以在参数对象的title参数中设置,也可以在swal()方法的第一个参数 ...
- java-mybaits-00202-DAO-原始DAO开发方法
原始Dao开发方法需要程序员编写Dao接口和Dao实现类. 原本的ibatis的 需要在dao实现类中注入一个SqlSessionFactory工厂. 1.思路 程序员需要写dao ...
- raspberry pi 树莓派作为比特比矿机
http://www.instructables.com/id/Bitcoin-Mining-using-Raspberry-Pi/ Step 5: Installing Required Libra ...
- Parallel Decision Tree
Decision Tree such as C4.5 is easy to parallel. Following is an example. This is a non-parallel vers ...
- testng日志和报告
TestNG是通过 Listeners 或者 Reporters 生成测试报告. Listeners,即 org.testng.ITestListener 的实现,能够在测试执行过程中发出各种测试结果 ...
- SpringData_Repository接口概述
Repository 接口是 Spring Data 的一个核心接口,它不提供任何方法,开发者需要在自己定义的接口中声明需要的方法 public interface Repository<T, ...
- 程序员:统治世界or修复bug?
程序员:统治世界or修复bug? 时至今日,我们依然生活在一个市场和技术受到高度崇拜的世界里,但是历史演化的规律提醒着我们:当一个东西开始成为社会崇拜的对象时,其中暗藏的不利因素将悄然的进行着.有人认 ...
- Smarty 模板布局继承
Smarty 模板继承 在覆盖父模板的{block}块以外的地方, 子模板不能定义任何内容.任何在{block}以外的 内容都会被自动忽略. 在子模板和父模板中的{block}内容,可以通过 appe ...
- mysql索引之主键索引
MySQL目前主要有以下几种索引类型:1.普通索引2.唯一索引3.主键索引4.组合索引5.全文索引 二.语句 CREATE TABLE table_name[col_name data type] [ ...
- Python面试题之Python中的类和实例
0x00 前言 类,在学习面向对象我们可以把类当成一种规范,这个思想就我个人的体会,感觉很重要,除了封装的功能外,类作为一种规范,我们自己可以定制的规范,从这个角度来看,在以后我们学习设计模式的时候, ...