如何通过在 glsl 中注册来设置着色器常量?

Posted

技术标签:

【中文标题】如何通过在 glsl 中注册来设置着色器常量?【英文标题】:How can I set shader constants by register in glsl? 【发布时间】:2011-12-16 09:05:25 【问题描述】:

我正在开发一个必须在 directx9 和 opengl 上运行的图形 api(2.1 并且不支持统一缓冲区) 我不想编写两个版本的着色器,需要在 hlsl 和 glsl 之间转换(Cg 不是一个选项) 我已经解决了大多数问题,使用 lua 编写着色器的部分脚本(在 glsl 上创建虚拟 main 以支持顶点输入和输出结构等),但我很难让常量正确。 在 hlsl 我可以写:

float4x4 WorldViewProjection : register( c0 );
float4   ColorTint           : register( c5 );
float3   UVOffset_Time       : register( c6 );

然后使用以下方法设置所有这些:

SetVertexShaderConstantF( 0, pData, 6 )

或者 SetPixelShaderConstantF。 pData 指向具有相同设置的结构(即 4x4 浮点矩阵、4 浮点向量、3 浮点向量)

我在 glsl 中想出的唯一解决方案是:

uniform vec4 UNIFORM0[ 6 ];
#define WorldViewProjection mat4( UNIFORM0[0], UNIFORM0[1], UNIFORM0[2], UNIFORM0[3] )
#define ColorTint UNIFORM0[4]
#define UVOffset_Time vec3( UNIFORM0[5].xyz )

然后我从 opengl 获取“UNIFORM0”的位置并使用 glUniform4fvARB 设置数组 然而,使用#defines 将我的常量放入着色器是非常难看的。

有没有办法让我以类似于 hlsl 的方式设置常量,我需要哪些扩展?

我可以在不使用实际定义的情况下使用某种引用/typedef/handle 来做类似于定义解决方案的事情吗,即:

const mat4 WorldViewProjection = mat4( UNIFORM0[0], UNIFORM0[1], UNIFORM0[2], UNIFORM0[3] );

【问题讨论】:

【参考方案1】:

有没有办法让我以类似于 hlsl 的方式设置常量,我需要哪些扩展?

OpenGL 4.3/ARB_explicit_uniform_location 提供了一种在着色器本身中指定统一位置的方法。您可以使用layout(location = #) 来限定您的制服,因此您不必查询制服位置。

没有此功能,您将无法做到这一点。所以取而代之的是,做 GLSL 风格的事情(查询着色器以获得统一的位置,使用这些位置来设置值)比做 HLSL 风格的事情更容易。毕竟,使用 HLSL 风格,你只是在查询你已经知道的东西。你做的比你需要的要多,但是向一个 API 添加额外的、不必要的查询比尝试从需要它们的查询中删除更容易。

【讨论】:

使用 HLSL 我根本不查询,我也不想查询,因为它不需要。我几乎可以解决 GLSL 上的问题,只需查询一些设置的统一浮点数组。但是不得不使用定义来获取实际的常量是相当难看的。 @Birken:GLSL 需要查询。如果您有两个 API,一个需要查询,一个不需要,抽象它们的最简单方法是同时使用这两个 API 进行查询,而不是试图找到一种不使用任何查询的方法。 对字符串进行查询还不够好。该 api 与常量缓冲区一起工作(与 dx11 一起工作)。我不想进行不必要的 ogl 或 dx 调用。 @Birken:“查询字符串还不够好。”这是 OpenGL 给你的唯一选择。如果这对您来说还不够好,那么您可以做出选择。对于 some 平台来说,跨平台开发总是不是最理想的。由您决定选择哪一个。在这种情况下,最简单的方法是添加更多的 D3D 调用。无论如何,如果您使用的是 D3D 常量缓冲区,那么为什么不在 OpenGL 中使用 uniform buffers 呢?作为程序链接的一部分,您可以一次性设置它们的位置。

以上是关于如何通过在 glsl 中注册来设置着色器常量?的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅如何抽取着色器代码到assets目录下的GLSL文件,以及如何通过Java或者C++代码来加载着GLSL文件?

我的OpenGL学习进阶之旅如何抽取着色器代码到assets目录下的GLSL文件,以及如何通过Java或者C++代码来加载着GLSL文件?

GLSL-片段着色器不同部分的精度不同

去除 GLSL 着色器产生的波纹图案

如何在 C++ 中为 GLSL 片段着色器实现 iGlobalTime?

创建一个 GLSL 制服数组?