GLSL预处理器

5

我正在尝试弄清楚以下GLSL代码为什么不起作用:

#ifndef VertexPositionType
#define VertexPositionType vec3
#endif

in StandardVertexShaderInputs {
    VertexPositionType ds_VertexPosition;
};

vec4 ProjectVertexPosition(in vec4 v);

vec4 ProjectVertexPosition(in vec3 v);

void main() {
    gl_Position = ProjectVertexPosition(ds_VertexPosition);
}

着色器拒绝编译。信息日志状态如下:
错误C1008:未定义变量“ProjectVertexPosition”
即使它没有警告预处理器,我也认为预处理器符号VertexPositionType没有被替换。如果我移除预处理器定义,一切都好。
现在,规范说明如下:
#define和#undef功能均按照具有和不具有宏参数的宏定义的C++预处理器的标准定义。
也许下面这行不是一个有效的预处理器行?
#define VertexPositionType vec3

你尝试在多台机器/驱动程序版本上测试了吗?GLSL支持通常比HLSL不稳定,你可能遇到了一个有问题的驱动程序版本。 - Anteru
不是。实际上是在 NVidia 280.26 上编译,着色器版本为 150... - Luca
6
请问"doesn't work"的定义是什么?是指无法编译、无法链接、链接成功但无法运行,还是其他情况?您是否获取了infolog以查看实际的编译器错误(如果有)? - Chris Dodd
哇... 6个 "不工作"!(问题已更新)开始害怕实现C预处理器。哭泣。 - Luca
3个回答

7
你的着色器是非法的。NVIDIA的编译器可能没有输出正确的错误信息,但你的着色器做错了事情(除了你没有提供#version声明之外)。我假设使用#version 330,但明确指定GLSL版本总是一个好习惯。
我只能假设这是一个顶点着色器,因为你正在写入gl_Position。在顶点着色器中,输入接口块是非法的,就像在片段着色器中输出接口块是非法的一样。AMD的编译器更加明确地表达了这一点。
ERROR: 0:5: error(#328) interface block should not apply in 'Vertex Shader in'.
ERROR: 0:14: error(#143) Undeclared identifier ds_VertexPosition
ERROR: 0:14: error(#202) No matching overloaded function found ProjectVertexPosition
ERROR: 0:14: error(#160) Cannot convert from 'const float' to 'Position 4-component vector of float'
ERROR: error(#273) 4 compilation errors.  No code generated

当我将接口块定义删除,仅保留in VertexPositionType ds_VertexPosition;,它就能成功编译。

如果我删除预处理器定义,则一切正常。

那么恭喜你:你发现了一个NVIDIA驱动程序的bug。你应该向他们报告,因为输入接口块不允许在顶点着色器中使用。


3
您声明了一个名为 ProjectVertexPosition 的重载函数,但您从未定义过它,因此在链接程序时出现了未定义的错误。错误信息说 'undefined variable' 可能不太合适,应该说 'undefined function' (因为您将其声明为函数),但我猜测链接器可能无法区分函数符号和变量符号之间的区别。此错误可能来自于 LinkProgram 调用,而与预处理器或 VertexPositionType 无关。

不要告诉我我的电脑上发生了什么。你不信任我的分析吗?这还不够吗?如果您愿意,我可以公开所有的步骤来证明问题是关于预处理器的...... - Luca
只是想指出,函数是在另一个着色器对象中定义的,并且错误来自于CompileShader信息日志。 - Luca
4
因为你没有提供任何关于正在发生什么的信息,所以我只能猜测。你没有提供足够的信息来重现这个问题,而你展示的内容似乎与预处理器无关。 - Chris Dodd
只需在问题的代码中添加 #version 指令即可。 @Chris Dodd - Luca

1
你的程序存在两个主要问题。 #define 不是你的问题。第一个问题是你从未提供 vec4 ProjectVertexPosition(in vec# v) 函数的实现。你需要提供一个声明,例如:
vec4 ProjectVertexPosition(in vec3 v) {
    return normalize(vec4(v, 1.0));
}

并且对于 in vec4 v 版本也是如此。删除定义的原因是让着色器忽略输入块,这本来就是无效的。在顶点着色器中,你不能使用 in 块。而是应该使用布局和结构体或者统一变量和结构体。对于顶点着色器,只能使用统一变量或者布局,不能使用纯粹的 in。如果你想使用布局,请按照以下步骤进行:

layout(location = 0) in VertexPositionType ds_VertexPosition;

对于C/C++方面,请执行以下操作(其中pointCount是VAO中点的数量,points是一个包含按顺序排列的点x1、y1、z1、x2、y2、z2、x3...的GLfloat*):

GLfloat* points = (GLfloat*) malloc(pointCount * 3 * sizeof(GLfloat));
// Set your points however you want here

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 3 * pointCount * sizeof(GLfloat), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
free(points);

// Now to draw (use whatever programId is returned when you link the program)
glUseProgram(programId);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, pointCount);
glUseProgram(0);

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