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官方翻译成栅格化或者像素化 ...
随机推荐
- python之threading.local
简述: threading.local是全局变量但是它的值却在当前调用它的线程当中 作用: 在threading module中,有一个非常特别的类local.一旦在主线程实例化了一个local,它会 ...
- POI - Excel API
一.概述 1. Apache POI是Apache软件基金会的开放源码函式库,POI提供API给java程式对Microsoft Office格式档案读和写的功能. 2. 结构 ...
- iis6下配置支持.net4.0&发布网站[转]
iis6配置支持.net4.0 在win2003操作系统上发布两个网站,首先配置iis: 1.下载 .net framework 4.0 差不多48MB 2.安装 3.打开iis: 开始=> ...
- STL学习笔记--各种容器的运用时机
如何选择最佳的容器类别? 缺省情况下应该使用vector.vector的内部结构简单,并允许随机存取,所以数据的存取十分方便灵活,数据的处理也够快. 如果经常要在序列的头部和尾部安插和移除元素,应采用 ...
- ubuntu update-alternatives
update-alternatives是ubuntu系统中专门维护系统命令链接符的工具,通过它可以很方便的设置系统默认使用哪个命令.哪个软件版本,比如,我们在系统中同时安装了open jdk和sun ...
- 2.8 The Object Model -- Enumerables
在Ember.js中,枚举是包含许多子对象的任何对象,并允许你使用Ember.Enumerable API和那些子对象一起工作.在大部分应用程序中最常见的可枚举是本地JS数组,Ember.js扩展到符 ...
- c++11 类默认函数的控制:"=default" 和 "=delete"函数 void fun() = default; void fun()=delete;
转自:lsgxeva #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #includ ...
- 001-java虚拟机的概念
https://blog.csdn.net/yfqnihao/article/details/8289363 1.什么是java虚拟机.(你以为你知道,如果你看我下面的例子,你会发现你其实不知道) ( ...
- 2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred) Solution
A. Find a Number Solved By 2017212212083 题意:$找一个最小的n使得n % d == 0 并且 n 的每一位数字加起来之和为s$ 思路: 定义一个二元组$< ...
- Duilib嵌入CEF禁止浏览器响应拖拽事件
转载:http://blog.csdn.net/liuyan20092009/article/details/53819473 转载:https://blog.csdn.net/u012778714( ...