Inici


Benvinguts a DirectXCat, la guia en català per aprendre a programar gràfics en DirectX11!

10.4. Tesselation + Displacement mapping

L’últim efecte que explicarem és el que fa referència a una novetat molt remarcable de Directx11. En el capítol referent als shaders es parla de l’efecte tessellation. Allà s’explica que és possible subdividir les malles de la manera que vulguem i en la quantitat de subdivisions que vulguem a una velocitat molt elevada. Si aquest es combina amb el displacement mapping es crea un efecte de relleu 3d molt realista i espectacular. I el millor de tot és que és molt menys costós que dissenyar directament una geometria amb relleu.

Així doncs l’exemple adjunt intenta aclarir i mostrar del que és capaç aquesta tècnica. Aquest cop està extret de la pàgina web d’Nvidia(en anglès). L’exemple s’anomena Terrain Tessellation, i com bé s’explica, utilitza tessellation per hardware, de manera que accelera molt els càlculs. També hi ha un whitepaper que aclareix els processos de càlcul que es fan en el codi adjunt.


Per a descarregar-lo fes click a aquest enllaç.

10.3. Transparència (Alpha Blending)

L’Alpha Blending és una tècnica de gràfics per ordinador que permet fer transparent la nostra geometria. En algunes ocasions ens serà útil per a fer aparèixer geometria o fer-la desaparèixer segons ens convingui.

A Directx3D s'usa una equació per a crear la il·lusió de la transparència.  Per entendre-la, primer detallem la llegenda d’ítems que surten a l’equació:
  • (FC) – Color Final
  • (SP) - Píxel Origen
  • (DP) – Píxel Destí
  • (SBF) - Factor de barreja origen
  • (DBF) - Factor de barreja destí
  • (FA) – Alfa Final
  • (SA) – Alfa Origen
  • (DA) – Alfa Destí
  • (+) - Operador Binari descrit a continuació
  • (X) – Matrius de Multiplicació creuada.

Les dues operacions que generen transparència a Directx11 són les següents:
  • (FC) = (SP) (X) (SBF) (+) (DP) (X) (DPF)
  • (FA) = (SA)(SBF) (+) (DA)(DBF)

La primera equació serveix per a calcular el color de la transparència i la segona per a calcular el seu valor alfa.

Pel que fa a l’operador binari pot ser una de les instruccions següents:

Jugar amb ells ens dóna una idea del que fan, tot i que el nom és molt aclaridor. Bàsicament, cadascun ens proporcionarà un efecte bàsic diferent sobre la transparència.
El factor de barreja (D3D11_BLEND) ens proporciona diferents efectes avançats sobre la transparència. A continuació es llisten cadascun d’ells.

Al següent enllaç es descriuen cadascun d’ells:
Per a poder crear transparència és necessari crear un descriptor de barreja (D3D11_BLEND_DESC).

Al següent enllaç s’expliquen els diferents paràmetres a usar en aquesta estructura:

10.3.1. Problemes amb la transparència en Directx11


A continuació s’expliquen problemes referents amb la transparència en Directx11. Aquests ocorren quan es tenen diversos objectes transparents a l’escena i van lligats a l’ordre en que es renderitzen.

És important renderitzar primer tots els objectes visibles (no transparents) de l’escena primer, i a continuació renderitzar els transparents. Si no es fes així, el càlcul del color de la transparència es faria només amb alguns dels objectes de l’escena no transparents, i no tots, de manera que el resultat final seria fals, fins i tot quedaria poc realista.

Quan es tenen molts objectes a l’escena 3D, més d’un de transparent i més d’un de sòlid, el millor per evitar problemes de color de transparència és crear un vector segons la profunditat de l’escena, des del punt més proper al punt més llunyà segons l’eix de profunditat, i renderitzar els objectes en aquest ordre, alhora que primer els sòlids i a continuació els transparents. 

10.3.2. Exemple de transparència


El següent exemple mostrarà amb transparència les capses de l’exemple del capítol 8, el d’il·luminació.

El primer que cal fer un cop generat el projecte on treballarem, serà definir les variables globals. Definim l’estat de la nostra geometria, i dues variables per mantenir els dos estats de rasterizació, en direcció a les agulles del rellotge i al revés, això ho entendrem més endavant.

ID3D11BlendState* Transparency;
ID3D11RasterizerState* CCWcullMode;
ID3D11RasterizerState* CWcullMode;

A continuació creem una funció per a netejar tots els elements usats en el projecte.

Tenint a mà l’exemple d’il·luminació, ja comentat abans, sota de la funció init cal afegir les funcions referents a la transparència.

Per a poder veure la part del darrere de les capses un cop siguin transparents i evitar així un error que podria donar l’alpha blending, afegim aquest codi que bàsicament canvia la forma de representar els objectes segons on siguin, de manera que la seva visualització sigui sempre l’adient. Això dependrà de l’escena, en el cas d’aquest exemple, interessa fer-ho.

La funció de pintat (DrawScene) quedaria amb aquest aspecte:

Es pot entendre molt millor al codi font adjunt, el qual conté comentaris de que es fa en cada cas. Cal apreciar, però, que s’han afegit funcions respecte l’exemple d’on partim, el d’il·luminació, que fan referència a la transparència i a la manera de rasterizar la geometria.

Les primeres línies referents a la transparència són les següents:

La primera fa referència a quanta opacitat volem de cada color. Aquí marquem que la volem un 75% invisible pels colors RGB i totalment per l’alfa.

La segona línia decideix si està actiu o no l’estat de blending. Ara mateix està actiu. Es pot desactivar tornant a cridar la instrucció canviant els dos primers paràmetres per NULL i el tercer deixant-lo així 0xffffffff.

La darrera línia mescla l’estat de blending creat per nosaltres amb el del pipeline gràfic de manera que la nostra creació tingui efecte a l’escena final.



10.2. Boira

L’efecte de boira en Directx11 no és res més que el que el seu nom indica. L’efecte pretén imitar la boira que es crea quan baixa la temperatura i fa que no hi veiem més enllà d’un llindar que pot ser molt llunyà o molt proper.

La boira, a Directx11 es pot representar mitjançant tres tipus d’equacions diferents:
  • Boira lineal = (FiBoira – DistànciaViewport) / (FiBoira - IniciBoira)
  • Boira Exponencial (tipus 1)= 1.0 /2.71828 elevat a (DistànciaViewport * DensitatBoira)
  • Boira Exponencial (tipus 2) = 1.0/2.71828 elevat a ((DistànciaViewport * DenistatBoira) * (DistànciaViewport * DensitatBoira))
La Boira lineal afegeix l’efecte linealment en relació a la distància entre la càmera i l’objecte emboirat.

La Boira exponencial de tipus 1 afegeix, respecte la boira lineal, una quantitat de boira exponencialment decreixent (o creixent si es mira al revés) entre el punt central de la boira i el punt de la càmera.

La Boira exponencial de tipus 2 fa el mateix que la de tipus 1, però donant més realisme i una aparença de boira més real a canvi de ser més costosa en el càlcul.

Un cop calculada la boira, triant una de les 3 equacions, es crea el FactorBoira. Per aplicar aquest factor a la textura d’un objecte, i produir el color final de la textura, s’usa l’equació següent:
  • ColorBoiraFinal = FactorBoira * ColorTextura + (1.0 - FactorBoira) * ColorBoiraOriginal

A continuació s’explica un exemple relacionat amb l’efecte Boira.

10.2.1. Exemple de boira


El següent exemple pretén generar el FactorBoira en un vèrtex shader i calcular a continuació el colorBoiraFinal en un píxel shader.

L’exemple està format per 8 classes. La majoria d’elles són per organitzar la informació de l’exemple de manera lògica  sent el main de l’aplicació el que crida les funcions necessàries per executar el codi final. La classe important és la que s'anomena fogshaderclass. Aquesta s’encarrega de cridar als shaders que creen l’efecte boira de manera adient. A continuació els expliquem.

Per crear l’efecte boira utilitzem dos shaders, un vèrtex shader i un píxel shader, com ja hem comentat al principi.

Codi del vertex shader:

Codi del pixel shader:

Un cop creats aquests shaders només cal enllaçar-los correctament al projecte i cridar-los de manera igual que fem i hem estat fent durant tots els exemples usant les funcions de shaders des de fora d’aquests.


10.1. Introducció

Fent ús d’algunes funcions de DirectX11 és possible dotar a les escenes 3D o 2D d’efectes especials amb l’objectiu de mostrar més realisme i espectacularitat. A continuació n’expliquem alguns, l’efecte boira, l’efecte transparència i un efecte conjunt usant les tècniques de tessellation i displacement mapping.

5.4. Depth buffer & Stencil buffer

A DirectX11, el depth buffer (anomenat també Z buffer) és usat per enregistrar la profunditat a la que es troba cada píxel que mostrem. Quan més d’un píxel es troben en posicions similars, el depth buffer ens ajuda a determinar quin píxel es mostra i quin no.

El rang de valors del depth buffer va de 0.0f a 1.0f, on el punt situat al 0.0f es troba just davant del z-near i el 1.0f es troba just abans del z-far (les propietats z-near i z-far són explicades en el capítol 4).

Per a tenir un bon funcionament del depth buffer a l’hora de pintar la nostra geometria necessitarem fer ús de l'stencil buffer, el qual s’usa per limitar l’àrea del renderitzat.

Treballar amb la combinació d'aquests dos buffers és una tècnica molt útil per la creació d’ombres i per la creació de reflexions.

Per a poder usar-los primer de tot cal crear-los en l’ inicialització del programa. A continuació tenim un exemple:

Al final del programa, s’hauran d’alliberar:

5.3. Vertex buffer & Index buffer

Per explicar el vertex buffer farem ús de la següent imatge:

Figura 1. Representació d'una esfera 3D.

Una esfera com la mostrada, està formada per centenars de petits triangles, cadascun d’aquests triangles es defineixen a partir de l’unió de tres punts (els seus vèrtexs). Així que per a poder pintar aquest cercle en el nostre programa, necessitem posar tots aquests vèrtexs en un array “especial” el qual li direm vertex buffer.

En el cas de l'index buffer (el qual està molt relacionat amb el vertex buffer), el seu propòsit és enregistrar la localització de cada vèrtex de la geometria que es troba emmagatzemada en el vertex buffer. La GPU usa l’índex buffer per a trobar ràpidament algun vèrtex específic que es trobi al vertex buffer. El concepte de l'index buffer és similar al índex d’un llibre, t’ajuda a trobar el tema que busques amb molta més rapidesa.

Per a crear el vèrtex buffer o l’índex buffer s’usarà la següent estructura de  Directx:

On:
ByteWidth és l’espai que ocupa el buffer (en bytes).
Usage és un valor que especifica com s’escriurà i llegirà l’estructura a memòria, normalment el seu valor és D3D11_USAGE_DEFAULT, (per a més informació visitar: http://msdn.microsoft.com/en-us/library/windows/desktop/ff476259(v=vs.85).aspx ).
BindFlags especifica quin tipus de buffer s’usarà, en el cas del vertex buffer usarem D3D11_BIND_VERTEX_BUFFER.
CPUAccessFlags són canvis d’estat per especificar els tipus d’accés a la CPU (Usar el valor 0 si no es requereix la CPU) , si no volem cap en especial, per defecte usarem el D3D11_CPU_ACCESS_WRITE. Tots els seus valors es poden trobar en la següent direcció http://msdn.microsoft.com/en-us/library/windows/desktop/ff476106(v=vs.85).aspx .
MiscFlags són canvis d’estat que permeten activar els recursos menys comuns. Normalment aquest valor valdrà 0. Per a més informació visitar: http://msdn.microsoft.com/en-us/library/windows/desktop/ff476203(v=vs.85).aspx
StructureByteStride especifica l’espai que ocupa cada element quan es treballa amb buffers estructurats. Normalment aquest valor valdrà 0.

Un cop definida l'estructura, es cridarà la funció CreateBuffer de DirectX la qual ens crearà el buffer. A continuació es mostra l'estructura de la funció CreateBuffer:

Aquesta funció demana tres paràmetres, el primer és l’estructura definida anteriorment, el segon camp és un punter a una estructura D311_SUBRESOURCE_DATA, la qual descriu la inicialització de les dades; i finalment, el tercer camp és una adreça d’un punter per on obtindrem el buffer ja creat.

A continuació tenim un exemple on es mostra la creació del vertex buffer i de l'index buffer:

Al final del programa, s’hauran d’alliberar aquests buffers: