系列五:Shader 与modern opengl是近亲
借用子龙的一句话:不会写Shader,也敢说会OpenGL

参考:https://www.khronos.org/opengl/wiki/Shader_Compilation
Shader使用需要2个过程,1. Shader编译 2.Shader链接,其过程类似于C/C++程序
Shader编译
- 创建打算使用并编译的Shader对象 glCreateShader
- 一旦创建好Shader对象后,需要编辑Shader,即给Shader相应的源代码 glShaderSource
- 编译Shader glCompileShader
- 检查Shader编译的是否正确 glGetShaderiv
- 如果Shader编译有误,查看其相应的输出日志 glGetShaderInfoLog
设置属性槽
如果指明使用Shader中的属性信息,需要在链接Shader前,绑定其属性槽 glBindAttribLocation
Shader链接
- 创建程序对象 glCreateProgame
- 将编译好的Shader对象附加或者作用到链接对象上 glAttachShader
- 链接程序 glLinkProgram
- 检查程序链接是否正确 glGetProgramiv
- 如果程序链接有误,查看其输出日志 glGetProgramInfoLog
- 解除并删除编译对象 glDetachShader glDeleteShader
程序使用
- 使用程序 glUseProgram
- 激活使用的属性槽
GLSPProgram.h
1 #pragma once 2 #include <string> 3 #include <gl/glew.h> 4 5 class GLSLPromgram 6 { 7 public: 8 GLSLPromgram(); 9 ~GLSLPromgram(); 10 11 void compileShaders(const std::string& vertexSharderFilePath, const std::string& fragmentShaderFilePath); 12 13 void linkShaders(); 14 15 void addAttribute(const std::string& attributeName); 16 17 void use(); 18 void unuse(); 19 private: 20 void compileShader(const std::string& filePath, GLuint shaderID); 21 22 GLuint m_progamID; 23 GLuint m_vertexShaderID; 24 GLuint m_fragmentShaderID; 25 int m_numAttributes; 26 };
GLSLProgram.cpp
#include "GLSLPromgram.h" #include "Error.h" #include <fstream> #include <vector> GLSLPromgram::GLSLPromgram() :m_progamID(0), m_vertexShaderID(0), m_fragmentShaderID(0), m_numAttributes(0) { } GLSLPromgram::~GLSLPromgram() { } void GLSLPromgram::compileShaders(const std::string& vertexSharderFilePath, const std::string& fragmentShaderFilePath) { m_vertexShaderID = glCreateShader(GL_VERTEX_SHADER); if (0 == m_vertexShaderID) { faterError("Vertex shader failed to the created!"); } m_fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); if (0 == m_fragmentShaderID) { faterError("Fragment shader failed to the created!"); } compileShader(vertexSharderFilePath, m_vertexShaderID); compileShader(fragmentShaderFilePath, m_fragmentShaderID); } // Now time to link them together into a program. void GLSLPromgram::linkShaders() { // Get a program object. m_progamID = glCreateProgram(); // Attach our shaders to our program glAttachShader(m_progamID, m_vertexShaderID); glAttachShader(m_progamID, m_fragmentShaderID); // Link our program glLinkProgram(m_progamID); // Note the different functions here: glGetProgram* instead of glGetShader*. GLint isLinked(0); glGetProgramiv(m_progamID, GL_LINK_STATUS, &isLinked); if (GL_FALSE == isLinked) { GLint maxLength = 0; glGetProgramiv(m_progamID, GL_INFO_LOG_LENGTH, &maxLength); // The maxLength includes the NULL character std::vector<char> infoLog(maxLength); glGetProgramInfoLog(m_progamID, maxLength, &maxLength, &infoLog[0]); // We don't need the program anymore glDeleteProgram(m_progamID); // Don't leak shaders either glDeleteShader(m_vertexShaderID); glDeleteShader(m_fragmentShaderID); std::printf("%s\n", &(infoLog[0])); faterError("Shaders failed to link"); } // Always detach shaders after a successful link glDetachShader(m_progamID, m_vertexShaderID); glDetachShader(m_progamID, m_fragmentShaderID); // Don't leak shaders either glDeleteShader(m_vertexShaderID); glDeleteShader(m_fragmentShaderID); } void GLSLPromgram::addAttribute(const std::string& attributeName) { glBindAttribLocation(m_progamID, m_numAttributes++, attributeName.c_str()); } void GLSLPromgram::use() { glUseProgram(m_progamID); for (int i = 0; i < m_numAttributes; ++ i) { glEnableVertexAttribArray(i); } } void GLSLPromgram::unuse() { glUseProgram(0); for (int i = 0; i < m_numAttributes; ++ i) { glDisableVertexAttribArray(i); } } void GLSLPromgram::compileShader(const std::string& filePath, GLuint shaderID) { std::ifstream vertexFile(filePath); if (vertexFile.fail()) { perror(filePath.c_str()); faterError("Failed to open " + filePath); } std::string fileContents = ""; std::string line; while (std::getline(vertexFile, line)) { fileContents += line + "\n"; } vertexFile.close(); const char* contentsPtr = fileContents.c_str(); glShaderSource(shaderID, 1, &contentsPtr, nullptr); glCompileShader(shaderID); GLint isCompiled(0); glGetShaderiv(shaderID, GL_COMPILE_STATUS, &isCompiled); if (GL_FALSE == isCompiled) { GLint maxLength(0); glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxLength); std::vector<char> infoLog(maxLength); glGetShaderInfoLog(shaderID, maxLength, &maxLength, &infoLog[0]); glDeleteShader(shaderID); std::printf("%s\n", &(infoLog[0])); faterError("Shader " + filePath + " failed to compile"); } }