Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tato část popisuje, jak používat geometrický shader s fází výstupu datového proudu.
Zkompilovat geometrický shader
Tento geometrický shader (GS) vypočítá normálový vektor plochy pro každý trojúhelník a vystupuje pozici, normálový vektor a texturové souřadnice.
struct GSPS_INPUT
{
float4 Pos : SV_POSITION;
float3 Norm : TEXCOORD0;
float2 Tex : TEXCOORD1;
};
[maxvertexcount(12)]
void GS( triangle GSPS_INPUT input[3], inout TriangleStream<GSPS_INPUT> TriStream )
{
GSPS_INPUT output;
//
// Calculate the face normal
//
float3 faceEdgeA = input[1].Pos - input[0].Pos;
float3 faceEdgeB = input[2].Pos - input[0].Pos;
float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
float3 ExplodeAmt = faceNormal*Explode;
//
// Calculate the face center
//
float3 centerPos = (input[0].Pos.xyz + input[1].Pos.xyz + input[2].Pos.xyz)/3.0;
float2 centerTex = (input[0].Tex + input[1].Tex + input[2].Tex)/3.0;
centerPos += faceNormal*Explode;
//
// Output the pyramid
//
for( int i=0; i<3; i++ )
{
output.Pos = input[i].Pos + float4(ExplodeAmt,0);
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = input[i].Norm;
output.Tex = input[i].Tex;
TriStream.Append( output );
int iNext = (i+1)%3;
output.Pos = input[iNext].Pos + float4(ExplodeAmt,0);
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = input[iNext].Norm;
output.Tex = input[iNext].Tex;
TriStream.Append( output );
output.Pos = float4(centerPos,1) + float4(ExplodeAmt,0);
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = faceNormal;
output.Tex = centerTex;
TriStream.Append( output );
TriStream.RestartStrip();
}
for( int i=2; i>=0; i-- )
{
output.Pos = input[i].Pos + float4(ExplodeAmt,0);
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = -input[i].Norm;
output.Tex = input[i].Tex;
TriStream.Append( output );
}
TriStream.RestartStrip();
}
Mějte na paměti, že geometry shader vypadá podobně jako vertex nebo pixel shader, ale s následujícími výjimkami: typ vrácený funkcí, deklarace vstupních parametrů a intrinsická funkce.
| Položka | Popis | |
|---|---|---|
| návratový typ funkce |
Návratový typ funkce dělá jednu věc: deklaruje maximální počet vrcholů, které mohou být vyprodukovány shaderem. V tomto případě
definuje výstup tak, aby obsahoval maximálně 12 vrcholů. |
|
deklarace vstupních parametrů |
Tato funkce má dva vstupní parametry:
Prvním parametrem je pole vrcholů (3 v tomto případě) definované GSPS_INPUT strukturou (která definuje data pro vrchol jako pozici, normální souřadnici a souřadnici textury). První parametr také používá klíčové slovo trojúhelník, což znamená, že vstupní fáze assembleru musí odesílat data do geometrického shaderu jako jeden z trojúhelníkových primitivních typů (trojúhelníkový seznam nebo úsečka trojúhelníku). Druhý parametr je trojúhelníkový proud definovaný typem TriangleStream<GSPS_INPUT>. To znamená, že parametr je pole trojúhelníků, z nichž každý se skládá ze tří vrcholů (které obsahují data ze členů GSPS_INPUT). Použijte klíčová slova "triangle" a "trianglestream" k identifikaci jednotlivých trojúhelníků nebo proudu trojúhelníků v GS. |
|
Vnitřní funkce |
Řádky kódu ve funkci shaderu používají vnitřní funkce common-shader-core HLSL s výjimkou posledních dvou řádků, které volají Append a RestartStrip. Tyto funkce jsou dostupné pouze pro geometrický shader. Příkaz Append informuje geometrický stínovač, aby připojil výstup k aktuálnímu proužku; RestartStrip vytvoří nový proužek primitiv. V každé vyvolání fáze GS se implicitně vytvoří nový pruh. |
Zbytek shaderu vypadá velmi podobně jako vertexový nebo pixelový shader. Shader geometrie používá strukturu k deklarování vstupních parametrů a označuje člen pozice pomocí sémantiky SV_POSITION, aby informovala hardware, že jde o poziční data. Vstupní struktura identifikuje ostatní dva vstupní parametry jako souřadnice textury (i když jedna z nich bude obsahovat normální tvář). Pokud chcete, můžete pro normální obličej použít vlastní sémantickou sémantiku.
Při návrhu shaderu geometrie volejte D3DCompile ke kompilaci, jak je znázorněno v následujícím příkladu kódu.
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
ID3DBlob** ppShader;
D3DCompile( pSrcData, sizeof( pSrcData ),
"Tutorial13.fx", NULL, NULL, "GS", "gs_4_0",
dwShaderFlags, 0, &ppShader, NULL );
Stejně jako vertexové a pixelové shadery potřebujete příznak shaderu, který kompilátoru říká, jak má být shader zkompilován (pro ladění, optimalizaci pro rychlost atd.), funkci vstupního bodu a model shaderu k ověření. Tento příklad vytvoří geometrický shader vytvořený ze souboru Tutorial13.fx pomocí funkce GS. Shader je zkompilován pro model shaderu 4.0.
Vytvoření objektu Geometry-Shader s výstupem streamu
Jakmile víte, že budete streamovat data z geometrie a úspěšně jste zkompilovali shader, dalším krokem je volání ID3D11Device::CreateGeometryShaderWithStreamOutput k vytvoření objektu shaderu geometrie.
Nejprve ale musíte deklarovat vstupní podpis fáze výstupu datového proudu (SO). Tento podpis odpovídá nebo ověřuje výstupy GS a vstupy SO v době vytvoření objektu. Následující kód je příkladem deklarace SO.
D3D11_SO_DECLARATION_ENTRY pDecl[] =
{
// semantic name, semantic index, start component, component count, output slot
{ "SV_POSITION", 0, 0, 4, 0 }, // output all components of position
{ "TEXCOORD0", 0, 0, 3, 0 }, // output the first 3 of the normal
{ "TEXCOORD1", 0, 0, 2, 0 }, // output the first 2 texture coordinates
};
D3D11Device->CreateGeometryShaderWithStreamOut( pShaderBytecode, ShaderBytecodesize, pDecl,
sizeof(pDecl), NULL, 0, 0, NULL, &pStreamOutGS );
Tato funkce přebírá několik parametrů, mezi které patří:
- Ukazatel na zkompilovaný geometrický stínovač (nebo vrcholový stínovač, pokud nebude přítomen žádný geometrický stínovač a data se budou streamovat přímo z vrcholového stínovače). Informace o získání tohoto ukazatele najdete v tématu Získání ukazatele na zkompilovaný shader.
- Ukazatel na pole deklarací, které popisují vstupní data pro výstupní fázi datového proudu. (Viz D3D11_SO_DECLARATION_ENTRY.) Můžete zadat až 64 deklarací, jednu pro každý jiný typ prvku, který má být výstupem z fáze SO. Pole položek deklarace popisuje rozložení dat bez ohledu na to, zda mají být pro výstup datového proudu vázány pouze jedna vyrovnávací paměť nebo více vyrovnávacích pamětí.
- Počet prvků, které jsou napsány ve fázi SO.
- Ukazatel na objekt shaderu geometrie, který je vytvořen (viz ID3D11GeometryShader).
V této situaci je krok vyrovnávací paměti NULL, index datového proudu, který se má odeslat do rastrátoru, je 0 a rozhraní propojení třídy je NULL.
Deklarace výstupu datového proudu definuje způsob zápisu dat do prostředku vyrovnávací paměti. Do deklarace výstupu můžete přidat libovolný počet komponent. Fáze SO slouží k zápisu do jednoho prostředku vyrovnávací paměti nebo mnoha prostředků vyrovnávací paměti. Pro jednu vyrovnávací paměť může fáze SO zapisovat mnoho různých prvků na vrchol. U více vyrovnávacích pamětí může fáze SO zapisovat do každé vyrovnávací paměti pouze jeden prvek dat související s každým vrcholem.
Pokud chcete použít fázi SO bez použití shaderu geometrie, zavolejte ID3D11Device::CreateGeometryShaderWithStreamOutput a předejte ukazatel na shader vrcholu pShaderBytecode parametru.
Nastavení výstupních cílů
Posledním krokem je nastavení vyrovnávacích pamětí fáze SO. Data je možné streamovat do jedné nebo více vyrovnávacích pamětí v paměti pro pozdější použití. Následující kód ukazuje, jak vytvořit jednu vyrovnávací paměť, kterou lze použít pro data vrcholů, ale také pro stupeň SO ke streamování dat.
ID3D11Buffer *m_pBuffer;
int m_nBufferSize = 1000000;
D3D11_BUFFER_DESC bufferDesc =
{
m_nBufferSize,
D3D11_USAGE_DEFAULT,
D3D11_BIND_STREAM_OUTPUT,
0,
0,
0
};
D3D11Device->CreateBuffer( &bufferDesc, NULL, &m_pBuffer );
Vytvořte vyrovnávací paměť voláním ID3D11Device::CreateBuffer. Tento příklad ukazuje výchozí využití, které je typické pro prostředek vyrovnávací paměti, u kterého se očekává, že jej CPU aktualizuje poměrně často. Příznak vazby identifikuje fázi potrubí, ke které může být prostředek připojen. Všechny prostředky vázané fází SO musí být vytvořeny také s příznakem D3D10_BIND_STREAM_OUTPUT.
Po úspěšném vytvoření vyrovnávací paměti ji nastavte na aktuální zařízení pomocí volání ID3D11DeviceContext::SOSetTargets:
UINT offset[1] = 0;
D3D11Device->SOSetTargets( 1, &m_pBuffer, offset );
Toto volání přebírá počet vyrovnávacích pamětí, ukazatel na tyto paměti a pole offsetů (po jednom offsetu pro každou vyrovnávací paměť, který určuje, kde začít zapisovat data). Data budou zapsána do těchto výstupních vyrovnávacích pamětí streamování při zavolání funkce kreslení. Interní proměnná sleduje pozici, kde začít zapisovat data do vyrovnávací paměti výstupu streamování, a tato proměnná se bude dále zvyšovat, dokud nebude znovu zavolána funkce SOSetTargets a zadá se nová hodnota posunu.
Všechna data zapsaná do cílových vyrovnávacích pamětí budou 32bitové hodnoty.