我应该把我的着色器代码放在哪里?

Posted

技术标签:

【中文标题】我应该把我的着色器代码放在哪里?【英文标题】:Where should I keep my shader code? 【发布时间】:2015-10-15 23:57:13 【问题描述】:

这是一个哲学问题。

我想知道,是否有任何优雅的方法可以在标准 QtCreator 项目中包含着色器代码。我知道的唯一两种方式是:

    着色器代码位于单独的文件中,例如“fragmentshader.frag”,这个文件在运行时被读取,着色器代码被编译和链接。

    着色器代码是项目中包含的源文件之一中的硬编码字符串。

这两种方式对我来说都有些烦人。第一种可能性要求硬盘驱动器上的文件必须与可执行文件位于同一目录中(因此我必须将它们放在每个调试/发布目录中,并最终得到我的着色器文件的多个副本)或特定的硬编码我的驱动器上的目录,这似乎不利于便携性。

第二种可能性困扰着我,因为您必须在着色器代码中包含 \n 之类的内容,这使得格式有点难看。

如何做到这一点的“正确”方式?如果有任何意义,我正在使用 c/c++、OpenGL 和 GLSL 进行编码。

编辑: 我一直在谷歌上搜索这个......我注意到例如一个图标文件可以保存在项目的一个特殊资源文件夹中。这样它就是一个文件,可以这样编辑,但仍然没有在运行时加载。有没有办法用着色器做到这一点?

【问题讨论】:

【参考方案1】:

如果你有 C++11,你可以做的另一件事是使用原始字符串文字:

const char shaderSource[] = R"glsl(
#version 450 core

...    

void main() 
    ...

)glsl";

看不到\n :)

【讨论】:

这很有趣!我一定会试试的! 难道你必须在每行的开头添加"?刚刚将我的 pro 文件配置为使用 c++11 并在 char 数组中,如果我按下回车,它会自动给我一个引号。 (您在此处发布的测试着色器也无法正常工作) 它可以工作,但没有glsl() 并且每行前后都有引号。 您可以在此处en.cppreference.com/w/cpp/language/string_literal 阅读有关字符串文字的更多信息。左括号和右括号旁边的“glsl”是可选的。它们只是使结束序列更长,以便您的字符串可以包含“)”“而不结束。 我强烈推荐这个。【参考方案2】:

我觉得这不是一个正确的答案,但评论也太长了。

粗略地说,您是对的 - 您可以在编译时使用着色器并进行硬编码,或者在运行时加载。我将详细说明您可以实现这一目标的各种方法。请注意,上述所有内容都可以应用于您的程序需要运行的任何其他类型的数据资源。

硬编码可以以更优雅的方式完成:将资源保存在单独的文件中,但设置您的构建系统,以便它自动生成具有硬编码资源的源文件(作为std::uint8_tchar 的静态或动态数组,例如),并将这些生成的文件编译到您的程序中。在这里,您可能需要一个从二进制数据生成 C++ 源文件的实用程序。我不知道像这样的好的特色节目;当我需要的时候,我自己写了,因为它很简单。

为了使运行时加载更便携,您可以使用许多选项,但似乎最重要的是使文件系统上的资源位置可配置;在运行时或编译时,这取决于您。它可以是编译标志(例如,宏 RUNTIME_RESOURCE_PATH,由构建系统设置)。它可以是一个带有一些合理默认值的命令行选项。

我不知道right 是哪条路。应该根据用例选择一个。

硬编码数据简化了部署(更少的文件、更少的显式 io、更少的错误),而单独文件中的资源使您能够在不触及程序本身的情况下更新它们,包括用户修改。

【讨论】:

«虽然单独文件中的资源使您能够在不触及程序本身的情况下更新它们» - 话虽如此,着色器代码也是一个程序......我们继续飞编译在这里。

以上是关于我应该把我的着色器代码放在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

什么是着色器 (Shader)占用率(Occupancy)? 为什么我们应该关心它?

着色器存储缓冲区中的 OpenGL 顶点

什么是着色器 (Shader)占用率(Occupancy)? 为什么我们应该关心它?

OpenGL 计算着色器 SSBO

OpenGL着色器版本编译错误

Phong 着色器不起作用