21

我想使用宏字符串化声明 GLSL 着色器字符串内联:

#define STRINGIFY(A)  #A
const GLchar* vert = STRINGIFY(
#version 120\n
attribute vec2 position;
void main()
{
    gl_Position = vec4( position, 0.0, 1.0 );
}
);

这使用 VS2010 构建并运行良好,但无法编译gcc

error: invalid preprocessing directive #version

有没有办法以可移植的方式使用这样的字符串化?

我试图避免每行引号:

const GLchar* vert = 
"#version 120\n"
"attribute vec2 position;"
"void main()"
"{"
"    gl_Position = vec4( position, 0.0, 1.0 );"
"}"
;

...和/或续行:

const GLchar* vert = "\
#version 120\n                                 \
attribute vec2 position;                       \
void main()                                    \
{                                              \
    gl_Position = vec4( position, 0.0, 1.0 );  \
}                                              \
";
4

5 回答 5

27

你可以使用 C++11 吗?如果是这样,您可以使用原始字符串文字

const GLchar* vert = R"END(
#version 120
attribute vec2 position;
void main()
{
    gl_Position = vec4( position, 0.0, 1.0 );
}
)END";

不需要转义或明确的换行符。这些字符串以 R(或 r)开头。您需要在引号和第一个括号之间使用分隔符(我选择了 END)来转义代码片段中的括号。

于 2012-12-14T04:19:28.467 回答
20

不幸的是,在宏的参数中包含预处理器指令是未定义的,因此您不能直接执行此操作。但只要您的着色器都不需要除 之外的预处理器指令#version,您就可以执行以下操作:

#define GLSL(version, shader)  "#version " #version "\n" #shader

const GLchar* vert = GLSL(120,
    attribute vec2 position;
    void main()
    {
        gl_Position = vec4( position, 0.0, 1.0 );
    }
);
于 2012-12-14T07:40:03.783 回答
5

为了达到这个目的,我使用了 sed。我用 GLSL 编辑了单独的文件(使用正确的语法突出显示),同时 GLSL 在 C++ 中内联。不是很跨平台,但使用 msys 它可以在 windows 下工作。

在 C++ 代码中:

const GLchar* vert = 
#include "shader_processed.vert"
;

在 Makefile 中:

shader_processed.vert: shader.vert
    sed -f shader.sed shader.vert > shader_processed.vert

programm: shader_processed.vert main.cpp
    g++ ...

着色器.sed

s|\\|\\\\|g
s|"|\\"|g
s|$|\\n"|g
s|^|"|g
于 2012-12-14T07:38:06.913 回答
5

问题是由于用于 GLSL 的 gcc 预处理宏。在 GLSL 代码中使用带有新行的标准字符串化和转义预处理器指令对我有用。

#define STRINGIFY(A)  #A

const GLchar* vert = STRINGIFY(

\n#version 120\n
\n#define MY_MACRO 999\n

attribute vec2 position;
void main()
{
    gl_Position = vec4( position, 0.0, 1.0 );
}
);
于 2013-07-09T07:17:21.727 回答
0

另一种方法:包含一个头文件,但带有.glsl扩展名。

例如,我有一个名为bar.h.glsl. 它将我的顶点和片段着色器代码公开为原始文字:

#pragma once

namespace bar {

static const char vertex[] = R"(#version 410 core


// ----- vertex shader start -----
layout( location = 0 ) in vec4 vPosition;

uniform float Time;
uniform float Width;

void main()
{
    float x = vPosition.x;
    float y = vPosition.y * Width;
    float yOffset = mix(sin(Time), sin(Time * 0.75), x * 0.5 + 0.5);
    gl_Position = vec4(x, y + yOffset, vPosition.z, vPosition.w);
}
// ------ vertex shader end ------


)";
static const char fragment[] = R"(#version 410 core


// ----- fragment shader start ----
out vec4 fragColor;

void main()
{
    fragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
// ------ fragment shader end -----


)";

}

然后在我的源代码中,我只包含该文件:

#include "bar.h.glsl"

并像这样访问 glsl 字符串:

bool success = barShader.Compile( bar::vertex, bar::fragment );

这样,虽然我需要忽略我的 glsl 文件中的一些 C 代码,但我可以充分利用 glsl 语法突出显示,而无需动态加载文件。

于 2020-05-08T08:05:13.613 回答