2014-02-27 22 views
8

在HLSL中,我必須使用語義將信息從頂點着色器傳遞到片段着色器。在GLSL中,不需要語義。語義的客觀利益是什麼?爲什麼HLSL具有語義?

實施例:GLSL

頂點着色器

varying vec4 foo 
varying vec4 bar; 

void main() { 
    ... 
    foo = ... 
    bar = ... 
} 

片段着色器

varying vec4 foo 
varying vec4 bar; 

void main() { 
    gl_FragColor = foo * bar; 
} 

實施例:HLSL

頂點着色器

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_OUTPUTfoobar獲得片段着色器連接到foobarmain。我沒有得到的是爲什麼我手動選擇語義來攜帶數據。爲什麼像GLSL一樣,DirectX不能確定在連接着色器時將數據放置在哪裏並將其連接起來?

手動指定語義還有一些更具體的優點,還是僅僅從彙編語言着色器日期剩下來了嗎?在COLOR2或BINORMAL1上選擇TEXCOORD4是否有一些速度優勢?

我得到的語義可以暗示的意思,也沒有意義foobar但它們也隱晦的意思是剛剛好,如果foo不是TEXCOORD和bar並不出彩。我們不把語義放在C#或C++或JavaScript變量上,爲什麼他們需要HLSL?

回答

8

簡單地說,(舊的)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; 
}; 

由於頂點着色器輸出提供了所有的輸入,像素着色器的需求,這是完全有效的。法線將被忽略,不會提供給像素着色器。

但是,您可以交換到可能需要法線的新像素着色器,而不需要另一個頂點着色器實現。您也可以只交換PixelShader,因此可以保存一些API調用(Separate Shader Objects擴展名爲OpenGL等效項)。

因此,在某些方面的語義爲您提供一種方式來封裝/輸出你的階段之間,因爲你參考其他語言,這將是使用性能/ setter方法/指針地址的等效...

速度明智的,取決於命名沒有區別(你可以以任何你想要的方式命名語義,當然除了系統之外)。不同的佈局位置意味着一個命中壽(管道將重新組織,但也會發出警告,至少在DirectX中)。 OpenGL也提供了Layout Qualifier,它大致相當(技術上有些不同,但是或多或少地遵循相同的概念)。

希望有所幫助。

2

正如Catflier上面提到的,使用語義可以幫助解耦着色器。

不過,也有語義的一些缺點,我能想到的:

  1. 語義的數量由您使用的DirectX版本的限制,所以它可能會用完。

  2. 語義名稱有點誤導。你會看到這些類型的變量很多(看看posWorld變量):

    struct v2f { float4 position : POSITION; float4 posWorld : TEXCOORD0; }

你會看到posWorld變量和TEXCOORD0語義是不相關的。但是沒關係,因爲我們不需要將紋理座標傳遞給TEXCOORD0。然而,這可能會導致那些只是選擇着色語言的人之間的混淆。