系列五: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 @   unicornsir  阅读(212)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示