Glsl 为什么HLSL有语义?

Glsl 为什么HLSL有语义?,glsl,hlsl,Glsl,Hlsl,在HLSL中,我必须使用语义将信息从顶点着色器传递到片段着色器。在GLSL中,不需要语义。语义学的客观好处是什么 示例:GLSL 顶点着色器 varying vec4 foo varying vec4 bar; void main() { ... foo = ... bar = ... } varying vec4 foo varying vec4 bar; void main() { gl_FragColor = foo * bar; } struct VS_OUTPU

在HLSL中,我必须使用语义将信息从顶点着色器传递到片段着色器。在GLSL中,不需要语义。语义学的客观好处是什么

示例:GLSL

顶点着色器

varying vec4 foo
varying vec4 bar;

void main() {
  ...
  foo = ...
  bar = ...
}
varying vec4 foo
varying vec4 bar;

void main() {
  gl_FragColor = foo * bar;
}
struct VS_OUTPUT
{
   float4  foo : TEXCOORD3;
   float4  bar : COLOR2;
}

VS_OUTPUT whatever()
{
  VS_OUTPUT out;

  out.foo = ...
  out.bar = ...

  return out;
}
void main(float4 foo : TEXCOORD3,
          float4 bar : COLOR2) : COLOR
{
    return foo * bar;
}
片段着色器

varying vec4 foo
varying vec4 bar;

void main() {
  ...
  foo = ...
  bar = ...
}
varying vec4 foo
varying vec4 bar;

void main() {
  gl_FragColor = foo * bar;
}
struct VS_OUTPUT
{
   float4  foo : TEXCOORD3;
   float4  bar : COLOR2;
}

VS_OUTPUT whatever()
{
  VS_OUTPUT out;

  out.foo = ...
  out.bar = ...

  return out;
}
void main(float4 foo : TEXCOORD3,
          float4 bar : COLOR2) : COLOR
{
    return foo * bar;
}
示例:HLSL

顶点着色器

varying vec4 foo
varying vec4 bar;

void main() {
  ...
  foo = ...
  bar = ...
}
varying vec4 foo
varying vec4 bar;

void main() {
  gl_FragColor = foo * bar;
}
struct VS_OUTPUT
{
   float4  foo : TEXCOORD3;
   float4  bar : COLOR2;
}

VS_OUTPUT whatever()
{
  VS_OUTPUT out;

  out.foo = ...
  out.bar = ...

  return out;
}
void main(float4 foo : TEXCOORD3,
          float4 bar : COLOR2) : COLOR
{
    return foo * bar;
}
像素着色器

varying vec4 foo
varying vec4 bar;

void main() {
  ...
  foo = ...
  bar = ...
}
varying vec4 foo
varying vec4 bar;

void main() {
  gl_FragColor = foo * bar;
}
struct VS_OUTPUT
{
   float4  foo : TEXCOORD3;
   float4  bar : COLOR2;
}

VS_OUTPUT whatever()
{
  VS_OUTPUT out;

  out.foo = ...
  out.bar = ...

  return out;
}
void main(float4 foo : TEXCOORD3,
          float4 bar : COLOR2) : COLOR
{
    return foo * bar;
}
我看到
VS\u输出中的
foo
bar
如何连接到片段着色器中的
foo
bar
。我不明白的是为什么我有手动选择语义来携带数据。为什么像GLSL一样,DirectX不能在链接着色器时确定数据的放置位置并将其连接

手动指定语义是否有更具体的优势,还是只是汇编语言着色器时代的遗留问题?选择TEXCOORD4比选择COLOR2或Binorma1有速度优势吗

我知道语义可以暗示意义,
foo
bar
没有意义,但它们也可以模糊意义,只要
foo
不是TEXCOORD,而
bar
不是颜色。我们不把语义放在C或C++或JavaScript变量上,为什么HLSL?

< P>需要,简单地说,(旧的)GLSL使用这个变量来命名变量(请注意现在不允许变化)。 语义的一个明显好处是,在阶段之间不需要相同的变量名,因此DirectX管道通过语义而不是变量名进行匹配,并且只要具有兼容的布局,就可以重新排列数据

如果使用foo2重命名foo,则需要在所有着色器(以及最终的后续着色器)中替换此名称。有了语义,你就不需要这个了

此外,由于不需要精确匹配,因此可以更轻松地在着色器阶段之间进行分离

例如:

可以使用如下所示的顶点着色器:

struct vsInput
{
float4 PosO : POSITION;
float3 Norm: NORMAL;
float4 TexCd : TEXCOORD0;
};

struct vsOut
{
float4 PosWVP : SV_POSITION;
float4 TexCd : TEXCOORD0;
float3 NormView : NORMAL;
};

vsOut VS(vsInput input)
{ 
     //Do you processing here
}
struct psInput
{
    float4 PosWVP: SV_POSITION;
    float4 TexCd: TEXCOORD0;
};
还有像这样的像素着色器:

struct vsInput
{
float4 PosO : POSITION;
float3 Norm: NORMAL;
float4 TexCd : TEXCOORD0;
};

struct vsOut
{
float4 PosWVP : SV_POSITION;
float4 TexCd : TEXCOORD0;
float3 NormView : NORMAL;
};

vsOut VS(vsInput input)
{ 
     //Do you processing here
}
struct psInput
{
    float4 PosWVP: SV_POSITION;
    float4 TexCd: TEXCOORD0;
};
由于顶点着色器输出提供像素着色器所需的所有输入,因此这是完全有效的。法线将被忽略,并且不会提供给像素着色器

但是,您可以切换到可能需要法线的新像素着色器,而无需另一个顶点着色器实现。您还可以仅交换PixelShader,从而保存一些API调用(扩展名与OpenGL等效)

因此,在某些方面,语义为您提供了一种在阶段之间封装in/Out的方法,而且由于您引用了其他语言,这就相当于使用属性/设置器/指针地址

从速度上看,命名并没有什么不同(您可以按照任何方式命名语义,当然系统除外)。不同的布局位置确实意味着命中tho(管道将为您重新组织,但也会发出警告,至少在DirectX中是这样)

OpenGL还提供了大致相同的功能(技术上有点不同,但遵循的概念大致相同)


希望这会有所帮助。

正如Catflier上面提到的,使用语义可以帮助解耦着色器

然而,我可以想到语义的一些缺点:

  • 语义的数量受您使用的DirectX版本的限制,因此可能会用完

  • 这个名称的语义有点误导。您将经常看到这类变量(查看posWorld变量):

    结构v2f{ 浮动位置4:位置; 浮动世界:TEXCOORD0; }

  • 您将看到posWorld变量和TEXCOORD0语义根本不相关。但这很好,因为我们不需要将纹理坐标传递给TEXCOORD0。但是,这可能会在那些刚开始使用着色器语言的人之间造成一些混淆。

    我更喜欢在变量后面写
    :NAME
    ,而不是在变量前面写
    布局(location=N)。
    
    此外,如果更改顶点输入的顺序(与Vulkan中不同),则不需要更新HLSL着色器。

    这种做法毫无意义。如果在某些着色器中使用TEXCOORD2,在另一个着色器中使用TEXCOORD0,则它们也不会匹配,因此无论是您自己的变量名还是选择语义名,您仍然必须按名称进行匹配。GLSL不需要
    布局(location=N)
    。这只适用于那些想要硬编码的人。如果没有它,驱动程序将选择位置,您将在运行时查找它们。此外,任何现代引擎都将生成着色器,因此选择位置将由引擎决定,它可以通过名称或数字进行选择,但可以说计算机在数字方面优于名称,因此名称只会为您带来更多开销。