系列五:Shader 与modern opengl是近亲

借用子龙的一句话:不会写Shader,也敢说会OpenGL

参考:https://www.khronos.org/opengl/wiki/Shader_Compilation

Shader使用需要2个过程,1. Shader编译 2.Shader链接,其过程类似于C/C++程序

Shader编译

  1. 创建打算使用并编译的Shader对象  glCreateShader
  2.  一旦创建好Shader对象后,需要编辑Shader,即给Shader相应的源代码  glShaderSource
  3. 编译Shader  glCompileShader
  4. 检查Shader编译的是否正确 glGetShaderiv
  5. 如果Shader编译有误,查看其相应的输出日志  glGetShaderInfoLog

设置属性槽

  如果指明使用Shader中的属性信息,需要在链接Shader前,绑定其属性槽 glBindAttribLocation

Shader链接

  1. 创建程序对象 glCreateProgame
  2. 将编译好的Shader对象附加或者作用到链接对象上 glAttachShader
  3. 链接程序 glLinkProgram
  4. 检查程序链接是否正确 glGetProgramiv
  5. 如果程序链接有误,查看其输出日志 glGetProgramInfoLog
  6. 解除并删除编译对象 glDetachShader glDeleteShader

程序使用

  1. 使用程序 glUseProgram
  2. 激活使用的属性槽

     

 

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

 

posted @ 2020-04-17 12:54  unicornsir  阅读(229)  评论(0)    收藏  举报