Cherno Video: https://www.youtube.com/watch?v=8wFEzIYRZXg&list=PLlrATfBNZ98dC-V-N3m0Go4deliWHPFwT&index=45&t=7s
Mycode : https://github.com/DXT00/Hazel_study/tree/043f14b8acecdb7064edbf720c7999cad5b8c60a/Hazel
把Shader写进文件,使用时从文件读入:
std::string OpenGLShader::ReadFile(std::string filepath)
{
std::string result;
std::ifstream in(filepath, std::ios::in | std::ios::binary);
if (in) {
in.seekg(0, std::ios::end);//指向文件末尾
result.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&result[0], result.size());
in.close();
}
else {
HZ_CORE_ERROR("Could not open file '{0}'", filepath);
}
return result;
}
使用unordered_map存储vertex shader和 fragment shader
OpenGLShader::OpenGLShader(const std::string& vertexSrc, const std::string& fragmentSrc)
{
std::unordered_map<GLenum, std::string> shaderSources;
shaderSources[GL_VERTEX_SHADER] = vertexSrc;
shaderSources[GL_FRAGMENT_SHADER] = fragmentSrc;
Compile(shaderSources);
}
std::unordered_map<GLenum, std::string> OpenGLShader::PreProcess(const std::string& source) {
std::unordered_map<GLenum, std::string> shaderSources;
const char* typeToken = "#type";
size_t typeTockenLength = strlen(typeToken);
size_t pos = source.find(typeToken, 0);//find找不到会返回npos
while (pos != std::string::npos) {
size_t eol = source.find_first_of("\r\n", pos);
HZ_CORE_ASSERT(eol != std::string::npos, "Syntax error");
size_t begin = pos + typeTockenLength + 1;
std::string type = source.substr(begin, eol - begin);
HZ_CORE_ASSERT(ShaderTypeFromString(type), "Invalid shader type specified");
size_t nextLinePos = source.find_first_not_of("\r\n", eol);
pos = source.find(typeToken, nextLinePos);
shaderSources[ShaderTypeFromString(type)] = source.substr(nextLinePos,
pos - (nextLinePos == std::string::npos ? source.size() - 1 : nextLinePos));//string::npos表示source的末尾位置
}
return shaderSources;
}
find_first_not_of , find_first_of,string::npos:https://blog.csdn.net/qq_32095699/article/details/100877726
Compile Shader :
void OpenGLShader::Compile(const std::unordered_map<GLenum, std::string>& shaderSources)
{
GLuint program = glCreateProgram();
std::vector<GLuint> ShaderID;
for (auto& kv : shaderSources) {
GLenum type = kv.first;
const std::string& source = kv.second;
GLuint shader = glCreateShader(type);
ShaderID.push_back(shader);
const GLchar *sourceCstr = source.c_str();
glShaderSource(shader, 1, &sourceCstr, 0);
glCompileShader(shader);
GLint isCompiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);
glDeleteShader(shader);
HZ_CORE_ERROR("{0}", infoLog.data());
HZ_CORE_ASSERT(false, "Shader compliation failure!")
break;
}
// Attach our shaders to our program
glAttachShader(program, shader);
}
// Vertex and fragment shaders are successfully compiled.
// Now time to link them together into a program.
// Get a program object.
// Link our program
glLinkProgram(program);
// Note the different functions here: glGetProgram* instead of glGetShader*.
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
if (isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
// We don't need the program anymore.
glDeleteProgram(program);
// Don't leak shaders either.
for (auto& shader : ShaderID) {
glDeleteShader(shader);
}
HZ_CORE_ERROR("{0}", infoLog.data());
HZ_CORE_ASSERT(false, "Shader link failure!")
return;
}
// Always detach shaders after a successful link.
for (auto& shader : ShaderID) {
glDetachShader(program,shader);
}
m_RendererID = program;
}