VSQTOpengl glsl 中支持#include fileName.

问题:glsl 不支持 include。在进行如通用光照模型,阴影计算相关的shader编码时,会有一堆相同的代码需要编写。光照模型变更,升级时也需要维护,修改大面积代码,十分麻烦。
查找相关的问题后,发现,可以通过OpenGL的 ARB 中的 GL_ARB_shading_language_include 拓展,可以解决该问题。

原理理解:
shader (glsl)不支持文件系统,所以include 无法支持。
GL_ARB_shading_language_include 拓展,通过在内部构建一个shader的虚拟文件系统,解决该问题。

解决步骤及问题:

  • 检查是否支持拓展
    QOpenGLExtraFunctions 子类中,添加拓展支持相关逻辑,代码大致如下。
    bool DMaterial::ExtetionSupport(QString sCheckExteion)
    {
        static QList<QString> szExteions;
        if (szExteions.count() <= 0)
        {
            GLint nEAmount;
            glGetIntegerv(GL_NUM_EXTENSIONS, &nEAmount);
            for (int i = 0; i < nEAmount; i++) {
                const char* sExName = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
                qDebug() << sExName;
                szExteions.append(sExName);
            }
        }

        //QString sCheckExteion = "GL_ARB_shading_language_include";
        if (szExteions.contains(sCheckExteion))
            return true;
        return false;

    }

for 循环,统计当前支持的拓展

如果支持该拓展,继续往下,不支持,暂时没有其他方案。

  • 虚拟文件系统,添加包含的文件
        QByteArray szInShaderPath = sFPath.toLatin1();
        const char* glslName = szInShaderPath.data();
        QFile shaderReader(tr("Shaders/%1").arg(glslName));
        shaderReader.open(QIODevice::ReadOnly | QIODevice::Text);
        QTextStream sReader(&shaderReader);
        sReader.setCodec("UTF-8");
        QString sInclude = sReader.readAll();
        qDebug() << sInclude;
        QByteArray szShaderCode = sInclude.toLatin1();
        const char* glslContent = szShaderCode.data();
        m_pIncludeARB->glNamedStringARB(GL_SHADER_INCLUDE_ARB, strlen(glslName), glslName, strlen(glslContent), glslContent);

通过上述代码将,包含的文件添加到虚拟文件系统中
注:文件必须以"/" 开始,(这块容易遇到问题,之前没有以"/" 开头,glGetError 一致报 1281错误)。
如上,glsl 中可以通过include包含文件。

  • “/” 开头导致的新问题
    由于 glsl 中,include 的 文件 要与 “/” 开始,导致 visual studio glsl 支持的的插件,会报红,找不到引用的文件。如下图:
    在这里插入图片描述思考:如上,虽然运行,不会有错,甚至可以使用其他编辑器,但是膈应人。
    是不是可以读取shader 后,替换 include 内容,手动添加 “/”.
    修改 shader初始化部分代码,提炼include 包含接口,每次加载初始化shader 时,动态添加include 的shader。同时为include 的文件名,添加 “/” 前置。
    shader include 文件接口如下
QList<QString> DMaterial::szIncludeShaders;
    QOpenGLExtension_ARB_shading_language_include* DMaterial::m_pIncludeARB = nullptr;
    void DMaterial::InitIncludeShaders(QString sFPath)
    {
        if (m_pIncludeARB == nullptr)
        {
            m_pIncludeARB = new QOpenGLExtension_ARB_shading_language_include();
            bool bRet = m_pIncludeARB->initializeOpenGLFunctions();
            if (!bRet)
            {
                SafeDelete(m_pIncludeARB);
                return;
            }
        }
        if (szIncludeShaders.contains(sFPath)) return;
        QByteArray szInShaderPath = sFPath.toLatin1();
        const char* glslName = szInShaderPath.data();
        QFile shaderReader(tr("Shaders/%1").arg(glslName));
        shaderReader.open(QIODevice::ReadOnly | QIODevice::Text);
        QTextStream sReader(&shaderReader);
        //sReader.open(QIODevice::ReadOnly | QIODevice::Text);
        sReader.setCodec("UTF-8");
        QString sInclude = sReader.readAll();
        qDebug() << sInclude;
        //QByteArray szShaderCode = shaderReader.readAll();
        QByteArray szShaderCode = sInclude.toLatin1();
        //qDebug() << shaderReader.errorString();
        //qDebug() << szShaderCode;
        //szShaderCode.data();
        const char* glslContent = szShaderCode.data();
        //qDebug() << glGetError();
        //glslContent = "uniform mat4 _ShadowMat;\r\n";
        m_pIncludeARB->glNamedStringARB(GL_SHADER_INCLUDE_ARB, strlen(glslName), glslName, strlen(glslContent), glslContent);
        //pTestInclude->glNamedStringARB(GL_SHADER_INCLUDE_ARB, strlen(glslName), glslName,glslContent.count(), glslContent.data());
        //qDebug() << glGetError();
        bool bRet = m_pIncludeARB->glIsNamedStringARB(strlen(glslName), glslName);
        if (bRet)
            szIncludeShaders.append(sFPath);
    }

shader 初始化,由文件名加载,修改为 读取shader 内容后,查找,添加,以及调整 include 文件格式。
原代码

    QList<DShaderInfo> DMaterial::szDefaultShader = {
            { QOpenGLShader::Vertex, "Shaders/Default.vs.glsl",nullptr },
            { QOpenGLShader::Fragment, "Shaders/Default.fs.glsl",nullptr },
    };

if (m_szShaders.count() <= 0)
        m_szShaders = DMaterial::szDefaultShader;
    m_nGlSProgram.create();
    bool bLoadShaderFailed = false;
    for (QList<DShaderInfo>::iterator it = m_szShaders.begin(); it != m_szShaders.end(); it++)
    {
        it->pShader = new QOpenGLShader(it->eType,this);
        if (it->pShader->compileSourceFile(it->sFileName))
            m_nGlSProgram.addShader(it->pShader);
        else
        {
            qDebug() << "Shader " << it->sFileName << " compilation failed : " << it->pShader->log();
            bLoadShaderFailed = true;
            break;
        }
    }

    if (!bLoadShaderFailed)
    {
        if (!m_nGlSProgram.link())
        {
            bLoadShaderFailed = true;
            qDebug() << "Shader Program link failed : " << m_nGlSProgram.log();
        }
    }

修改后加载代码:

if (m_szShaders.count() <= 0)
        m_szShaders = DMaterial::szDefaultShader;
    m_nGlSProgram.create();
    bool bLoadShaderFailed = false;
    for (QList<DShaderInfo>::iterator it = m_szShaders.begin(); it != m_szShaders.end(); it++)
    {
        it->pShader = new QOpenGLShader(it->eType,this);
        QFile shaderReader(it->sFileName);
        shaderReader.open(QIODevice::ReadOnly);
        QByteArray szShaderCode = shaderReader.readAll();
        int nStartIndex = szShaderCode.indexOf("#include");
        while (nStartIndex != -1)
        {
            int nEndIndex = szShaderCode.indexOf("\n", nStartIndex);
            QByteArray sFile = szShaderCode.mid(nStartIndex + 9, nEndIndex - nStartIndex - 10);
            int nFilsePath = szShaderCode.indexOf("\"", nStartIndex);
            if (szShaderCode[nFilsePath+1] != '/')
            {
                szShaderCode.insert(nFilsePath+1, "/");
                sFile = "/" + sFile;
            }
            sFile = sFile.replace(" ", "");
            sFile = sFile.replace("\"", "");
            PrintLog(sFile);
            DMaterial::InitIncludeShaders(sFile);
            nStartIndex = szShaderCode.indexOf("#include", nEndIndex);
        }
        
        //if (it->pShader->compileSourceFile(it->sFileName))
        QString szCode = szShaderCode;
        if (it->pShader->compileSourceCode(szCode))
            m_nGlSProgram.addShader(it->pShader);
        else
        {
            QString sErrLog = it->pShader->log();
            qDebug() << "Shader " << it->sFileName << " compilation failed : " << sErrLog;
            bLoadShaderFailed = true;
            break;
        }
    }

以上,处理后,可以比较好的再glsl 中使用#include “fileNam.glsl” 引用

参考 文档连接:https://blog.csdn.net/linjf520/article/details/107525793

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值