对于 OpenGL 着色器,您将如何用 C++ 编写一个接受所有类型的统一函数?
Posted
技术标签:
【中文标题】对于 OpenGL 着色器,您将如何用 C++ 编写一个接受所有类型的统一函数?【英文标题】:For OpenGL Shaders, how would you write a Uniform Function in C++ that accepts all types? 【发布时间】:2019-11-14 19:08:41 【问题描述】:假设我有一个 Shader 类,我想要一个 Uniform 函数将我传递的数据发送到加载的 Shader 程序
class Shader
unsigned int programid;
template<typename Type>
void Uniform(unsigned int location, Type object)
//Some logic that passes the type data to the uniform using glUniform[?]()
如何编写 Uniform 函数(使用 C++ 中的模板)来接受任何类型(原始 OR 对象)并将其传递给着色器?
例子:
GLSL:uniform float Amount;
C++:shader.Uniform(somefloat);
GLSL:uniform vec3 Position;
C++:
template<typename Type, size_t Size>
Vector Type data[Size];
Vector<float, 3> position = 0.0f, 1.0f, 1.0f
shader.Uniform(position);
GLSL:
struct Light
vec3 position;
vec4 rotation;
float luminosity;
bool status;
;
uniform Light object;
C++:
struct Light
Vector<float, 3> position;
Vector<float, 4> rotation;
float luminosity;
bool status;
Light object = 1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f,true;
shader.Uniform(object);
【问题讨论】:
如果你接受anything,你怎么知道着色器能够处理它?它需要知道如何处理你扔给它的任何东西,它怎么可能做到这一点?魔法?当它无法处理你扔给它的东西时,你会期望它如何表现? 好吧,我会事先知道着色器想要什么(因为我对其进行了编码),Uniform 函数只会有一些逻辑将类型路由到正确的 glUniform 函数(或结构/数组的多个函数调用) .如果我传递了着色器不接受的东西,它应该在内部出错并且不使用传递的对象。 阅读explicit (full) template specialization。请注意,您必须为每种类型编写单独的函数、方法或特化,因为 OpenGL API 为每种类型提供了不同的命名接口函数 (glUniform*
)
【参考方案1】:
首先,C++ 和 GLSL 是静态类型语言,而不是像 javascript 或 Python 那样动态类型。所以没有实际的方法来编写一个接受任何类型的 C++ 函数。您的 C++ 模板函数的作用本质上是文本替换。每次 C++ 编译器看到使用的模板时,例如“Vector”,它都会获取原始模板声明并制作一个新副本,其中“Type”和“Size”分别替换为“float”和“3”。并且编译器会生成一个唯一的重整名称以防止链接器错误,例如 __Vector_TypeFOO_SizeBAR...
(为了完整起见,是的,可以使用联合和/或指针强制转换在 C/C++ 中实现您自己的动态类型。但由于您不能在 GLSL 中执行其中任何一项,因此无助于回答问题。)
因此,由于 GLSL 没有模板来进行文本替换,因此您必须自己实现它。从文件或其他任何内容加载着色器的源。在将其传递给 glCompileShader 之前,请使用您最喜欢的字符串处理库将实际字符串插入占位符文本中。
例如,在您的着色器中,您可以编写如下内容:
<TYPE><SIZE> position;
你的主程序会做类似的事情
src = loadShaderCode("example.template");
src.replace("<TYPE>", "vec");
src.replace("<SIZE>", "3");
shader = compileShader(src, ...);
希望这会有所帮助。
【讨论】:
GLSL 模板系统的好主意,但我一直在寻找 C++ 中的函数系统,它可以接受任何原语或对象或向量并将其发送到着色器。使用模板和类型比较的东西。 (我认为我的问题标题有点混乱) 那么您想要接受一系列 C++ 类型并将它们转换为固定的 GLSL 统一类型的 C++ 函数吗?几个浮点数的简单情况,比如一个标量或 1 到 4 个值的向量,编写 5 个重载变体可能比弄清楚如何模板化更快。除此之外,复杂性会迅速升级,并且在很大程度上取决于谁使用代码以及用于什么目的。 “任何原语或对象或向量”可以是字符串吗? B树? OBJ模型?不知道更多是不可能回答的 是的,昨天才意识到。我只是用复制和粘贴来制作所有原语和矢量函数。如果没有反射,对任何结构对象使用模板都是不可能的。以上是关于对于 OpenGL 着色器,您将如何用 C++ 编写一个接受所有类型的统一函数?的主要内容,如果未能解决你的问题,请参考以下文章
我的OpenGL学习进阶之旅 C++ 长行字符串多行书写的方法以及如何书写正确的OpenGL Shader着色器代码
无法获得简单的 2D 着色器以在 C++ openGL 中绘制红色三角形(无编译器错误)
我的OpenGL学习进阶之旅如何抽取着色器代码到assets目录下的GLSL文件,以及如何通过Java或者C++代码来加载着GLSL文件?