Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I det här avsnittet beskrivs hur du använder en geometry-shader med stream output-fasen.
Kompilera en geometry shader
Den här geometry shadern (GS) beräknar en ytanormal för varje triangel och matar ut position, normal- och texturkoordinater.
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();
}
Tänk på att en geometrisk shader ser ut ungefär som en vertex- eller pixelshader, men med följande undantag: typen som returneras av funktionen, indataparameterdeklarationerna och den inbyggda funktionen.
| Föremål | Beskrivning | |
|---|---|---|
|
Funktionsreturtyp |
Funktionens returtyp gör en sak: den deklarerar det maximala antalet vertexer som kan matas ut av skuggaren. I det här fallet
definierar att utdata ska vara högst 12 hörn. |
|
Indataparameterdeklarationer |
Den här funktionen tar två indataparametrar:
Den första parametern är en matris med hörn (3 i det här fallet) som definieras av en GSPS_INPUT struktur (som definierar data per hörn som en position, en normal och en strukturkoordinat). Den första parametern använder också triangelnyckelordet, vilket innebär att indatamonterarsteget måste mata ut data till geometriskuggaren som en av triangelns primitiva typer (triangellista eller triangelremsa). Den andra parametern är en triangelström som definieras av typen TriangleStream<GSPS_INPUT>. Det innebär att parametern är en matris med trianglar som var och en består av tre hörn (som innehåller data från medlemmarna i GSPS_INPUT). Använd nyckelorden triangel och triangelström för att identifiera enskilda trianglar eller en ström av trianglar i en GS. |
|
inbyggd funktion |
Kodraderna i skuggningsfunktionen använder common-shader-core HLSL-inbyggda funktioner förutom de två sista raderna, som anropar Append och RestartStrip. Dessa funktioner är endast tillgängliga för en geometrisk shader. Bifoga informerar geometrishadaren att bifoga utdata till det nuvarande segmentet; RestartStrip skapar ett nytt primitivt segment. En ny remsa skapas implicit i varje anrop av GS-fasen. |
Resten av shadern liknar mycket en vertex- eller pixelshader. Geometriskuggaren använder en struktur för att deklarera indataparametrar och markerar positionsmedlemmen med SV_POSITION semantisk för att tala om för maskinvaran att detta är positionsdata. Indatastrukturen identifierar de andra två indataparametrarna som texturkoordinater (även om en av dem kommer att innehålla en ytanormal). Du kan använda din egen anpassade semantik för ansiktsnormalen om du föredrar det.
När du har utformat geometriskuggningen anropar du D3DCompile för att kompilera enligt följande kodexempel.
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
ID3DBlob** ppShader;
D3DCompile( pSrcData, sizeof( pSrcData ),
"Tutorial13.fx", NULL, NULL, "GS", "gs_4_0",
dwShaderFlags, 0, &ppShader, NULL );
Precis som hörn- och pixelskuggare behöver du en skuggningsflagga för att berätta för kompilatorn hur du vill att skuggningen ska kompileras (för felsökning, optimerad för hastighet och så vidare), startpunktsfunktionen och skuggningsmodellen som ska valideras mot. I det här exemplet skapas en geometriskuggning som skapats från filen Tutorial13.fx med hjälp av GS-funktionen. Shadern kompileras för shadermodell 4.0.
Skapa ett Geometry-Shader objekt med Stream-utdata
När du vet att du kommer att strömma data från geometrin och du har kompilerat skuggningen är nästa steg att anropa ID3D11Enhet::CreateGeometryShaderWithStreamOutput för att skapa objektet för skuggning av geometri.
Men först måste du deklarera indatasignaturen för stream output (SO)-steg. Den här signaturen matchar eller verifierar GS-utdata och SO-indata när objektet skapas. Följande kod är ett exempel på SO-deklarationen.
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 );
Den här funktionen tar flera parametrar, bland annat:
- En pekare till den kompilerade geometrishadern (eller vertexshadern om ingen geometrishader används och data strömmas direkt från vertexshadern). Information om hur du hämtar den här pekaren finns i Hämta en pekare till en kompilerad skuggning.
- En pekare till en matris med deklarationer som beskriver indata för strömningens utdatafas. (Se D3D11_SO_DECLARATION_ENTRY.) Du kan ange upp till 64 deklarationer, en för varje typ av element som ska matas ut från SO-fasen. Matrisen med deklarationsposter beskriver datalayouten oavsett om endast en enda buffert eller flera buffertar ska bindas till strömutdata.
- Antalet element som skrivs ut av SO-fasen.
- En pekare till det geometriskuggningsobjekt som skapas (se ID3D11GeometryShader).
I det här fallet är buffertsteget NULL, indexet för strömmen som ska skickas till rastreringsverktyget är 0 och klasslänkningsgränssnittet är NULL.
Utdatadeklarationen för dataström definierar hur data skrivs till en buffertresurs. Du kan lägga till så många komponenter som du vill i utdatadeklarationen. Använd SO-fasen för att skriva till en enskild buffertresurs eller många buffertresurser. För en enda buffert kan SO-fasen skriva många olika element per vertex. För flera buffertar kan SO-fasen bara skriva ett enda element av vertexdata till varje buffert.
Om du vill använda SO-fasen utan att använda en geometriskuggning anropar du ID3D11Enhet::CreateGeometryShaderWithStreamOutput och skickar en pekare till en hörnskuggning till parametern pShaderBytecode.
Ange utdatamål
Det sista steget är att ställa in SO-stegbuffertarna. Data kan strömmas till en eller flera buffertar i minnet för användning senare. Följande kod visar hur du skapar en enda buffert som kan användas för hörndata, samt för SO-fasen att strömma data till.
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 );
Skapa en buffert genom att anropa ID3D11Enhet::CreateBuffer. Det här exemplet illustrerar standardanvändningen, vilket är typiskt för en buffertresurs som förväntas uppdateras ganska ofta av processorn. Bindningsflaggan identifierar pipelinesteget som resursen kan bindas till. Alla resurser som används av SO-fasen måste också skapas med bindningsflaggan D3D10_BIND_STREAM_OUTPUT.
När bufferten har skapats ställer du in den på den aktuella enheten genom att anropa ID3D11DeviceContext::SOSetTargets:
UINT offset[1] = 0;
D3D11Device->SOSetTargets( 1, &m_pBuffer, offset );
Det här anropet tar antal buffertar, en pekare till buffertarna och en matris med offsetar (en offset till var och en av buffertarna som anger där datan ska börja skrivas). Data skrivs till dessa direktuppspelningsbuffertar när en dragningsfunktion anropas. En intern variabel håller reda på var data ska börja skrivas till buffertarna för direktuppspelningsutdata, och variablerna fortsätter att öka tills SOSetTargets anropas igen och ett nytt förskjutningsvärde anges.
Alla data som skrivs ut till målbuffertarna är 32-bitarsvärden.