2.将着色器对象关联到着色器程序 void glAttachShader(GLuint program, GLuint shader);
参数: 关联到的着色器程序。 着色器对象。 着色器对象可以在任何时候关联到着色器程序,但是只有经过程序的成功链接之后,着色器对象的功能才能可用。 着色器对象可以同时关联到多个不同的着色器程序上。
3.链接着色器程序 void gllinkProgram(GLuint program);
参数: 指定链接的着色器程序。
5.使用着色器来处理顶点和片元 void glUseProgram(GLuint program);
参数: 指定要运行的着色器程序。 如果 program 为0,那么所有当前使用的着色器都会被清除。
Shader类着色器源代码编写、编译、加载、管理都是比较麻烦的事,所以构建一个类专门处理这些事情很有必要。 Shader.h #pragma once#include <string>class Shader{public: /// <summary> /// 加载源代码文件,构造着色器 /// </summary> /// <param name="vertexPath">顶点着色器源代码文件路径</param> /// <param name="fragmentPath">片元着色器源代码文件路径</param> Shader(const std::string& vertexPath, const std::string &fragmentPath); /// <summary> /// 析构函数 /// </summary> ~Shader(); /// <summary> /// 启用着色器程序 /// </summary> void Bind() const; /// <summary> /// 取消使用着色器程序 /// </summary> void Unbind() const;private: /// <summary> /// 着色器程序ID /// </summary> unsigned int m_ID; /// <summary> /// 根据着色器源代码字符串,构建着色器对象 /// </summary> /// <param name="vertexSource">顶点着色器源代码字符串</param> /// <param name="fragmentSource">片元着色器源代码字符串</param> void CreateShader(const std::string& vertexSource, const std::string& fragmentSource); /// <summary> /// 把着色器源代码字符串,根据指定的着色器类型,编译成着色器对象。 /// </summary> /// <param name="type">着色器类型</param> /// <param name="source">着色器源代码字符串</param> /// <returns>返回着色器对象</returns> unsigned int CompileShader(unsigned int type, const std::string& source);};
Shader.cpp #include "Shader.h"#include <GL/glew.h>#include <fstream>#include <sstream>#include <iostream>Shader::Shader(const std::string& vertexPath, const std::string &fragmentPath) :m_ID(0){ // 着色器源代码字符串 std::string vertexCode; std::string fragmentCode; std::ifstream vertexFile; std::ifstream fragmentFile; // 保证ifstream对象可以抛出异常: vertexFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fragmentFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { // 打开文件 vertexFile.open(vertexPath); fragmentFile.open(fragmentPath); std::stringstream vertexStream, fragmentStream; // 读取文件的缓冲内容到数据流中 vertexStream << vertexFile.rdbuf(); fragmentStream << fragmentFile.rdbuf(); // 关闭文件处理器 vertexFile.close(); fragmentFile.close(); // 转换数据流到string vertexCode = vertexStream.str(); fragmentCode = fragmentStream.str(); } catch (const std::exception&) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; } CreateShader(vertexCode, fragmentCode);}Shader::~Shader(){ glDeleteProgram(m_ID);}void Shader::CreateShader(const std::string& vertexSource, const std::string& fragmentSource){ unsigned int vertexShader, fragmentShader; // 顶点着色器对象 vertexShader = CompileShader(GL_VERTEX_SHADER, vertexSource); // 片元着色器对象 fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentSource); if (vertexShader > 0 || fragmentShader > 0) { // 创建着色器程序 m_ID = glCreateProgram(); // 关联着色器对象 if (vertexShader > 0) glAttachShader(m_ID, vertexShader); if (fragmentShader > 0) glAttachShader(m_ID, fragmentShader); // 链接着色器程序 gllinkProgram(m_ID); } // 删除着色器,它们已经链接到我们的程序中了,已经不再需要了 if (vertexShader > 0) glDeleteShader(vertexShader); if (fragmentShader > 0) glDeleteShader(fragmentShader);}unsigned int Shader::CompileShader(unsigned int type, const std::string& source){ unsigned int shader; // 创建着色器对象 shader = glCreateShader(type); const char* src = source.c_str(); // 附加着色器源码 glShaderSource(shader, 1, &src, NULL); // 编译着色器对象 glCompileShader(shader); return shader;}void Shader::Bind() const{ glUseProgram(m_ID);}void Shader::Unbind() const{ glUseProgram(0);}
顶点数据有了着色器,我们就可以把每个顶点上的颜色属性展示出来了。 // 顶点数据float vertices[] = { // --- position --- --- color --- -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下角 -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 左上角 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // 右上角 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f // 右下角};
因为我们添加了另一个顶点属性,并且更新了VBO的内存,我们就必须重新配置顶点属性指针。更新后的VBO内存中的数据现在看起来像这样: // --- 位置属性 ---glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), 0);glEnableVertexAttribArray(0);// --- 颜色属性 ---glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT)));glEnableVertexAttribArray(1);
由于我们现在有了两个顶点属性,我们不得不重新计算步长值:6*sizeof(GL_FLOAT)。对于每个顶点,位置属性的偏移值不变,还是0;而颜色属性的偏移值是位置属性的字节长度,即:3*sizeof(GL_FLOAT)。 完整项目#include <GL/glew.h>#include <GLFW/glfw3.h>#include <iostream>#include "src/Shader.h"unsigned int VBO;unsigned int IBO;void init() { // 顶点数据 float vertices[] = { // --- position --- --- color --- -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下角 -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 左上角 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // 右上角 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f // 右下角 }; // 绘制顶点的顺序 unsigned int indices[] = { 0, 1, 2, // 第一个三角形的顶点数组下标 2, 0, 3 // 第二个三角形的顶点数组下标 }; // 创建一个缓存对象名,并存储到VBO glGenBuffers(1, &VBO); // 将缓存对象绑定到GL_ARRAY_BUFFER glBindBuffer(GL_ARRAY_BUFFER, VBO); // 把顶点数据复制到当前绑定的缓存对象 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 创建一个缓存对象名,并存储到IBO glGenBuffers(1, &IBO); // 将缓存对象绑定到GL_ELEMENT_ARRAY_BUFFER glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); // 把顶点索引数据复制到当前绑定的缓存对象 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // --- 位置属性 --- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), 0); glEnableVertexAttribArray(0); // --- 颜色属性 --- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT))); glEnableVertexAttribArray(1); // 着色器 Shader shader("res/Basic.vert", "res/Basic.frag"); shader.Bind();}void display() { // 绘制 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);}void clear() { // 删除缓存对象 glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &IBO);}// mainint main(void){ GLFWwindow* window; if (!glfwInit()) return -1; window = glfwCreateWindow(640, 480, "Shader", NULL, NULL); if (!window) { glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // glew init if (glewInit() != GLEW_OK) { std::cout << "glew init error!" << std::endl; } // print opengl version std::cout << "OpenGL version :" << glGetString(GL_VERSION) << std::endl; init(); while (!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT); display(); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); clear(); return 0;}
运行结果:
GitHub[作揖]https://github.com/zGameDeveloper/LearnOpenGL/tree/main/Project/06_Shader
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。 违法不良信息举报邮箱:115904045 头条快讯网 版权所有
中国互联网举报中心
|