#include "Shader.h" #include "spdlog/spdlog.h" #include #include Shader::Shader(const QString vertexPath, const QString fragmentPath) { /* 获取OpenGL上下文 */ auto ctx = QOpenGLContext::currentContext(); if(!ctx) { SPDLOG_ERROR("获取OpenGL上下文失败"); return; } m_glFuncs = ctx->functions(); SPDLOG_DEBUG("加载着色器代码"); QByteArray vertexShaderSource; QByteArray fragmentShaderSource; if(!loadShaderSourceFromFile(vertexPath, vertexShaderSource)) { SPDLOG_ERROR("加载顶点着色器失败: {}", vertexPath.toStdString()); return; } if(!loadShaderSourceFromFile(fragmentPath, fragmentShaderSource)) { SPDLOG_ERROR("加载片段着色器失败: {}", fragmentPath.toStdString()); return; } /* 编译着色器 */ SPDLOG_DEBUG("编译着色器..."); GLuint vertexShader = compileShader(vertexShaderSource, GL_VERTEX_SHADER); GLuint fragmentShader = compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER); /* 创建着色器程序 */ m_programID = m_glFuncs->glCreateProgram(); /* 将顶点着色器和片段着色器附加到着色器程序对象上 */ m_glFuncs->glAttachShader(m_programID, vertexShader); m_glFuncs->glAttachShader(m_programID, fragmentShader); /* 链接着色器程序 */ m_glFuncs->glLinkProgram(m_programID); printOpenGLLinkError(m_programID); /* 删除着色器对象 */ m_glFuncs->glDeleteShader(vertexShader); m_glFuncs->glDeleteShader(fragmentShader); SPDLOG_INFO("着色器创建成功"); } Shader::~Shader() { } void Shader::use() { m_glFuncs->glUseProgram(m_programID); } GLuint Shader::getProgramID() const { return m_programID; } /* 设置uniform工具 */ void Shader::setBool(const QString &name, bool value) { auto location = m_glFuncs->glGetUniformLocation(m_programID, name.toStdString().c_str()); m_glFuncs->glUniform1i(location, (int)value); } void Shader::setInt(const QString &name, int value) { auto location = m_glFuncs->glGetUniformLocation(m_programID, name.toStdString().c_str()); m_glFuncs->glUniform1i(location, value); } void Shader::setFloat(const QString &name, float value) { auto location = m_glFuncs->glGetUniformLocation(m_programID, name.toStdString().c_str()); m_glFuncs->glUniform1f(location, value); } /* 打开着色器文件,加载着色器代码 */ bool Shader::loadShaderSourceFromFile(const QString &filePath, QByteArray &outShaderSource) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { SPDLOG_ERROR("无法打开着色器文件: {}", filePath.toStdString()); SPDLOG_ERROR("错误信息: {}", file.errorString().toStdString()); return false; } outShaderSource = file.readAll(); file.close(); return true; } /* 编译着色器 */ GLuint Shader::compileShader(const QByteArray &shaderSource, GLenum shaderType) { const char* sourceCStr = shaderSource.constData(); /* 创建着色器对象 */ GLuint shader = m_glFuncs->glCreateShader(shaderType); /* 加载着色器源码 */ m_glFuncs->glShaderSource(shader, 1, &sourceCStr, nullptr); /* 编译着色器 */ m_glFuncs->glCompileShader(shader); printOpenGLCompileError(shader); return shader; } /* 打印编译错误 */ void Shader::printOpenGLCompileError(GLuint errorCode) { int sucess; char infoLog[512]; m_glFuncs->glGetShaderiv(errorCode, GL_COMPILE_STATUS, &sucess); if (!sucess) { m_glFuncs->glGetShaderInfoLog(errorCode, 512, nullptr, infoLog); SPDLOG_ERROR("OpenGL编译错误: {}", infoLog); } } /* 打印着色器链接错误 */ void Shader::printOpenGLLinkError(GLuint errorCode) { int sucess; char infoLog[512]; m_glFuncs->glGetProgramiv(errorCode, GL_LINK_STATUS, &sucess); if (!sucess) { m_glFuncs->glGetProgramInfoLog(errorCode, 512, nullptr, infoLog); SPDLOG_ERROR("OpenGL链接错误: {}", infoLog); } }