Na emailu se mi některé, většinou začátečnické, dotazy neustále opakují, jako příklad lze uvést problémy s knihovnou GLAUX a symbolickou konstantou CDS_FULLSCREEN v Dev-C++. Doufám, že tato stránka trochu sníží zatížení, ale pokud si stále nevíte rady, nebojte se mi napsat. Doufám, že nebude vadit, když sem umístím i ten váš problém.
Znalý programátor by vám s největší pravděpodobností odpověděl, že se jedná o standard popisující API (aplikační programové rozhraní) mezi programem a hardwarem grafické karty. Já se pokusím o trochu pochopitelnější vysvětlení. Určitě jste už viděli nějakou 3D akční hru (např. Quake, Unreal Tournament...), ve které se lze pohybovat do jakéhokoli směru (nahoru, dolů, doleva, doprava, dopředu, dozadu). OpenGL, velice zjednodušeně řečeno, zajišťuje rendering (vykreslení) těchto 3D objektů na 2D monitor a dále se stará o spoustu dalších věcí, které byste ale na tomto místě stejně nepochopili...
Začněte například u článku Pomoc, začínám, určitě v něm naleznete odpověď.
OpenGL s největší pravděpodobností neběží na hardwaru grafické karty, ale emuluje se softwarově. Zkuste nainstalovat/přeinstalovat ovladače grafické karty. Mimochodem, nespoléhejte na to, že jsou v systému, když jde nastavit libovolné rozlišení a barevnou hloubku (ano, i ve Win XP). Instalace v Linuxu.
Nezapomněli jste ho zapnout pomocí funkce glEnable()? Grrrr!!! Klid, mě se to stává taky :-)
Ano, místo glColor3f() - hodnoty od 0.0f do 1.0f - zavolejte glColor3ub(). Unsigned Byte může nabývat hodnot od 0 do 255, na tato čísla jste asi zvyklí více a pravděpodobně to bude i rychlejší (o málo, ale přece :-)...
Tato dvě čísla označují x, y pozici na textuře - 0.0f je levý/spodní okraj, 1.0f určuje pravý/horní okraj a čísla mezi specifikují jinou pozici (např. 0.5f polovina textury). Nemusí se však zadávat pouze hodnoty v intervalu od 0.0f do 1.0f. Předání větších čísel vytvoří "dlaždicový" efekt - jako když si dáte v OS na plochu obrázek 50x50 pixelů vedle sebe. Např. číslo 10.0f způsobí namapování dané textury 10x přes celou šířku polygonu.
Problémem je, že i kdybychom ignorovali natočení scény a podobné věci naprosto nepřenositelné ze 3D do 2D, perspektivní korekce způsobí, že se bude velikost objektů v závislosti na hloubce měnit. Samozřejmě lze použít různé přepočítávací funkce (gluProject() a gluUnProject()), které konvertují pixelové souřadnice v okně na OpenGL jednotky a naopak, ale až budete dělat v OpenGL trochu déle, zjistíte, že ve většině případů nic takového vůbec nepotřebujete.
Pokusím se o modelovou situaci. Programujeme klasický 3D automobilový simulátor, ve kterém se může hráč dívat z pohledu řidiče, z kamery umístěné nahoře za autem, popř. z dynamicky přesunované kamery vedle cesty. Budeme zmenšovat/zvětšovat všechny objekty podle zvoleného pohledu a vymýšlet 3 různé funkce pro rendering? Samozřejmě, že ne. Hlavní trik spočívá v tom, že ve všech třech pohledech vykreslíme vše naprosto stejně, ale před samotným vykreslením změníme pozici kamery a úhel pohledu - nic víc, nic míň. Řekněme, že závodní dráha zabírá plochu 1000 jednotek s maximálním převýšením 30 jednotek. Stromy jsou vysoké 3 až 5 jednotek a modely závodních aut mají délku 1 jednotku - nejsou důležité konkrétní velikosti, ale poměr mezi nimi. S těmito znalostmi můžeme bez problémů vykreslit scénu, o nějaké pohledy se vůbec nemusíme starat. Změnu pohledu pak provedeme zavoláním funkcí glTranslatef(), glRotatef(), popř. gluLookAt() před samotným vykreslením. Doufám, že je to pochopitelné.
Abych se ale vrátil k původní otázce, perspektivní zmenšování objektů lze eliminovat použitím pravoúhlé (=kolmé) projekce. S výhodou se jí využívá např. u výpisu textů (u nich najdete i implementaci v programu). Postup spočívá v nahrazení gluPerspective() za funkci glOrtho(), které se předávají požadované rozměry 2D scény. Při přesunech objektu do hloubky budou jeho rozměry při pravoúhlé projekci vždy stejné. A ještě malá poznámka na závěr: pokud nepředáte glOrtho() aktuální rozměry viewportu, ale konstantní hodnoty např. 1000x1000, při změně jeho velikosti se relativní poloha vykreslovaného objektu nezmění. Z toho vyplývá, že po zvětšení okna ze 640x480 na 1600x1200 bude objekt "uprostřed" opravdu "uprostřed" a ne v levé části.
OpenGL 2D grafiku přímo nepodporuje, ale místo 3D glVertex3f(x, y, z) lze používat její 2D variantu glVertex2f(x, y) - za z souřadnici se automaticky dosadí 0, ale na pozadí se defakto jedná stále o 3D. Pokud budou vadit "bezrozměrné" OpenGL jednotky a perspektiva, je možné se přepnout do pravoúhlé projekce (NeHe Tutoriály 17, 21, 24 atd.), kde lze nastavit zadávání souřadnic v pixelech.
Blitter a spol., co vím, OpenGL přímo nepodporuje (update: glDrawPixels(), glReadPixels(), glCopyPixels() atd.), ale naprogramovat si ho není zase až tak těžké (NeHe 29). Abych to shrnul, s klasickou 2D grafikou je v OpenGL trochu problém, protože bez grafického akcelerátoru se hra (většinou se jedná o hry :) nepohne z místa, nicméně samo o sobě má také spoustu vychytávek. Například perfektně vypadají klasické 2D rovinné hry, ve kterých jsou všechny objekty i prostředí trojrozměrné (ale na ploše, v konstantní hloubce).
V tomto tutoriálu se začínají používat textury, pro jejichž nahrávání je potřeba knihovna GLAUX. Tato knihovna je docela zastaralá, a proto se k některým kompilátorům standardně nepřibaluje a obecně se ji nedoporučuje používat. Asi nejjednodušší řešení je stáhnout si ji v downloadu, dále můžete zkusit nahrát obrázek jinou knihovnou (např. SDL_Image - nutný projekt v SDL a ne ve Win API) nebo si napsat vlastní nahrávací kód (např. formát TGA byl vysvětlen v tut. 24, tut. 33).
Některé kompilátory a vývojová prostředí, mezi nimi právě Dev-C++, symbolickou konstantu CDS_FULLSCREEN automaticky nedefinují. Problém vyřešíte ručním nadefinováním, mělo by stačit něco takového:
#ifndef CDS_FULLSCREEN// Některé kompilátory nedefinují CDS_FULLSCREEN
#define CDS_FULLSCREEN 4// Ruční nadefinování
#endif
Zkuste článek Načítání .3DS modelů...
napsal: Michal Turek - Woq <WOQ (zavináč) seznam.cz>, 15.08.2004