Shader(着色器)

什么是Shader?

shader是运行在GPU上的程序。我们前面已经在GPU上创建了buffer并且传输了数据,那么shader就是利用这些数据来展示出图形效果

Vertex Shader和Fragment Shader

简化一下pipeline的话就是
传数据->Vertex Shader -> Fragment Shader ->输出
简单来说,Vertex Shader确定点的位置,Fragment Shader填充像素点。
以三角形为例,Vertex Shader调用3次,而Fragment Shader调用次数和三角形内像素的个数有关,多少个多少次

OpenGL中创建Shader

  1. 创建Shader并分配ID,glCreateShader
  2. 设置Shader内容, glShaderSource
  3. 编译Shader, glCompileShader
  4. 创建Program,glCreateProgram
  5. 附加Shader,glAttachShader
  6. 链接Shader, glLinkProgram
  7. 删除Shader,glDeleteShader
  8. 使用Program, glUseProgram
  9. 删除Program,glDeleteProgram

static GLuint CompileShader(unsigned int type, const std::string& source)
{
    GLuint id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(id);
    
    int result;
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);
    if (result == GL_FALSE) {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)_alloca(length * sizeof(char));
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "failed" << std::endl;
        std::cout << message << std::endl;
        glDeleteShader(id);
        return 0;
    }

    return id;
}

static GLuint CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
    GLuint program = glCreateProgram();
    GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}
GLuint shader = CreateShader(vertexShader, fragmentShader);
glUseProgram(shader);

Shader代码

#shader vertex
#version 330 core  

layout(location = 0)in vec4 position;

void main()
{  
	gl_Position = position;           
};

#shader fragment
#version 330 core  

layout(location = 0) out vec4 color;  

void main()
{  
	color = vec4(1.0, 0.0, 0.0, 1.0);   
};

从文件获取shader代码


struct ShaderProgramSource
{
    std::string vertexSource;
    std::string fragmentSource;
};

static ShaderProgramSource ParseShader(const std::string& filepath)
{
    std::ifstream stream(filepath);

    enum class ShaderType
    {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    std::string line;
    std::stringstream ss[2];
    ShaderType type = ShaderType::NONE;

    while (getline(stream, line))
    {
        if (line.find("#shader") != std::string::npos) {
            if (line.find("vertex") != std::string::npos) {
                type = ShaderType::VERTEX;
            }
            else if (line.find("fragment") != std::string::npos) {
                type = ShaderType::FRAGMENT;
            }
        }
        else
        {
            ss[(int)type] << line << '\n';
        }
    }

    return { ss[0].str(), ss[1].str() };
}
ShaderProgramSource source = ParseShader("./res/shaders/Basic.shader");
GLuint shader = CreateShader(source.vertexSource, source.fragmentSource);
glUseProgram(shader);

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

大纲

Share the Post:
滚动至顶部