Cześć wszystkim. The Friendly Neighborhood Roach ze swoim interesującym tutorialem pomoże Wam polepszyć swoje aplikacje. W rzeczywistości programy korzystające z OpenGL wyglądają lepiej niż normalne aplikacje, tylko że wielkim problemem z którym się nieraz spotkamy to aliasing. O tym własnie będzie ten tutorial. Kwadrat zawiera "kreseczki" które są umieszczone na przekątnych liniach w stosunku do pikseli kwadrata które widzisz na ekranie. Rozwiązanie dla tego zdarzenia nazywane jest dla tego anty aliasingiem. Antyaliasing zasłania "kreseczki" tak, aby obiekt wyglądał znacznie lepiej. Proces w którym używany jest anty aliasing nazywany jest wielowzorowością.
Pełnoekranowy Anty Aliasing ma dużo zalet. Przy nowszym sprzęcie jesteśmy zdolni uzyskać ten sam efekt. Rozszerzenie ARB_MULTISAMPLE pozwala nam na to. Każdy piksel jest wzorowany na sąsiedzie aby przedstawiac optymalny anty alias. To zatem prowadzi do spowolnienia programu.
Vid_mem = sizeof(Front_buffer) + sizeof(Back_buffer) + num_samples * (sizeof(Front_buffer) +sizeof(ZS_buffer))
Po więcej informacji zajrzyjcie pod poniższe linki:
GDC2002 -- OpenGL Wielowzorcowosc
OpenGL Formaty Fixeli i Wielowzorowosc Antialiasingu
W przeciwieństwie do innych rozszerzeń, które są związane z renderowaniem w OpenGL, rozszerzenie ARB_MULTISAMPLE musi być rozpatrywany podczas całego procesu renderowania okna. Ten proces wygląda tak:
- Stwórz normalne okno
- Podaj wartość wielowzorowego piksela (InitMultisample)
- Jeżeli wielodobieranie jest dostępne to zniszcz okno i odnów je naszym nowym formatem pikseli
- Dla anty aliasingu musimy wywołać glEnable(GL_ARB_MULTISAMPLE);
Zacznijmy omawiać kod pliku arbMultiSample.cpp. Zacznijmy od dodania bibliotek gl.h, glu.h i windows.h. O arb_multisample.h porozmawiamy później.
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "arb_multisample.h"
Druga i trzecia linia kodu określają zakres dostępu do łańcucha WGL (WGL string). Użymy je do zwiększenia cech formatu piksela do testowania naszego formatu wzorca. Dwie inne zmienne są używane do dostępu do danych.
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042
bool arbMultisampleSupported = false;
int arbMultisampleFormat = 0;
Następna funkcja o której będziemy mówić to WGLisExtensionSupported. Używana jest do uzyskania listy rozszerzeń WGL do weryfikacji jeżeli podany format jest wspierany przez system. Będziemy opisywać kod gdy do niego dojdziemy ponieważ jest to łatwiejszy sposób na wytłumaczenie poszczególnych funkcji.
NOTATKA:Kod poniżej był przepisany przez Henry Goffin. Jego aktualna wersja zawiera lepsze parsery wspierające rozszerzenia GL.
bool WGLisExtensionSupported(const char *extension)
{
const size_t extlen = strlen(extension);
const char *supported = NULL;
wglGetProcAddress("wglGetExtensionsStringARB");
if (wglGetExtString) supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());
if (supported == NULL) supported = (char*)glGetString(GL_EXTENSIONS);
if (supported ==NULL) return false;
for (const char* p = supported; ; p++)
{
p = strstr(p, extension);
if (p == NULL)
return false;
if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==''))
return true;
}
}
Następna funkcja to w istocie główny kod programu. Podstawowo, sprawdzimy czy nasze rozszerzenia arb są wspierane przez system. Potem, przejdziemy do sprawdzania naszego planu kontekstu aby znaleźć zakres naszej wielowzorcowości. Popatrzmy w kod.
bool InitMultisample(HINSTANCE hInstance, HWND hWnd,PIXELFORMATDESCRIPTOR pfd)
{
if (!WGLisExtensionSupported("WGL_ARB_multisample"))
{
arbMultisampleSupported = false;
return false;
}
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB =
(PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB");
if (!wglChoosePixelFormatARB)
{
arbMultisampleSupported=false;
return false;
}
HDC hDC = GetDC(hWnd);
int pixelFormat;
bool valid;
UINT numFormats;
float fAttributes[] = {0,0};
int iAttributes[] = { 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);
if (valid && numFormats >= 1)
{
arbMultisampleSupported=true;
arbMultisampleFormat=pixelFormat;
return arbMultisampleSupported;
}
iAttributes[19] = 2;
valid = wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
if(valid && numFormats >= 1)
{
arbMultisampleSupported=true;
arbMultisampleFormat=pixelFormat;
return arbMultisampleSupported;
}
return arbMultisampleSupported;
}
Teraz, kiedy skończyliśmy pisać nasz kod, musimy go tak skonfigurować aby wiedział co nasze kreacje w oknie będą robić. Najpierw musimy dołączyć nasz arb_multisample.f, a na koniec przesunąć prototypy destroywindow i createwindow na samą górę.
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "NeHeGL.h"
#include "ARB_MULTISAMPLE.h"
BOOL DestroyWindowGL (GL_Window* window);
BOOL CreateWindowGL (GL_Window* window);
Następny bit musi być dodany do funkcji CreateWindowsGL i kod musi zostać jeszcze trochę zmodyfikowany. Nie możemy używać formatów pikseli dopóki mamy stworzone okno, ale za to niemożemy używac obrazu FSAA dopóki nie wiemy jaki format pikseli będzie wspomagał go. Zrobimy okno, uzyskamy format pikseli, potem zniszczymy i zrobimy okno na nowo jeżeli wielowzorcowość jest wspomagana.
Proste...
window->hDC = GetDC (window->hWnd);
if (window->hDC == 0)
DestroyWindow(window->hWnd);
window->hWnd = 0;
return FALSE;
}
if(!arbMultisampleSupported)
{
PixelFormat= ChoosePixelFormat (window->hDC, &pfd);
if (PixelFormat == 0)
ReleaseDC(window->hWnd, window->hDC);
window->hDC = 0;
DestroyWindow(window->hWnd);
window->hWnd = 0;
return FALSE;
}
}
else
{
PixelFormat = arbMultisampleFormat;
}
if (SetPixelFormat(window->hDC, PixelFormat, &pfd) == FALSE)
{
ReleaseDC(window->hWnd, window->hDC);
window->hDC = 0;
DestroyWindow(window->hWnd);
window->hWnd = 0;
return FALSE;
}
Okno zostalo zrobione, wiec mamy juz potrzebny uchwyt dla Wielowzorcowego wsparcia. Jezeli znajdziemy wsparcie, zniszczymy okno, i wywolamy funkcje CreateWindowGL od nowa , tylko ze z nowym formatem pikseli.
if (wglMakeCurrent (window->hDC, window->hRC) == FALSE)
{
wglDeleteContext(window->hRC);
window->hRC = 0;
ReleaseDC(window->hWnd, window->hDC);
window->hDC = 0;
DestroyWindow(window->hWnd);
window->hWnd = 0;
return FALSE;
}
if(!arbMultisampleSupported && CHECK_FOR_MULTISAMPLE)
{
if(InitMultisample(window->init.application->hInstance,window->hWnd,pfd))
{
DestroyWindowGL (window);
return CreateWindowGL(window);
}
}
ShowWindow (window->hWnd, SW_NORMAL);
window->isVisible = TRUE;
OK, konfiguracja zakończona pomyślnie! Skonfigurowaliśmy nasz ekran tak, że teraz zezwala na odpowiednią głębie dla wielowzorowości. Teraz najlepsza część! Renderowanie sceny. Na szczęście ARB zdecydował zrobić dynamiczną wielowzorowość więc to pozwala na włączenie i wyłączenie tego przy pomocy funkcji glEnable / glDisable
glEnable(GL_MULTISAMPLE_ARB);
glDisable(GL_MULTISAMPLE_ARB);
Był to najłatwiejszy efekt rotacji do pokazania jaki znam.