上篇博客,主要是介绍了Opengl的大致使用流程,由于中间过程可能比较复杂,

所以今天笔者首先梳理一遍整个的流程。
祭宝图哈。


上篇博客我们的重点是放在由 顶点数据——>顶点着色器 的这个过程上面,如果对于顶点着色器,以及片段着色器介绍了它们是用shadow语言写的,然后如何调用使用它们的。我们的使用方式为: 在shadowprogram里面指定好两个 :顶点着色器,以及片段着色器。然后我们输入数据,并且规定好 从顶点数据到我们的顶点着色器之间的读取规则。

好的,今天呢,我们重点来关注下顶点着色器以及片段着色器的相关知识。其实,昨天里面就已经包含了顶点着色器,片段着色器了,现在我们来细细的分析下:

// Shaders
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";

以上是两个着色器代码,这里注意哈,虽然是用GLchar* 指示的一个变量,像是字符串,但是这里我们应该认为是代码哈,就是可以运行的哈。两个着色器感觉差不多,我们就取一个来讲。而且这里的的\n其实就是一个换行符,所以整理下为:

#version 330 core
layout (location = 0) in vec3 position; // position变量的属性位置值为0out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main()
{gl_Position = vec4(position, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f); // 把输出变量设置为暗红色
}

ok,一步一步分析:
第一行,就是用#开头,后面的内容就是说指我们的使用版本是多少多少。这个的话,不是很影响,了解就行。
接着,

layout (location = 0) in vec3 position;

这行代码:layout(location)和我们之前设置的有关系,贴个图:

ok,好的,要是不清楚的可以回到之前再看下哈。(对于有件事,由于本人也是在学习opengl,所以在学习的时候会参考一些学习网站,比如https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/04%20Hello%20Triangle/,大家感兴趣,可以去看下哈,这里说的很好,但是可能第一次阅读不是很好懂,我的博客这两篇基本上都是来对于上面的内容进行二次总结。唉,没办法啊,小白入门真的不容易啊)继续,后面的in表示就是指我们输入的是一个vec3的向量,然后变量名为position,就像函数的参数一样。好,接着,

out vec4 vertexColor; // 为片段着色器指定一个颜色输出

这里的话,我们还需要从那个图说起


我们看 着色器的运行是是有一个先后顺序的,要注意,着色器之间是不可以相互通行的,他们就像是一环套一环一样,所以前一个的输出就是另一个的输入。好的,这里的out表示就是输出的意思,表示输出一个vec4的向量,vertexcolor。之后,我们在main函数中的

 gl_Position = vec4(position, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数
vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f); // 把输出变量设置为暗红色们

这里做的事情,就是把我们的glposition给确定好,然后把我们的颜色向量设置好。
看 片段着色器:

#version 330 core
in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)out vec4 color; // 片段着色器输出的变量名可以任意命名,类型必须是vec4void main()
{color = vertexColor;

ok,我们看这里的in vertexColor不就是我们的顶点着色器输出的那个verextColor变量,就是通过这种方式,才能把我们的着色器程序之间相互关联起来。好的,我们可以预想,这里的vec4(0.5f, 0.0f, 0.0f, 1.0f);就是我们绘制的顶点颜色。当然由于内部机制原因,整个图形都是这个颜色。好的,其实到现在为止,我们已经基本了解了。然后我们看个案例吧。

#include <iostream>// GLEW
#define GLEW_STATIC
#include <GL/glew.h>// GLFW
#include <GLFW/glfw3.h>// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;// Shaders
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";// The MAIN function, from here we start the application and run the game loop
int main()
{// Init GLFWglfwInit();// Set all the required options for GLFWglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);// Create a GLFWwindow object that we can use for GLFW's functionsGLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);glfwMakeContextCurrent(window);// Set the required callback functionsglfwSetKeyCallback(window, key_callback);// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensionsglewExperimental = GL_TRUE;// Initialize GLEW to setup the OpenGL Function pointersglewInit();// Define the viewport dimensionsglViewport(0, 0, WIDTH, HEIGHT);// Build and compile our shader program// Vertex shaderGLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// Check for compile time errorsGLint success;GLchar infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// Fragment shaderGLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// Check for compile time errorsglGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// Link shadersGLuint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// Check for linking errorsglGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// Set up vertex data (and buffer(s)) and attribute pointersGLfloat vertices[] = {// Positions         // Colors0.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 Left0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // Top };GLuint VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// Position attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);// Color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));glEnableVertexAttribArray(1);glBindVertexArray(0); // Unbind VAO// Game loopwhile (!glfwWindowShouldClose(window)){// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functionsglfwPollEvents();// Render// Clear the colorbufferglClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// Draw the triangleglUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);glBindVertexArray(0);// Swap the screen buffersglfwSwapBuffers(window);}// Properly de-allocate all resources once they've outlived their purposeglDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);// Terminate GLFW, clearing any resources allocated by GLFW.glfwTerminate();return 0;
}// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)glfwSetWindowShouldClose(window, GL_TRUE);
}

同样的配置,现在的效果是:


ok,这个代码和我们之前讲的那个三角形代码,基本上差不多,只是改了如下的地方

GLfloat vertices[] = {// Positions         // Colors0.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 Left0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // Top };

 // Position attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);// Color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));glEnableVertexAttribArray(1);

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";

这三个地方的代码,主要的意思,就是说我们在存入顶点的坐标数据的时候还写了顶点的颜色rgb值,但是由于的问题是说,我们的片段着色器后面并不是只单单给我们的三个顶点赋值了颜色,其余的位置也是按照线性变化赋值了相应的rgb值。所以最后结果如上图所示。
ok,其实到这里,我觉得对于着色器的相关使用方法已经介绍完了哈。但是可能有一个地方我们需要改进下,就是如果我们的shadow程序太过复杂了,我们都写在.cpp文件下,会显得十分的繁琐,所以我们可以另外写一个文件,然后我们在使用shadow程序之前,用文件流去读写,然后我们就可以写进内容,然后用GLchar*来保存,之后就和之前是一样的。
然后为了方便我们的使用,我们新增加一个类,把读取的相关操作用一个函数进行封装。所有的东西就直接写在.h文件中,内容为:

#ifndef SHADER_H
#define SHADER_H#include <string>
#include <fstream>
#include <sstream>
#include <iostream>#include <GL/glew.h>class Shader
{
public:GLuint Program;// Constructor generates the shader on the flyShader(const GLchar* vertexPath, const GLchar* fragmentPath){// 1. Retrieve the vertex/fragment source code from filePathstd::string vertexCode;std::string fragmentCode;std::ifstream vShaderFile;std::ifstream fShaderFile;// ensures ifstream objects can throw exceptions:vShaderFile.exceptions (std::ifstream::badbit);fShaderFile.exceptions (std::ifstream::badbit);try{// Open filesvShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;// Read file's buffer contents into streamsvShaderStream << vShaderFile.rdbuf();fShaderStream << fShaderFile.rdbuf();// close file handlersvShaderFile.close();fShaderFile.close();// Convert stream into stringvertexCode = vShaderStream.str();fragmentCode = fShaderStream.str();}catch (std::ifstream::failure e){std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;}const GLchar* vShaderCode = vertexCode.c_str();const GLchar * fShaderCode = fragmentCode.c_str();// 2. Compile shadersGLuint vertex, fragment;GLint success;GLchar infoLog[512];// Vertex Shadervertex = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex, 1, &vShaderCode, NULL);glCompileShader(vertex);// Print compile errors if anyglGetShaderiv(vertex, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertex, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// Fragment Shaderfragment = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment, 1, &fShaderCode, NULL);glCompileShader(fragment);// Print compile errors if anyglGetShaderiv(fragment, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragment, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// Shader Programthis->Program = glCreateProgram();glAttachShader(this->Program, vertex);glAttachShader(this->Program, fragment);glLinkProgram(this->Program);// Print linking errors if anyglGetProgramiv(this->Program, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(this->Program, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}// Delete the shaders as they're linked into our program now and no longer necesseryglDeleteShader(vertex);glDeleteShader(fragment);}// Uses the current shadervoid Use() { glUseProgram(this->Program); }
};#endif

之后的话,我们使用起来,就直接用shader函数就可以加载啦。具体使用的案例,我会给一个vs中project,然后直接直接添加到你的解决方案中去。当然配置和之前一样不能少噢。代码下载链接
当然这个只是换了一种方式,最后的效果一样哈,还是这样的

ok,以上就是我对于opengl中着色器的相关使用理解,希望可以帮助到你们哈。

小朱opengl学习笔记(三)------着色器的详细学习相关推荐

  1. OpenGL超级宝典学习笔记:着色器存储区块、原子内存操作、内存屏障

    前言 本篇在讲什么 本篇为蓝宝书学习笔记 着色器存储区块 原子内存操作 内存屏障 本篇适合什么 适合初学Open的小白 本篇需要什么 对 C++语法有简单认知 对 OpenGL有简单认知 最好是有 O ...

  2. LearnOpenGL学习笔记——几何着色器

    几何着色器 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点.几何着色器可以在顶点发送到下一着色器阶段之前对它们随意 ...

  3. dx12 龙书第十二章学习笔记 -- 几何着色器

    如果不启用曲面细分(tessellation)这一环节,那么几何着色器(geometry shader)这个可选阶段便会位于顶点着色器与像素着色器之间.顶点着色器以顶点作为输入数据,而几何着色器的输入 ...

  4. SurfaceFlinger学习笔记(三)之SurfaceFlinger进程

    概述 本系列是基于android Q 即android10 SurfaceFlinger学习笔记(一)应用启动流程 SurfaceFlinger学习笔记(二)之Surface SurfaceFling ...

  5. Hive学习笔记三之函数操作

    文章目录 5 函数 5.1 系统内置函数 5.2 常用内置函数 5.2.1 空字段赋值 5.2.2 CASE WHEN THEN ELSE END(类似于java中的switch case) 5.2. ...

  6. motan学习笔记 三 motan Demo 分析

    motan学习笔记 一 微博轻量级RPC框架Motan motan学习笔记 二 motan架构分析 motan学习笔记 三 motan Demo 分析 motan学习笔记 四 motan Demo 之 ...

  7. OpenGL ES渲染管线与着色器

    转自:http://blog.csdn.net/kesalin/article/details/8223649 [OpenGL ES 02]OpenGL ES渲染管线与着色器 罗朝辉 (http:// ...

  8. OpenCasCade学习笔记(三):加载显示STEP格式图片,并实现平移、缩放和旋转操作

    OpenCasCade学习笔记(三):加载显示STEP格式图片,并实现平移.缩放和旋转操作 C3DWidget.h #pragma once#include <QtWidgets/QApplic ...

  9. K8S 学习笔记三 核心技术 Helm nfs prometheus grafana 高可用集群部署 容器部署流程

    K8S 学习笔记三 核心技术 2.13 Helm 2.13.1 Helm 引入 2.13.2 使用 Helm 可以解决哪些问题 2.13.3 Helm 概述 2.13.4 Helm 的 3 个重要概念 ...

最新文章

  1. anaconda spyder使用协程报错解决:RuntimeError: This event loop is already running
  2. 机器学习【吴恩达|周志华|李宏毅|算法】清单 #收藏#
  3. 合作伙伴:VMware收购Wavefront提供强大的多云应用管理渠道
  4. linux共享文件权限设置,linux – Windows更改Samba文件共享中的文件权限
  5. 【python】正则表达式匹配多个模式
  6. 帧栈使用的基本用法c语言,栈帧详解
  7. SqlParameter类——带参数的SQL语句
  8. 机器人学基础(三):机器人运动学
  9. maven 压缩html,使用YUI Compressor Maven插件压缩 js,css 输出war包
  10. Grasshopper 0.9汉化版下载 【Rhino5.0参数化插件】
  11. Hibernate官网下载最新版jar包
  12. Ubuntu搭建Android NDK开发环境并编译Demo
  13. JS 阻止键盘输入event.preventDefault 和window.event.returnValue
  14. 计算机组成原理- 旋转跳跃的指令实现
  15. 四位共阳极数码管显示函数_4位共阴极数码管单片机驱动
  16. Excel重复编号,1万个数据重复1到100编号
  17. 建矩阵力学奠基新量子论 不确定原理颠覆经典概念|量子群英传
  18. 开发android怎么开发ios app,怎么开发ios android 都能使用的app
  19. Android4.3 Google Pinyin输入法UI定制
  20. win10下QT5.11.1静态编译(带MYSQL)

热门文章

  1. 探索性数据分析 面膜数据描述统计#R
  2. [知识小节]Windbg常用指令(笔记本)
  3. 移动VMware虚拟机
  4. latex中怎么输出双引号
  5. 基因共表达网络分析java,WGCNA:加权基因共表达网络分析
  6. Java黄金矿工小游戏,适合初学者练手项目_java游戏_java项目
  7. 微信小程序学习用demo推荐:微信涂鸦、canvas学习
  8. JETBRAINS开发工具中Translation翻译插件的使用
  9. 思辨领域模型-- DDD≠数据库关系模型
  10. 江苏省专科计算机学校排名2015,2021江苏专科学校排名 最新高职院校排行榜