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:
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áč) seznam.cz>