Szécsi László 3D Grafikus Rendszerek 14. előadás Direct3D Szécsi László 3D Grafikus Rendszerek 14. előadás
vertex data, instance data RESOURCES PIPELINE STAGES RENDER STATES Vertex buffer Input Assembler I. input streaming Input layout Instance buffer vertex data, instance data Shader program Constant buffers and textures Vertex Shader Uniform parameters processed vertex data Input Assembler II. primitive setup Index buffer Primitive type primitive data Constant buffers and textures Shader program Geometry Shader Uniform parameters Output buffer primitive strip data Cull mode Rasterizer face culling depth bias adjustment clipping homogenous division viewport transformation output filtering Depth bias Viewport Fill mode Filtering fragments with interpolated data Constant buffers and textures Fragment Shader Shader program Uniform parameters fragment color and depth Render target textures Render target textures Render target textures Output merger stencil test depth test blending Depth-stencil state Blending state Depth-stencil texture
GPU pipeline input vertex bufferek index buffer rajzolási állapot egyes pipeline-elemek működési beállításai programozható elemek shader programjai erőforrások – globális memóriában adatok globális (uniform) változók textúrák adatbufferek csak olvasható
GPU pipeline output kép adatbuffer read/write (GpGpu-hoz) render target frame buffer textúra mélységbuffer (+stencil) adatbuffer stream out target read/write (GpGpu-hoz) unordered access view
GPU pipeline tesszellátor nélkül IA VS IA GS RS PS OM SO +mindenki olvashatja a uniform változókat, textúrákat, buffereket
GPU pipeline tesszellátorral tessfactor IA VS IA HS Tess DS GS RS PS OM tessfactor SO +mindenki olvashatja a uniform változókat, textúrákat, buffereket
Rajzolási állapot tessfactor IA IA Tess RS OM input layout primitive topology rasterizer state viewport depth-stencil state blend state SO
semmi új --- semmi új --- semmi új Lépések I vertexek összeállítása Vertex Shader model trafó – hol van a vertex világkoordinátában árnyalás view és proj trafó – hova esik a vertex a képernyőn primitívek összeállítása vertexek összeválogatása vertex bufferbeli sorrend alapján index bufferbeli indexek alapján semmi új --- semmi új --- semmi új
Lépések II tesszelláció Geometry Shader patch primitívekből ami vezérlőpontokkal (vertexekkel) adott lineáris primitívek előállítása vonal, háromszög Geometry Shader primitívek módosítása: kb fix számú és kevés kimeneti primitív primitívek szűrése (kidobni is lehet) vertex bufferbe írás (stream out)
semmi új --- semmi új --- semmi új Lépések III raszterizálás hátsólap-eldobás vágás homogén osztás viewport trafó Pixel shader pixel szín meghatározása z-teszt blending semmi új --- semmi új --- semmi új
Vertexek összeállítása Vertex buffer rekordok tömbje Instance buffer hasonló tömb Minden instance rekorddal el kell küldeni minden vertex rekordot a vertex shadernek pos normal tex pos normal tex pos normal tex IA vertex
semmi új --- semmi új --- semmi új Vertex shader bejövő adat uniform: model, view, proj mátrixok, fények, ... minden vertexre más: vertex és instance elemek [pozíció, normál, szín, texcoord] kimenő adat pozíció homogén normalizált képernyő koordinátákban árnyalás eredménye [szín] bármi más [normál, texcoord] semmi új --- semmi új --- semmi új VS
Primitívek összeállítása non-indexed vertex bufferben egymás után következők semmi új --- semmi új --- semmi új triangle list triangle strip 1 2 3 4 5 6 1 2 3 4 5 2 5 2 4 1 3 4 6 1 5 3
semmi új --- semmi új --- semmi új Indexelt primitívek Index buffer egészek tömbje Indexed primitive index bufferben egymás utáni következő indexekhez tartozó vertexek list, strip előny kényelmes nem kell strip hogy gyors legyen semmi új --- semmi új --- semmi új IA
semmi új --- semmi új --- semmi új Primitívtopológiák I semmi új --- semmi új --- semmi új
Primitívtopológiák II
Primitívtopológiák III
Primitívtopológiák IIII Tesszellátorhoz 1-control-point patch list … 32-control-point patch list Olyan mint a triangle list, csak nem 3 elemű Domain shaderben úgy értelmezzük őket ahogy akarjuk
Tesszellátor Vertexek a vezérlőpontok Hull shader Tesszellátor vezérlőpontok módosítása tesszellációs faktorok számítása Tesszellátor legyárt egy háromszöghálót Domain shader a háromszögháló vertexeinek feltöltése adatokkal pl. pozíció számítása a vezérlőpontok súlyozásával tessfactor HS Tess DS tessfactor
Geometry shader Primitívek vertextömbjét kapja Primitívfolyamba írhat elemszám topológiafüggő ha adjacenciát tartalmaz, akkor azokat is megkapja de a tesszellátor ilyen topológiát nem tud előállítani, ha van tesszellátor akkor adjacencia nincs Primitívfolyamba írhat max. elemszámot meg kell adni lassú ha ez a szám nagy GS SO
Folyamkimenet (Stream Out) Geometry shader kimenete egy vertex bufferbe irányítva Pipeline többi része nem is kell hogy működjön VB később menetre köthető Pl. részecskerendszer-szimuláció részecskék a vertexek GS számítja az új pozíciójukat ping-pong a két VB között
Raszterizáló egység: lapeldobás körüljárási irány (képernyőn) alapján eldobhatunk lapokat ha a modellünkben (index bufferben) konzisztens a háromszögek körüljárási iránya, ezzel eldobhatjuk a test hátsó lapjait a belsejét úgysem látjuk, ha poliéder semmi új --- semmi új --- semmi új
semmi új --- semmi új --- semmi új Raszterizáció vágás homogén osztás viewport trafó: pixel koordináták lineáris interpoláció vertex output adatok (kivéve pozíció) interpolálása minden kitöltendő pixelhez pixel shader indítása minden pixelszín meghatározásához semmi új --- semmi új --- semmi új RS
Pixel shader bejövő adat kimenő adat vertex shader kimenő adatai lineárisan interpolálva pixel koordináták kimenő adat pixel szín [RGBA] mélység, ha felül akarjuk írni a háromszög csúcsainak z-jéből interpolált eredetit ha nem, akkor a z-teszt előrehozható a pixel shader elé PS
semmi új --- semmi új --- semmi új Kimeneti műveletek bufferek célterület (render target) frame buffer textúra mélység-stencil buffer műveletek mélység teszt stencil teszt keverés [alfa blending] semmi új --- semmi új --- semmi új OM
Stencil teszt a stencil buffer a z-buffer pár használatlan bitje beállítódik valamire, ha a pixelbe rajzoltunk valamit később feltételként szabhatjuk a pixel felülírására a stencil buffer értéket pl. kirajzoljuk a tükör téglalapját, utána a tükörben látható objektumokat csak a tükör pixeleire rajzoljuk
Keverés [alpha blending] A célterületen már meglevő érték [dest] és az újonnan számított szín [src] kombinálása mindkettőhöz megadható egy súly (0, 1, srcalpha, dstalpha, 1-alpha ...) megadható a függvény (add, subtract, min, max ...) átlátszóság: hátulról előre rajzolás + blending src * srcalpha + dst * (1- srcalpha)
A pipeline programozása minimális példa
Minimális GPU pipeline IA VS IA RS PS OM textúra cache TS globális eszközmemória konstansok adatbuffer textúra
Minimális rajzolási állapot IA VS IA RS PS OM input layout primitive topology
A pipeline vezérlése erőforrások allokálása vertex buffer, index buffer, textúrák rajzolási állapot beállítása ..., culling, blending, ... shader programok, uniform változók HLSL forrás alapján működés indítása draw call
Direct3D API - device eszköz [device] a grafikus kártya memóriájának absztrakciója erőforrások (és más előregyártott objektumok, állapotstruktúrák, shader programok) kezelésére szolgáló felület ID3D11Device interface ID3D11Device* device;
Direct3D API - context kontextus [context] a pipelineelemek állapotának absztrakciója rajzolási állapot beállítására, rajzolásra szolgáló felület alapvetően egy van belőle egy devicehoz immediate context deferred context többszálú működéshez (lenne) jó ID3D11DeviceContext interface ID3D11DeviceContext* context;
DXUT legacy – de a laborban Win7 van... DirectX utility toolkit olyan mint az OpenGLhez a GLUT oprendszer funkciók elrejtése (ablaknyitás pl.) sokkal többet tud ezért bonyolultabb de a magja ugyanaz általunk írt callback függvények regisztrálása vezérlés átadása eseményekkor meghívja a mi callback függvényeinket
Eszköz-események létrejött [CreateDevice] új ablak [ResizedSwapChain] program indulásakor új ablak [ResizedSwapChain] induláskor, új oprendszer-összerendeléskor (pl. átméretezés után) régi ablak eltűnik [ReleasingSwapChain] hiba esetén, az oprendszer-felület változásakor (pl. átméretezéskor) megszűnt [DestroyDevice]
Erőforrás-gazdálkodás create, resized létrehozás destroy, releasing felszabadítás típusok vertex, index buffer ID3D11Buffer textúra ID3D11Texture2D cube texture, 3D texture
OO eseménykezelés laboron Egg::App osztály metódusait hívják a callbackek CreateDevice → new, createResources DestroyDevice → releaseResources, delete ResizedSwapChain → setSwapChain, createSwapChainResources ReleasingSwapChain → releaseSwapChainResources FrameMove → animate FrameRender → render MsgProc → processMessage LABOR LABOR LABOR LABOR LABOR LABOR LABORLABORLABOR
Állapot-objektumok ezeket is a device metódusaival hozzuk létre és a context metódusaival választjuk ki input layout ID3D11InputLayout VB elemek és VS inputok összrendelése vertex shader ID3D11VertexShader program pixel shader ID3D11PixelShader RasterizerState, BlendState, DepthStencilState
Erőforrástípusok ID3D11Buffer vertex, index, instance, constant, shader resource ID3D11Texture1D, ID3D11Texture2D, ID3D11Texture3D valahány elemű tömbje a valahány mipmap-szinttel rendelkező valamilyen formátumú pixelek tömbjeinek hatelemű textúratömb = cube map
Erőforrás-kezelési módok (usage) immutable létrehozáskor inicializálható, utána csak olvasható dynamic rátölthetünk új adatot akár minden frameben default nem tölthetünk rá, de szerepelhet a pipelineban mint kimenet (pl. render-to- texture) staging CPU memóriában van, átmásolható bele egy default erőforrás tartalma ha olvasni akarjuk
Melyik usage mikor kell? immutable betöltött, fix dolgok, modellek, textúrák dynamic mozgó dolgok, részecskerendszerek default GPU outputként is szereplő elemek staging vészhelyzetben
Erőforrások kötési módjai (bind) vertex buffer pipeline bemenet index buffer shader resource shader olvashat belőle render target kép kerülhet bele depth-stencil stream out constant buffer
Vertex buffer létrehozása D3D11_BUFFER_DESC desc; desc.Usage = D3D11_USAGE_IMMUTABLE; desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; desc.ByteWidth = sizeof(D3DXVECTOR3) * 3; desc.StructureByteStride = sizeof(D3DXVECTOR3); D3DXVECTOR3 vertexPositionArray[3] = { D3DXVECTOR3(0, 0, 0.5), D3DXVECTOR3(0, 1, 0.5), D3DXVECTOR3(1, 0, 0.5) }; D3D11_SUBRESOURCE_DATA initData; initData.pSysMem = vertexPositionArray; pd3dDevice->CreateBuffer( &desc, &initData, &vertexBuffer);
Vertex Shader létrehozása const char* vertexShaderCode = "float4 vsIdle(float4 pos :POSITION ) :SV_Position {return pos;}"; ID3DBlob* vertexShaderByteCode; D3DX11CompileFromMemory(vertexShaderCode, strlen(vertexShaderCode), NULL, NULL, NULL, "vsIdle", "vs_5_0", 0, 0, NULL, &vertexShaderByteCode, NULL, NULL); pd3dDevice->CreateVertexShader( vertexShaderByteCode->GetBufferPointer(), vertexShaderByteCode->GetBufferSize(), NULL, &vertexShader);
Input layout létrehozása D3D11_INPUT_ELEMENT_DESC positionElement; positionElement.AlignedByteOffset = 0; positionElement.Format = DXGI_FORMAT_R32G32B32_FLOAT; positionElement.InputSlot = 0; positionElement.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; positionElement.SemanticName = "POSITION"; positionElement.SemanticIndex = 0; pd3dDevice->CreateInputLayout( &positionElement, 1, vertexShaderByteCode->GetBufferPointer(), vertexShaderByteCode->GetBufferSize(), &inputLayout);
Erőforrások felszabadítása COM objektumok referenciaszámlált createValami növeli a referenciaszámlálót ha végeztünk vele valami->Release(); csökkenti a referenciaszámlálót ha máshol sem kell már fel lesz szabadítva
Erőforrásnézetek vannak esetek amikor az erőforrás simán beköthető, nem kell extra info pl. vertex buffer a pipeline inputra de van amikor kell pl. textúra olvasásra – melyik szeletek, melyik mipmap szintek textúra render targetnek – melyik szelet melyik mipmap szintjére renderelünk ilyenkor létre kell hozni egy erőforrásnézetet, és azt lehet bekötni
Textúra és nézet D3D11_TEXTURE2D_DESC opaqueTextureDesc; //... device->CreateTexture2D( &opaqueTextureDesc, NULL, &opaqueTexture ); D3D11_SHADER_RESOURCE_VIEW_DESC opaqueSrvDesc; opaqueSrvDesc.Format = opaqueTextureDesc.Format; opaqueSrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; opaqueSrvDesc.Texture2D.MostDetailedMip = 0; opaqueSrvDesc.Texture2D.MipLevels = 1; device->CreateShaderResourceView( opaqueTexture, &opaqueSrvDesc, &opaqueSrv );
Egy lépésben fileból betöltve a Texture2D objektum nem érdekes, mindig csak a nézetet fogjuk használni D3DX11CreateShaderResourceViewFromFile( device, L"media/giraffe.jpg", NULL, NULL, &kdSrv, NULL);
Erőforrásnézetek fajtái árnyaló-erőforrásnézet [shader resource view] shader input rajzolásicél-nézet [render target view] output merger input/output mélység‒stencil-nézet [depth stencil view] szabad hozzáférésű nézet [unordered access view] pixel/compute shader input/output
Rajzolás OnFrameRender esemény context metódusainak hívásával be kell állítani render target render state shaderek, uniform paraméterek textúrák vertex, index buffer draw call
Rajzolás unsigned int stride = sizeof(D3DXVECTOR3); ekkorát kell lépni a következő vertexhez Rajzolás unsigned int stride = sizeof(D3DXVECTOR3); unsigned int offset = 0; context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset); context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); context->IASetInputLayout(inputLayout); context->VSSetShader(vertexShader, NULL, 0); context->PSSetShader(pixelShader, NULL, 0); context->Draw(3, 0); innen kezdve 1 db VB elemek értelmezése ennyi vertexet innen kezdve
Effect framework egyszerű módszer HLSL shader kódok betöltésére render state beállításra uniform paraméterek beállítására név alapján, nem kell nekünk kitalálni, melyik regiszterben legyen ugyanazt csinálja, mint a WebGL anyagrendszerünkben a Material.shared textúrák hozzárendelésére név alapján, nem nekünk kell valamelyik textúrázó egységhez rendelni
HLSL shaderek effect fileban egy függvény pass technique11 szemantika input-output változók megcímkézhetők az input layouttal együtt megadják, melyik paraméter értéket honnan vesszük a vertex (ill. instance) bufferből pass render state, shader program beállító script technique11 passok gyűjteménye
HLSL shader függvény struct IaosTrafo // Input Assembler Output Struct { float4 pos : POSITION; }; struct VsosTrafo // Vertex Shader Output Struct float4 pos : SV_POSITION; VsosTrafo vsTrafo(IaosTrafo input) VsosTrafo output = (VsosTrafo)0; output.pos = mul(input.pos, modelViewProjMatrix); return output; }
Technique, pass definíció technique11 basic { pass basic SetVertexShader ( CompileShader( vs_5_0, vsTrafo() ) ); SetPixelShader( CompileShader( ps_5_0, psBasic() ) ); }
Effect11 forráskódban kiadott C++ osztálykönyvtár <dxsdk dir>/Samples/C++/Effects11 le kell fordítani magunknak be kell linkelni de bele lehet nyúlni LABOR LABOR LABOR LABOR LABOR LABOR LABORLABORLABOR
Effect interface kicsit legacy, de nagyon hasznos ID3DX11Effect interface a device context feletti magasabb absztrakciós szint ugyanazt lehet vele megcsinálni, mint a device context metódusaival
Effect nélkül a shader összes paraméterét fel kell sorolni és megszámozni a HLSL kódban ID3D11DeviceContext::PSSetShaderResour ces paraméter: erőforrásnézetek tömbje a shader által várt sorrendben
Effecttel globális változok az effect fileban bármely shader használhatja őket beállítás név szerint effect->GetVariableByName("kdTexture")- >AsShaderResource()->SetResource(kdSrv); nem kell foglalkozni vele melyik shader melyiket használja olyan, mint a WebGL-ben Material.shared
Több effect file használata sok shaderünk van, ne egy kupacon legyen de csak egy .fx-filet tölthetünk be megoldás: lesz egy main.fx, amibe beincludoljuk azokat, amik kellenek laboron: EffectInclude osztály: saját include kereső ID3DInclude interfaceből származtatható effect betöltésekor megadható "" a project folderben, <> a közös folderben keres LABOR LABOR LABOR LABOR LABOR LABOR LABORLABORLABOR
Effect és médiafileok elérési útja honnan tudjuk futásidőben, hogy mi a projektünk elérési útja? kapja meg a programunk parancssori paraméterként Project Properties/Configuration Properties/Debugging/Command Arguments --solutionPath:"$(SolutionDir)" --projectPath:"$(ProjectDir)" parancssori paraméterek kezelésére Egg::SystemEnvironment osztály LABOR LABOR LABOR LABOR LABOR LABOR LABORLABORLABOR
UTF8 UTF16 elvileg mindenhol Unicode stringeket használunk wchar_t*, LPWSTR, std::wstring const wchar_t*, LPCWSTR, const std::wstring ha mégis UTF8 (char*, std::string) kell, akkor konverzió Egg::UftConverter segítségével LABOR LABOR LABOR LABOR LABOR LABOR LABORLABORLABOR