CZ NeHe OpenGL
Lekce 46

Lekce 46 - Fullscreenový antialiasing

Chtěli byste, aby vaše aplikace vypadaly ještě lépe než doposud? Fullscreenové vyhlazování, nazývané též multisampling, by vám mohlo pomoci. S výhodou ho používají ne-realtimové renderovací programy, nicméně s dnešním hardwarem ho můžeme dosáhnout i v reálném čase. Bohužel je implementováno pouze jako rozšíření ARB_MULTISAMPLE, které nebude pracovat, pokud ho grafická karta nepodporuje.

V tomto zajímavém tutoriálu zkusíme posunout grafický vzhled aplikací ještě dále. O antialiasingu jste už četli v minulých tutoriálech, multisampling, narozdíl od něj, neoperuje s jednotlivými objekty zvlášť, ale pracuje až s vykreslovanými pixely. Ve výsledném obrázku se pokouší najít a odstranit ostré hrany. Protože se musí vzít v úvahu každý zobrazovaný pixel, bez hardwarové akcelerace grafické karty by velice snížil výkon aplikace.

Vid_mem = sizeof(Front_buffer) + sizeof(Back_buffer) + num_samples * (sizeof(Front_buffer) +sizeof(ZS_buffer))

Pro více informací prosím zkuste tyto odkazy:

GDC2002 - OpenGL Multisample Nové okno
OpenGL Pixel Formats and Multisample Antialiasing Nové okno

Po tomto nutném úvodu se konečně můžeme pustit do práce. Narozdíl od jiných rozšíření, která OpenGL při renderingu využívá, musíme s ARB_MULTISAMPLE počítat už při vytváření okna. Postupujeme tedy následovně:

Začneme v souboru arb_multisample.cpp. Jako vždy inkludujeme hlavičkové soubory pro OpenGL a knihovnu GLU. O arb_multisample.h se budeme bavit později.

#include <windows.h>

#include <gl/gl.h>

#include <gl/glu.h>

#include "arb_multisample.h"

Symbolické konstanty použijeme při definování atributů pixel formátu. Podporuje-li grafická karta multisampling, bude logická proměnná arbMultisampleSupported obsahovat true.

#define WGL_SAMPLE_BUFFERS_ARB 0x2041// Symbolické konstanty pro multisampling

#define WGL_SAMPLES_ARB 0x2042

bool arbMultisampleSupported = false;// Je multisampling dostupný?

int arbMultisampleFormat = 0;// Formát multisamplingu

Následující funkce testuje, zda je WGL OpenGL rozšíření na systému dostupné v daném formátu.

bool WGLisExtensionSupported(const char *extension)// Je rozšíření podporováno?

{

const size_t extlen = strlen(extension);

const char *supported = NULL;

// Pokud je to možné, pokusí se wglGetExtensionStringARB použít na aktuální DC

PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");

if (wglGetExtString)// WGL OpenGL rozšíření

{

supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());

}

if (supported == NULL)// Zkusí ještě standardní OpenGL řetězec s rozšířeními

{

supported = (char*)glGetString(GL_EXTENSIONS);

}

if (supported == NULL)// Pokud selže i toto, není řetězec dostupný

{

return false;

}

for (const char* p = supported; ; p++)// Testování obsahu řetězce

{

p = strstr(p, extension);// Hledá podřetězec

if (p == NULL)// Podřetězec není v řetězci

{

return false;// Rozšíření nebylo nalezeno

}

// Okolo podřetězce se musí vyskytovat oddělovač (mezera nebo NULL)

if ((p == supported || p[-1] == ' ') && (p[extlen] == '\0' || p[extlen] == ' '))

{

return true;// Rozšíření bylo nalezeno

}

}

}

Funkce InitMultisample() je svým způsobem jádrem programu. Dotážeme se na podporu potřebného rozšíření a pokud ji máme, získáme požadovaný pixel formát.

bool InitMultisample(HINSTANCE hInstance, HWND hWnd, PIXELFORMATDESCRIPTOR pfd)// Inicializace multisamplingu

{

if (!WGLisExtensionSupported("WGL_ARB_multisample"))// Existuje řetězec ve WGL

{

arbMultisampleSupported = false;

return false;

}

PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");// Získání pixel formátu

if (!wglChoosePixelFormatARB)// Daný pixel formát není dostupný

{

arbMultisampleSupported = false;

return false;

}

HDC hDC = GetDC(hWnd);// Získání kontextu zařízení

int pixelFormat;

int valid;

UINT numFormats;

float fAttributes[] = {0, 0};

Následující pole atributů slouží pro definování vlastností pixel formátu. Všechny položky kromě WGL_SAMPLE_BUFFERS_ARB a WGL_SAMPLE_ARB jsou standardní, a proto by nám neměly činit potíže. Pokud uspěje hlavní test podpory multisamplingu, který reprezentuje wglChoosePixelFormatARB(), máme vyhráno.

int iAttributes[] =// Atributy

{

WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,

WGL_SUPPORT_OPENGL_ARB, GL_TRUE,

WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,

WGL_COLOR_BITS_ARB, 24,

WGL_ALPHA_BITS_ARB, 8,

WGL_DEPTH_BITS_ARB, 16,

WGL_STENCIL_BITS_ARB, 0,

WGL_DOUBLE_BUFFER_ARB, GL_TRUE,

WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,

WGL_SAMPLES_ARB, 4,

0, 0

};

valid = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);// Pixel formát pro čtyři vzorkování

if (valid && numFormats >= 1)// Vráceno true a počet formátů je větší než jedna

{

arbMultisampleSupported = true;

arbMultisampleFormat = pixelFormat;

return arbMultisampleSupported;

}

iAttributes[19] = 2;// Čtyři vzorkování nejsou dostupná, test dvou

valid = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);

if (valid && numFormats >= 1)

{

arbMultisampleSupported = true;

arbMultisampleFormat = pixelFormat;

return arbMultisampleSupported;

}

return arbMultisampleSupported;// Vrácení validního formátu

}

Kód pro detekci multisamplingu máme hotov, teď modifikujeme vytváření okna. Inkludujeme hlavičkový soubor arb_multisample.h a vytvoříme funkční prototypy.

#include "arb_multisample.h"// Hlavičkový soubor pro multisampling

BOOL DestroyWindowGL(GL_Window* window);// Funkční prototypy

BOOL CreateWindowGL(GL_Window* window);

Následující výpis kódu patří do funkce CreateWindowGL(). Původní kód povětšinou zůstane, ale uděláme v něm několik změn. V základu potřebujeme vyřešit problém, který spočívá v tom, že nemůžeme položit dotaz na pixel formát (detekovat přítomnost multisamplingu), dokud není vytvořeno okno. Nicméně naproti tomu nemůžeme vytvořit okno s vyhlazováním, dokud nemáme pixel formát, který ho podporuje. Trochu se to podobá otázce, zda bylo první vejce nebo slepice. Implementujeme dvouprůchodový systém - nejprve vytvoříme obyčejné okno, dotážeme se na pixel formát a pokud je multisampling podporován, zrušíme okno a vytvoříme správné. Trochu těžkopádné, ale neznám jiný způsob.

// Funkce CreateWindowGL()

window->hDC = GetDC(window->hWnd);// Grabování kontextu zařízení

if (window->hDC == 0)// Podařilo se ho získat?

{

DestroyWindow(window->hWnd);// Zrušení okna

window->hWnd = 0;// Nulování handle

return FALSE;// Neúspěch

}

Při prvním průchodu touto funkcí (další průchody např. při přepínání do/z fullscreenu) není možné multisampling natvrdo zapnout, takže jsme vytvořili pouze obyčejné okno. Pokud máme jistotu, že ho můžeme použít, nastavíme pixel formát na arbMultiSampleFormat.

if(!arbMultisampleSupported)// Multisampling není podporován

{

// Vytvoření normálního okna

PixelFormat = ChoosePixelFormat(window->hDC, &pfd);// Získá kompatibilní pixel formát

if (PixelFormat == 0)// Podařilo se ho získat?

{

ReleaseDC(window->hWnd, window->hDC);// Uvolnění kontextu zařízení

window->hDC = 0;// Nulování proměnné

DestroyWindow(window->hWnd);// Zrušení okna

window->hWnd = 0;// Nulování handle

return FALSE;// Neúspěch

}

}

else// Multisampling je podporován

{

PixelFormat = arbMultisampleFormat;

}

if (SetPixelFormat(window->hDC, PixelFormat, &pfd) == FALSE)// Zkusí nastavit pixel formát

{

ReleaseDC(window->hWnd, window->hDC);

window->hDC = 0;

DestroyWindow(window->hWnd);

window->hWnd = 0;

return FALSE;

}

window->hRC = wglCreateContext(window->hDC);// Zkusí získat rendering kontext

if (window->hRC == 0)// Podařilo se ho získat?

{

ReleaseDC(window->hWnd, window->hDC);

window->hDC = 0;

DestroyWindow(window->hWnd);

window->hWnd = 0;

return FALSE;

}

if (wglMakeCurrent(window->hDC, window->hRC) == FALSE)// Aktivuje rendering kontext

{

wglDeleteContext(window->hRC);

window->hRC = 0;

ReleaseDC(window->hWnd, window->hDC);

window->hDC = 0;

DestroyWindow(window->hWnd);

window->hWnd = 0;

return FALSE;

}

Okno bylo vytvořeno, takže máme k dispozici handle pro dotaz na multisampling. Pokud je podporován, zrušíme okno a vytvoříme ho s novým pixel formátem.

if(!arbMultisampleSupported && CHECK_FOR_MULTISAMPLE)// Je multisampling dostupný?

{

if(InitMultisample(window->init.application->hInstance, window->hWnd, pfd))// Inicializace multisamplingu

{

DestroyWindowGL(window);

return CreateWindowGL(window);

}

}

ShowWindow(window->hWnd, SW_NORMAL);// Zobrazí okno

window->isVisible = TRUE;

ReshapeGL(window->init.width, window->init.height);// Oznámí rozměry okna OpenGL

ZeroMemory(window->keys, sizeof(Keys));// Nulování pole indikující stisk kláves

window->lastTickCount = GetTickCount();// Inicializuje časovou proměnnou

return TRUE;// Vše v pořádku

}

OK, nastavování je kompletní, dostáváme se k zábavnější části, pro kterou jsme se tak snažili. Naštěstí se sdružení ARB rozhodlo učinit multisampling dynamickým, což nám ho umožňuje kdykoli zapnout nebo vypnout. Stačí jednoduché glEnable() a glDisable().

glEnable(GL_MULTISAMPLE_ARB);

// Vykreslení vyhlazovaných objektů

glDisable(GL_MULTISAMPLE_ARB);

A to je vše. Až spustíte ukázkové demo, uvidíte, jak kvalitně vyhlazování zlepšuje celkový vzhled scény.

napsal: Colt McAnlis - MainRoach <duhroach (zavináč) hotmail.com>
přeložil: Michal Turek - Woq <WOQ (zavináč) email.cz>

Zdrojové kódy

Lekce 46

<<< Lekce 45 | Lekce 47 >>>


Tento offline překladů NeHe OpenGL Tutoriálů lze volně šířit podle Obecné veřejné licence GNU Nové okno, jeho nejnovější verze je dostupná na domovském webu projektu CZ NeHe OpenGL Nové okno.

Michal Turek - Woq <WOQ (zavináč) email.cz> (24.02.2004).