Vykreslení trojúhelníku pomocí OpenGL

V této kapitole vykreslíme barevný trojúhelník pomocí OpenGL v Javě s využitím JOGL. Budeme potřebovat Javu ve verzi 1.5 a vyšší a JOGL ve verzi 1.1 a vyšší. Programovat je možné v libovolném textovém editoru, ale s ohledem na budoucí ukázky je výhodnější použít Eclipse nebo podobný IDE, protože doplní automaticky potřebné importy apod. Pro bezproblémovou přenositelnost mezi platformami je výhodné používat UTF-8 pro kódování všech souborů, pokud chceme používat české popisky.

Program se skládá ze dvou tříd. Klientská třída Lesson je společná pro všechny kapitoly. Mění se pouze titulek okna. Pomocí této třídy se spouští celý program, obsahuje metodu main(). Druhou třídou je Renderer, která definuje výslednou vyrenderovanou scénu a v tomto příkladu navíc ještě obsluhuje stisky kláves.

Po spuštění níže uvedeného kódu uvidíte okno, jako je na následujícím obrázku.

Výsledný trojúhelník
Výsledný trojúhelník

Třída Lesson

Obsahuje statickou metodu main(), vytváří swingový JFrame, na který je umístěn canvas (kreslící plátno pro OpenGL renderování) a spouští Animator, aby se automaticky překreslovala scéna.

public class Lesson extends JFrame

{

GLCanvas canvas = new GLCanvas();

Animator animator = new Animator();

 

public static void main(String[] args)

{

new Lesson();

}

 

public Lesson()

{

canvas.addGLEventListener(new Renderer());

 

animator.add(canvas);

 

this.getContentPane().add(canvas);

this.setTitle("Lekce 1: Vytvoření OpenGL okna");

this.setSize(640, 480);

this.setLocationRelativeTo(null);

 

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.setVisible(true);

 

animator.start();

canvas.requestFocus();

}

}

Třída Renderer

Implementuje GLEventListener pro řešení událostí OpenGL a KeyListener pro obsluhu stisků kláves. V této třídě je definována celá scéna, která se renderuje. Metoda display() definuje co, je bude vykreslovat a je automaticky volána třídou Animator, ostatní metody slouží k nastavení scény.

Importujeme GL, což je základní rozhraní pro zpřístupnění funkcí z OpenGL verze 2.0. GLAutoDrawable vychází z GLDrawable, který slouží k renderování scén, ale podporuje vykreslování pomocí událostí, což přispívá k vyššímu výkonu. GLU se využívá k nastavení pohledu.

public class Renderer implements GLEventListener, KeyListener

{

private GLU glu = new GLU();

private GL gl;

Metodu display() volá Animator pro zobrazení každého framu, definuje se tu celá scéna, která se má vykreslovat. V této kapitole se smaže obrazovka s hloubkovým bufferem, resetuje matice a posune se scéna o -2,75 ve směru osy Z (do hloubky). Posunutí je nutné, protože rovina znear je ve vzdálenosti 1 a trojúhelník by nebyl zobrazen, viz níže.

public void display(GLAutoDrawable gLDrawable)

{

gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

gl.glLoadIdentity();

 

gl.glTranslatef(0f, 0.0f, -2.75f);

Na začátku vykreslování si volíme, jaké útvary chceme kreslit. Na výběr máme z několika základních geometrických útvarů, které jsou zobrazeny na obrázcích a popsány v tabulce. Na první pohled jde pouze o 2D útvary, ale souřadnice každého vrcholu obsahují i složku Z.

GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP GL_TRIANGLES
GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP GL_TRIANGLES
GL_TRAINGLE_STRIP GL_TRAINGLE_FAN GL_QUADS GL_QUAD_STRIP GL_POLYGON
GL_TRAINGLE_STRIP GL_TRAINGLE_FAN GL_QUADS GL_QUAD_STRIP GL_POLYGON
GL_POINTS Každý vertex je reprezentovaný jako samostatný bod.
GL_LINES Každý pár po sobě jdoucích vertexů definuje úsečku.
GL_LINE_STRIP Spojí po sobě jdoucí vertexy v lomenou čáru.
GL_LINE_LOOP Stejně jako GL_LINE_STRIP spojuje po sobě jdoucí vertexy, ale navíc ještě spojí první a poslední bod.
GL_TRIANGLES Každá trojice po sobě jdoucích vertexů definuje trojúhelník.
GL_TRIANGLE_STRIP První tři vertexy definují jeden trojúhelník, každý další bod definuje nový trojúhelník s využitím předchozích dvou vertexů jako vrcholy.
GL_TRIANGLE_FAN Podobně jako GL_TRIANGLE_STRIP, všechny trojúhelníky využívají první vertex jako jeden svůj vrchol, druhý vrchol je předchozí vrchol.
GL_QUADS Každá čtveřice vertexů definuje čtyřúhelník.
GL_QUAD_STRIP První čtyři vertexy definují jeden čtyřúhelník a každé další dva vertexy definují nový čtyřúhelník, který využívá předchozí dva vertexy.
GL_POLYGON Jako GL_LINE_LOOP, ale s vyplněnou plochou.

Na začátku vykreslování nastavíme kreslení trojúhelníků pomocí GL_TRIANGLES. Pak pro každý bod specifikujeme barvu vrcholu a jeho souřadnici v prostoru. Barva je reprezentována jako třísložkový vektor, kde jednotlivé složky odpovídají červené, zelené a modré barvě. Hodnoty jsou v intervalu <0; 1>. Souřadnice bodu v prostoru jsou reprezentovány obvyklým způsobem (X, Y, Z). Kreslení se nesmí zapomenout ukončit.

gl.glBegin(GL.GL_TRIANGLES);

gl.glColor3d(1.0, 0.0, 0.0);

gl.glVertex3f(0.0f, 1.0f, 0.0f);

gl.glColor3d(0.0, 1.0, 0.0);

gl.glVertex3f(-1.0f, -1.0f, 0.0f);

gl.glColor3d(0.0, 0.0, 1.0);

gl.glVertex3f(1.0f, -1.0f, 0.0f);

gl.glEnd();

}

Metoda displayChanged() není nyní v JOGL implementována. V budoucnu se bude volat při změně barevné hloubky nebo připojení dalšího monitoru, atd. Metodu je nutné implementovat, protože je definována v rozhraní GLEventListener.

public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged, boolean deviceChanged)

{

}

Metoda init() se volá bezprostředně po vytvoření OpenGL okna, je vhodná pro nastavení základních parametrů vykreslování apod. V této kapitole se vytváří přístup k OpenGL, nastavuje barva pozadí (černá) a přidává třída, která bude obsluhovat stisky kláves. Barva pozadí je reprezentována jako čtyřsložkový vektor, kde první tři hodnoty určují barvu a čtvrtá hodnota určuje průhlednost, u barvy pozadí na nastavení průhlednosti nezáleží.

public void init(GLAutoDrawable gLDrawable)

{

this.gl = gLDrawable.getGL();

gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

gLDrawable.addKeyListener(this);

}

Metoda reshape() je zavolána při změně velikosti okna a při prvním vykreslením, protože je nutné, aby se nastavil perspektivní pohled podle aktuální velikosti okna.

public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height)

{

if (height <= 0)

height = 1;

 

final float h = (float)width / (float)height;

gl.glViewport(0, 0, width, height);

Matice GL_PROJECTION ovlivňuje jak výrazná bude perspektiva, tj. jak moc se budou vzdálenější objekty zmenšovat. Metodou gluPerspective se nastavuje pohledová pyramida (viz následující obrázek), která v tomto případě svírá úhel 45°, závisí na výšce a šířce okna, ořezávací rovina znear je ve vzdálenosti 1 a zfar 20 na ose Z. Hodnota znear by neměla nabývat 0, protože pak se mohou vyskytnout z důvodu zaokrouhlovacích chyb problémy s viditelností. Přepnutí na matici GL_MODELVIEW oznamuje, že forma pohledu bude změněna, glLoadIdentity opět resetuje matici.

gl.glMatrixMode(GL.GL_PROJECTION);

gl.glLoadIdentity();

glu.gluPerspective(45.0f, h, 1.0, 20.0);

gl.glMatrixMode(GL.GL_MODELVIEW);

gl.glLoadIdentity();

}

Pohledová pyramida
Pohledová pyramida

Metoda keyPressed() je zavolána, když uživatel stiskne klávesu. Pokud stiskne Escape, aplikace se ukončí. Metody keyReleased() a keyTyped() jsou prázdné, ale musí být implementovány, aby byla implementace korektní.

public void keyPressed(KeyEvent e)

{

if (e.getKeyCode() == KeyEvent.VK_ESCAPE)

System.exit(0);

}

 

public void keyReleased(KeyEvent e) {}

 

public void keyTyped(KeyEvent e) {}

}