什么是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
- 创建Shader并分配ID,glCreateShader
- 设置Shader内容, glShaderSource
- 编译Shader, glCompileShader
- 创建Program,glCreateProgram
- 附加Shader,glAttachShader
- 链接Shader, glLinkProgram
- 删除Shader,glDeleteShader
- 使用Program, glUseProgram
- 删除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);