在GLSL中外部定义预处理宏

24

GLSL有完整的C风格预处理器,唯一不支持的是#include。其中一个很棒的功能是,您可以使用#ifdef注释掉函数,从而创建一种着色器,如果不使用某些特定的功能,则可以缩小该着色器。

我的问题是:

是否有一种方法可以从C代码中定义宏?

似乎OpenGL接口没有这样做的方法。一个快速的hack是在从文件加载的代码之前添加几行#define FOO。但这似乎有点反向。

2个回答

28

你其实不需要在加载的代码前加上它,这就是为什么glShaderSourceARB API中有多个字符串的原因。

下面这种做法可以达到你想要的效果:

char *sources[2] = { "#define FOO\n", sourceFromFile };
glShaderSourceARB(shader, 2, sources, NULL);

4
这是一个可行的解决方案,但并不比在源代码前面添加更好。 - rioki
2
嗯,这取决于你想要什么。这是为了防止一些额外的内存分配和复制(这就是为什么我认为前置解决方案有些糟糕)。你觉得哪个更好看,为什么? - Bahbar
30
因为这是一个可怕的想法,你的着色器代码开头必须有 #version 声明。如果你随意添加其他内容,就会使这个声明无法正常工作。这样一来,你将默认使用相当古老的 GLSL 版本 1.10。 - Nicol Bolas
8
只要sources[3]== {"#version 330 core\n", "#define FOO\n, ...",就足以让它成为一个“好主意”。 - Luca
11
除非你有使用不同版本的GLSL的创新想法,否则你需要在着色器代码中修改它,而不是在着色器程序中修改。这意味着你的着色器程序就不能再独立存在了。 - Nicol Bolas
显示剩余5条评论

7
以下是我用来避免#version问题的方法。它是用Java编写的,虽然没有进行性能优化,但完美地解决了问题:
// extract shader sourcecode from file
StringBuilder shaderSource = Tools.readTextRessource(shaderSrcFile.url);

// apply defined values
int versionIndex = shaderSource.indexOf("#version");
if(versionIndex == -1) err("missing #version xxx in shader "+shaderSrcFile.name());
int defineInsertPoint = shaderSource.indexOf("\n", versionIndex)+1;

for (int i = defined.size() - 1; i >= 0; --i)
    shaderSource.insert(defineInsertPoint, "#define " + defined.get(i) + "\n");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接