1. GLSL语言

glsl语言是用来编写着色器的,通过一段一段包含main函数的程序片段,告诉渲染引擎怎么去渲染内容。

glsl语言的语法有点类似c语言风格,只是增加了一些特有的关键字来修饰变量,下面是一个着色器基本的程序结构:

首先声明的是GLSL的版本号和模式,然后就是声明变量。像其他语言一样,声明变量我们要包括数据类型和变量名两个部分。而在GLSL中,我们还要指定变量的类型。

  • in,通过in关键字来声明,现在声明的变量是一个输入变量。
  • out,对应的out关键字表明这是一个输出变量。
  • uniform,而uniform就比较厉害了,他代表生成的变量是一个全局变量。

最后一部分就是主函数main。我们在这里处理输入输出值。

2. 输入变量in

首先我们可以定义的输入变量的个数是有限的,这一般取决于硬件,但OpenGL至少还是会为我们保留16个输入变量可用。我们可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限:

 3. 输出变量out

由于片段着色器直接输出色值交个显卡渲染,下一个阶段不会对色值进行处理,所以我们生成的输出变量无需与下一个阶段产生联系。但是试想一下,如果我们在顶点着色器中,想传递一个参数给片段着色器怎么办呢?**我们要建立起输入变量和输出变量间的关系。**怎么建立呢,GLSL给了我们一个很简单的方式来建立联系,一致的数据类型及变量名称即可。

顶点着色器

片段着色器

 4 . 全局变量

全局的作用范围作用于整个着色器程序上。也就是你把带有全局变量x的着色器源码编译在着色器A上,再把A添加到着色器程序B上,那么B中的所有着色器都可以使用变量x。并且在GL编码中,也可以通过对应的着色器程序获取到指定的全局变量x。

这里我们仅提供一个在片段着色器中使用全局变量的示例:

片段着色器

渲染循环

 5. 数据类型

向量

向量重组

 6. glVertexAttribPointer

这是一个设置顶点变量属性的函数,通过它可以设置步长,偏移量和位置

顶点数据

顶点着色器

片段着色器

我们看到,顶点着色器中,我们声明了两个输入变量。一个代表位置,一个代表颜色。然后我们要把颜色值传给片段着色器,所以要声明一个输出变量,在片段着色器中在声明一个以一样的输入变量,如此,颜色也就从顶点着色器传到片段着色器中了。

着色器配置完成,我们还要设置顶点数据的属性。

 7. Shader Class

一个着色器程序就是一个最小的绘制单元。其绘制结果直接取决于两个着色器。基于面向对象的思想,我们希望对其进行封装。

我们来梳理一下加载着色器的代码:

创建着色器对象->附加着色器源码并编译->创建着色器程序->绑定着色器->链接着色器

基于上述过程,我们封装了一下着色器程序的类:

  1 #ifndef Shader_hpp
2 #define Shader_hpp
3
4 #include <glad/glad.h>
5 #include <GLFW/glfw3.h>
6 #include <string>
7 #include <fstream>
8 #include <sstream>
9 #include <iostream>
10
11 class Shader {
12 public:
13 ///着色器程序ID
14 unsigned int ID;
15 ///构造器读取着色器
16 Shader(const GLchar * vertexPath,const GLchar * fragmentPath) {
17 std::string vertexCode;
18 std::string fragmentCode;
19 std::ifstream vShaderFile;
20 std::ifstream fShaderFile;
21 // ensure ifstream objects can throw exceptions:
22 vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
23 fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
24 try
25 {
26 ///打开文件
27 vShaderFile.open(vertexPath);
28 fShaderFile.open(fragmentPath);
29 std::stringstream vShaderStream, fShaderStream;
30 ///读取文件
31 vShaderStream << vShaderFile.rdbuf();
32 fShaderStream << fShaderFile.rdbuf();
33 ///关闭文件
34 vShaderFile.close();
35 fShaderFile.close();
36 ///获取源码
37 vertexCode = vShaderStream.str();
38 fragmentCode = fShaderStream.str();
39 }
40 catch (std::ifstream::failure e)
41 {
42 std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
43 }
44 ///获取c字符串
45 const char* vShaderCode = vertexCode.c_str();
46 const char * fShaderCode = fragmentCode.c_str();
47 ///编译
48 unsigned int vertex, fragment;
49 ///顶点着色器
50 vertex = glCreateShader(GL_VERTEX_SHADER);
51 glShaderSource(vertex, 1, &vShaderCode, NULL);
52 glCompileShader(vertex);
53 checkCompileErrors(vertex, "VERTEX");
54 ///片段着色器
55 fragment = glCreateShader(GL_FRAGMENT_SHADER);
56 glShaderSource(fragment, 1, &fShaderCode, NULL);
57 glCompileShader(fragment);
58 checkCompileErrors(fragment, "FRAGMENT");
59 ///着色器程序
60 ID = glCreateProgram();
61 glAttachShader(ID, vertex);
62 glAttachShader(ID, fragment);
63 glLinkProgram(ID);
64 checkCompileErrors(ID, "PROGRAM");
65 ///释放着色器
66 glDeleteShader(vertex);
67 glDeleteShader(fragment);
68 }
69
70 ///激活主色器程序
71 void use() {
72 glUseProgram(ID);
73 }
74
75 ///uniform setter
76 void setBool(const std::string &name ,GLboolean value) const {
77 glUniform1i(glGetUniformLocation(ID,name.c_str()),(GLint)value);
78 }
79 void setInt(const std::string &name ,GLint value) const {
80 glUniform1i(glGetUniformLocation(ID,name.c_str()),value);
81 }
82 void setFloat(const std::string &name ,GLfloat value) const {
83 glUniform1f(glGetUniformLocation(ID,name.c_str()),value);
84 }
85 void setVec4f(const std::string &name ,GLfloat x,GLfloat y,GLfloat z,GLfloat w) const {
86 glUniform4f(glGetUniformLocation(ID,name.c_str()),x,y,z,w);
87 }
88
89 private:
90 ///检查编译错误
91 void checkCompileErrors(unsigned int shader, std::string type)
92 {
93 int success;
94 char infoLog[1024];
95 if (type != "PROGRAM")
96 {
97 glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
98 if (!success)
99 {
100 glGetShaderInfoLog(shader, 1024, NULL, infoLog);
101 std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
102 }
103 }
104 else
105 {
106 glGetProgramiv(shader, GL_LINK_STATUS, &success);
107 if (!success)
108 {
109 glGetProgramInfoLog(shader, 1024, NULL, infoLog);
110 std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
111 }
112 }
113 }
114 };
115
116 #endif /* Shader_hpp */

OpenGL 着色器详解的更多相关文章

  1. GLSL-几何着色器详解跟实例(GS:Geometry Shader)[转]

    [OpenGL4.0]GLSL-几何着色器详解和实例(GS:Geometry Shader) 一.什么是几何着色器(GS:Geometry Shader) Input Assembler(IA)从顶点 ...

  2. 顶点着色器详解 (Vertex Shaders)

    学习了顶点处理,你就知道固定功能流水线怎么将顶点从模型空间坐标系统转化到屏幕空间坐标系统.虽然固定功能流水线也可以通过设置渲染状态和参数来改变最终输出的结果,但是它的整体功能还是受限.当我们想实现一个 ...

  3. C编译器、链接器、加载器详解

    摘自http://blog.csdn.net/zzxian/article/details/16820035 C编译器.链接器.加载器详解 一.概述 C语言的编译链接过程要把我们编写的一个c程序(源代 ...

  4. Java类加载器详解

    title: Java类加载器详解date: 2015-10-20 18:16:52tags: JVM--- ## JVM三种类型的类加载器- 我们首先看一下JVM预定义的三种类型类加载器,当一个 J ...

  5. JMeter 后置处理器之正则表达式提取器详解

    后置处理器之正则表达式提取器详解   by:授客 QQ:1033553122 1. 添加正则表达式提取器 右键线程组->添加->后置处理器->正则表达式提取器 2. 提取器配置介绍 ...

  6. OpenGL着色器入门简介

    说明:本文翻译自LearnOpengl经典教程,OpenGL着色器基础介绍的比较通俗易懂,特总结分享一下! 为什么要使用着色器?我们知道,OpenGL一般使用经典的固定渲染管线来渲染对象,但是随着Op ...

  7. Solr系列五:solr搜索详解(solr搜索流程介绍、查询语法及解析器详解)

    一.solr搜索流程介绍 1. 前面我们已经学习过Lucene搜索的流程,让我们再来回顾一下 流程说明: 首先获取用户输入的查询串,使用查询解析器QueryParser解析查询串生成查询对象Query ...

  8. Lucene系列三:Lucene分词器详解、实现自己的一个分词器

    一.Lucene分词器详解 1. Lucene-分词器API (1)org.apache.lucene.analysi.Analyzer 分析器,分词器组件的核心API,它的职责:构建真正对文本进行分 ...

  9. python设计模式之装饰器详解(三)

    python的装饰器使用是python语言一个非常重要的部分,装饰器是程序设计模式中装饰模式的具体化,python提供了特殊的语法糖可以非常方便的实现装饰模式. 系列文章 python设计模式之单例模 ...

  10. Jmeter 正则表达式提取器详解(Regular Expression Exactor)

    Jmeter 正则表达式提取器详解(Regular Expression Exactor) Name(名称):随意设置,最好有业务意义. Comments(注释):随意设置,可以为空 Apply to ...

随机推荐

  1. 正确处理 CSV 文件的引号和逗号

    CSV(Comma-Separated Values,逗号分割值),就是用纯文本的形式存储表格数据,最大的特点就是方便. 作为开发,我们经常面临导数据的问题,特别是后台系统,产品或者运营的同事常常会提 ...

  2. RDB初步了解

    RDB概念 快照文件是.rdb结尾 redis6.2以前和之后(包括6.2)在什么条件下会保存rdb文件有所不同 以前 15min&&1个key(改变)调用保存 5min&&a ...

  3. Linux下Oracle单实例配置多监听

    Oracle单实例配置多监听 一.前言 有时候我们项目中需要使用Oracle数据库,同时要需要不同的数据源,而Oracle不像Mysql那样直接建个库即可,Oracle是以账号为单位,可以理解为一个账 ...

  4. QTextEdit的使用

    import sys from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit,QVBoxLayout, QPushButton cla ...

  5. vite — 超快且方便的编译工具

    我们编写的代码,比如 ES6. TypeScript.react 等是不能被浏览器直接识别的,需要通过 webpack .rollup 这样的构建工具来对代码进行转换.编译. 但随着项目越来越大,需要 ...

  6. Linq开发技巧与业务逻辑校验

    Linq 是一种基于 .NET Framework 的编程语言,它的出现极大地提高了开发效率.Linq 提供了一种统一的查询语法,使得开发人员可以使用一种语言来查询不同类型的数据源,包括对象.集合.数 ...

  7. EXP 一款 Java 插件化热插拔框架

    EXP 一款 Java 插件化热插拔框架 前言 多年以来,ToB 的应用程序都面临定制化需求应该怎么搞的问题. 举例,大部分本地化软件厂家,都有一个标准程序,这个程序支持大部分企业的功能需求,但面对世 ...

  8. 开机自动打开termux以及启动termux的服务

    ps:因为我们的服务是安装在平板上面的termux,客户不想维护麻烦,如果平板重启之后还需要手动启动ternux,还要开启命令启动服务,这样比较麻烦,所以研究如下操作 1.安装macroDroid 直 ...

  9. GitHub Deskhub使用

    (适合已经知道git是啥但是还不太熟到同学看-) GitHub deskhub就是一个图形化的github管理工具啦,比起来命令行使用舒服100倍哈哈哈- 链接:https://desktop.git ...

  10. ChatGPT大师班 从入门到精通 视频教程 完整版

    本内容收集于:AIGC从入门到精通教程汇总 课程截图 课程目录 01.先导课:工具篇----ChatGPT平替解决方案及汉化教程.mp4 02.第1课:AIGC时代的到来.mp4 03.第2课:认识C ...