IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

3. diel - 3D grafika v OpenGL a C ++ - Základy vykresľovanie

V minulej lekcii, 3D grafika v OpenGL a C ++ - Vytvorenie okna , sme si otvorili naše prvé okno. Poďme si do neho niečo vykresliť.

Vykresľovanie trojuholníka

Konečne sa dostávame k samotnému vykresľovanie. OpenGL vidí všetky modely ako trojuholníky, preto náš prvý model bude práve trojuholník. OpenGL obsahuje mnoho pokročilých štruktúr (VAO, VBO, shadery atď ...), preto je zo začiatku aj obyčajné vykreslenie trojuholníka zložitá práca. Nakoniec zistíte, že je to naopak celkom jednoduchá záležitosť.

Shadery a dodatočný kód

Ešte pred písaním kódu si stiahnite zdrojové kódy a pridajte si k projektu nasledujúce súbory:

  • NacitacShaderu.h
  • NacitacShaderu.cpp
  • bodovy_shader.vert
  • pixelovy_shader.frag

Prvé dva súbory si rovno pridáme do projektu skrz Visual Studio a NacitacShaderu.h naincludujeme do nášho súboru z minulej lekcie:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "NacitacShaderu.h"

int main(void)
{
    // kód z předchozí lekce
}

Zvyšné súbory .vert a .frag si pridajme niekam k nášmu projektu, najlepšie ku knižnici glew32.dll.

pozn .: Shadery nemajú špecifickú príponu súboru, preto si môžete zvoliť príponu ľubovoľnú, pokojne aj .txt. Silne ale odporúčam shader súbory segregovat podľa typu, aby s nimi bolo možné rozumne pracovať.

OpenGL využíva pri vykresľovaní tzv. Shadery, čo sú programy ovplyvňujúce celý proces vykresľovanie. O shader si povieme viac v nasledujúcej lekcii. Zatiaľ nám ale stačí vedieť, že shadery sú nutné pre vykresľovanie a že budeme používať 2 hlavné typy shaderov, vrcholový (vertex) a pixelový (fragment) shader. Implementácia shaderov je v OpenGL individuálne, preto v seriáli budeme používať funkcie z NacitacShaderu.

Body trojuholníka

Presuňme sa teraz do funkcie main() pod inicializáciu GLFW a Glewe. Aby sme vykreslili trojuholník, potrebujeme k tomu súradnice jeho troch vrcholov. Prvý bod bude vľavo dole, druhý bude hore uprostred a tretí bude vpravo dole:

// inicializace GLEW a GLFW

/* GLfloat je pouze standartní float, má ale speciální deklaraci,
   aby se OpenGL vyhnulo kompilačním problémům, takto fungují i
   jiné typy */
GLfloat pole_bodu_data[] = {
    -1.0f, -1.0f, 0.0f, // první bod
    0.0f, 1.0f, 0.0f, // druhý bod
    1.0f, -1.0f, 0.0f // třetí bod
};

Body nám zodpovedajú súradniciam v našom okne podľa tvaru X, Y, Z. Súradnicu Z si necháme na hodnote 0.0f, pretože vykresľujú 2D. Teoreticky by sme si ju mohli vypustiť, ale museli by sme upraviť bodový shader.

Načítanie shaderov

Na použitie shaderov si najskôr musíme vytvoriť shader program. To sú už skompilované shadery v jednom kuse, ktoré sa nachádza na grafickej karte. Pri vykresľovanie nám stačí zvoliť daný shader program a všetky shadery k nemu pripojené sa automaticky použijú.

Najskôr si teda vytvoríme náš shader program:

GLuint shader_program = glCreateProgram(); // vytvoříme si na GPU nový shader program

OpenGL nám vráti (rovnako ako u samotných shaderov a ostatných konštrukcií) miesto na GPU, kde sa program nachádza (nemôže nám vrátiť priamy ukazovateľ, pretože GPU je iné zariadenie). Ďalej k programu pripojíme naše shadery, bodovy_shader a pixelovy_shader, ktoré rovno skompilujeme:

GLuint bodovy_shader = pripojShaderKProgramu("bodovy_shader.vert", GL_VERTEX_SHADER, shader_program); // přidáme k němu bodový shader
GLuint pixelovy_shader = pripojShaderKProgramu("pixelovy_shader.frag", GL_FRAGMENT_SHADER, shader_program); // přidáme k němu pixelový shader

Ako posledný prepojíme náš program s príslušným shaderovým procesorom a skontrolujeme prípadné chyby:

bool uspech_linkovani = napojProgram(shader_program); // připojíme program k GPU
// pokud kompilace nebo linkování shaderů selže, terminujeme program
if (bodovy_shader == 0 || pixelovy_shader == 0 || !uspech_linkovani)
{
    glfwTerminate();
    return -1;
}

Vertex Array Object a Vertex Buffer Object

Ako už bolo spomenuté, GPU (grafický procesor) je úplne iné zariadenie, preto s ním nemožno pracovať rovnako ako sa CPU (procesorom) a RAM. Naše dáta musíme najskôr odovzdať nášmu GPU do video-pamäte.

Dáta sa neskladajú iba z bodov modelu, ale aj z farieb alebo súradníc textúr. Určite by bolo vhodné, keby boli všetky dáta pohromade a všetko sa vykreslilo jedným príkazom.

VBO čiže Vertex Buffer Object je štruktúra, ktorá skladuje dáta nejakého typu. Môžu to byť napríklad body modelov (vrcholy), farby alebo súradnice textúr.

VAO čiže Vertex Array Object je štruktúra, ktorá skladuje VBO a ich nastavenie pohromade. Môžeme k nemu pripojiť treba vrcholy nášho modelu a súradnice textúr (napr. Model kríky aj s jeho textúrou), nastaviť spôsob čítania bufferov a napojiť indexy shaderov. Potom stačí pri vykresľovaní len načítať náš VAO a všetko sa vykreslí v jednom príkaze.

Ako prvý si vygenerujeme nové VAO a nastavíme ho ako aktívny:

GLuint VAO_trojuhelnik; // založíme si náš VAO pro trojúhelník
glGenVertexArrays(1, &VAO_trojuhelnik); // řekneme OpenGL ať ho vygeneruje (chceme pouze jeden)
glBindVertexArray(VAO_trojuhelnik); // nastavíme ho jako aktivní VAO

Teraz si môžeme vytvoriť VBO, do ktorého budeme kopírovať vrcholy trojuholníka:

GLuint VBO_vrcholy; // založíme si náš VBO pro vrcholy trojúhelníku
glGenBuffers(1, &VBO_vrcholy); // řekneme OpenGL ať ho vygeneruje (chceme pouze jeden)
glBindBuffer(GL_ARRAY_BUFFER, VBO_vrcholy); // připojíme ho k aktuálnímu VAO (tedy našemu trojúhelníku)
glBufferData(GL_ARRAY_BUFFER, sizeof(pole_bodu_data), pole_bodu_data, GL_STATIC_DRAW); // překopírování dat vrcholů do našeho VBO

Pred kopírovaním dát nesmieme zabudnúť na napojenie VBO k aktuálnemu VAO. Po napojení VBO môžeme dáta úspešne kopírovať. Nakoniec už len potrebujeme nastaviť formát dát:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // nastavíme správný formát dat, aby OpenGL vědělo, jak tento buffer číst
glEnableVertexAttribArray(0); // umožníme našemu shaderu používat data na indexu 0

Ako prvý hodnotu nastavíme index, na ktorom sa nachádza buffer s vrcholmi. Pre nás to bude index 0 (nemusí byť nutne 0, ale musí sa zhodovať s indexom v bodovy_shader­.vert). Dáta sú typu float, normalizovať nechceme a offset / skok je 0. Následne už musíme náš index iba zapnúť.

Pre bezpečnostné účely je dobrý postup všetky aktívne štruktúry odbindovat, aby sme sa vyhli chybám:

// pro bezpečnost musíme přepnout aktivní VBO a VAO na nulovou hodnotu
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

Všetky operácie, ktoré sme doteraz vykonali (založenie VAO / VBO, načítanie dát, kompilácie shaderov, nastavenie formátu dát ...) patrí do inicializačnú časti programu a stačí ich vykonať len raz (ak je v priebehu nebudeme upravovať). Pri ich ďalšom použití je už stačí zvoliť ako aktívny štruktúry a všetko sa vykreslí pomocou jedného príkazu. Bez použitia VAO by sa všetky nastavenia musela aplikovať pri každom vykreslovacím cyklu, čo by bolo výpočtovo neefektívne.

Vykreslenie bodov

Presuňme sa teraz do našej slučky, kam pridáme trochu vykreslovacího kódu:

while (!glfwWindowShouldClose(okno))
{
    glClearColor(0.0, 0.1, 0.0, 1.0); // nastavení barvy pozadí
    glClear(GL_COLOR_BUFFER_BIT); // vyčištění okna


    glUseProgram(shader_program); // nastavení našeho shader programu jako aktivního
    glBindVertexArray(VAO_trojuhelnik); // nastavení našeho VAO jako aktivního

    glDrawArrays(GL_TRIANGLES, 0, sizeof(pole_bodu_data) / (sizeof(float) * 3)); // vykreslení našich bodů

    // bezpečnostní "odbindování" našich shaderů a našeho trojúhelníku
    glBindVertexArray(0);
    glUseProgram(0);


    glfwSwapBuffers(okno); // OpenGL vymění buffery
    glfwPollEvents(); // získání všech eventů (stisk klávesy atd.)
}

Najskôr nastavíme náš shader program a VAO ako aktívny a spustíme vykresľovací funkciu. Tá má nastavené, že vykresľuje trojuholníky, začína na offsetu 0 a vykresľuje 3 vrcholy (vypočítali sme z veľkosti dát). Tu môžete vidieť, že nám len stačí nabindovať náš VAO a všetky jeho dáta / nastavenia sa pri vykresľovanie použijú. Nakoniec už len odbindujeme aktívnej štruktúry.

Pri ukončení nesmieme zabudnúť na vyčistenie aktuálne používaných zdrojov na GPU:

// vyčištění zdrojů a terminování GLFW
glDeleteShader(bodovy_shader);
glDeleteShader(pixelovy_shader);
glDeleteProgram(shader_program);
glDeleteBuffers(1, &VBO_vrcholy);
glDeleteVertexArrays(1, &VAO_trojuhelnik);

glfwTerminate();
return 0;

V našom prípade by sme to mohli vynechať, pretože pri ukončení programu sa všetko automaticky vyčistí. Pri väčších projektoch by to však predstavovalo veľký problém.

Konečný výstup programu by mohol vyzerať nejako takto:

Prvý trojuholník v OpenGL - OpenGL - 3D grafika v C ++

Ak vám niečo nefungovalo, zdrojové kódy sú nižšie k stiahnutiu.

V ďalšej lekcii, 3D grafika v OpenGL a C ++ - Shadery , sa pozrieme bližšie na shadery a pridáme nášmu trojuholníka farby za behu programu.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 33x (4.77 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C++

 

Predchádzajúci článok
3D grafika v OpenGL a C ++ - Vytvorenie okna
Všetky články v sekcii
OpenGL - 3D grafika v C ++
Preskočiť článok
(neodporúčame)
3D grafika v OpenGL a C ++ - Shadery
Článok pre vás napísal Richard Bleier
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Aktivity