Curs 2

Biblioteci grafice

La crearea diverselor programe de grafică 2D sau 3D se pot folosi obiecte proprii limbajelor sau mediilor de programare (unde se crează aceste programe). Prin schimbarea sistemului de operare sau a limbajului/mediului de programare utilizat trebuia ca programul să fie rescris. Pentru ca această activitate să fie mai uşoară s-au propus diverse colecţii de funcţii (proceduri) care se pot apela pentru realizarea de desene. Aceste funcţii au fost incluse în biblioteci grafice. Pentru diversele sisteme de operare şi limbaje de programere trebuie ca aceste biblioteci să fie implementate.
Dintre aceste biblioteci amintim:

OpenGL (Open Graphics Library)

Folosire OpenGL în Java

Posibilităţi de folosire (unele dintre proiectele următoare nu se mai dezvoltă):

JOGL

JOGL are adresa de start (pagina pe internet) Java Binding for the OpenGL® API.
JOGL constituie o interfaţă pentru execuţia comenzilor (instrucţiunilor) OpenGL.
Există mai multe versiuni de utilizare (instalare). In continuare (anul univ. 2010/2011) se va face referire la versiunea (stabilă) 1.2.
Paşi la instalare: Obs. Fişierul Get started with JOGL.doc conţine instrucţiuni de utilizare pentru JOGL
La adresa Jogl - User's Guide se precizează unele informaţii privind utilizarea JOGL.

Cerinţe în programe java

  1. Se includ pachetele necesare din jogl. Clasele utile pentru execuţia comenzilor din OpenGL sunt implementate în mai multe pachete. Descrierea acestor pachete şi clasele incluse în ele se află în documentaţia amintită. In funcţie de clasele care sunt utile în aplicaţie, se importă pachetele care le conţin, de exemplu:
    import javax.media.opengl.*;
    import javax.media.opengl.glu.*;
    
  2. Pentru a realiza desene cu OpenGL este necesară implementarea interfeţei GLAutoDrawable. Sunt puse la dispoziţie două clase ce implementează această interfaţă:
    javax.media.opengl.GLCanvas
    javax.media.opengl.GLJPanel
    
    In interfaţa aplicaţiei utilizator se include un obiect ce instanţiază una dintre aceste clase. De exemplu, dacă "d" este un obiect ce instanţiază clasa GLCanvas (în acest obiect se vor face desenele de către OpenGl), atunci sunt necesare instrucţiunile:
    GLCanvas d = new GLCanvas();    //crearea unui obiect GLCanvas (unde se fac desenele cu OpenGL)
    add(d);                         //adaugarea acestui obiect la interfata
    
  3. Desenarea în acest obiect (control) se face prin evenimentul GLEvent (care apare la obiectul unde se face desenarea de către OpenGL). Obiectul care tratează evenimentul GLEvent se obţine prin implementarea unei clase utilizator ce instanţiază interfaţa GLEventListener. In această interfaţă apar metodele cu ajutorul cărora se pot face desene: init, display, reshape, displayChanged.
    Aceste patru metode, din interfaţa care trebuie implementată, au următoarea semnificaţie:
  4. Se crează un obiect corespunzător clasei utilizator ce implementează interfaţa GLEventListener, şi se precizează că acest obiect va trata evenimentul GLEvent, de exemplu:
    ClasaGLEvent ob = new ClasaGLEvent();
    d.addGLEventListener(ob);
    
In continuare se dă un program minimal, fără desenare, care utilizează OpenGL:
import java.awt.*;
import java.awt.event.*;

import javax.media.opengl.*;

public class exemplu extends Frame {
    
  public exemplu(){
    super("Aplicatie cu OpenGL");
    //aici nu s-au precizat dimensiunile interfetei
    GLCanvas d = new GLCanvas();    //crearea unui obiect unde se fac desenele cu OpenGL
    add(d);                         //adaugarea acestui obiect la interfata

    d.addGLEventListener(new Desenare());  
    //obiectul care va face desenarea se adauga (ca si consumator pt. evenimentul GLEvent) la obiectul unde se face desenarea 
    
    addWindowListener(new WindowAdapter (){
      public void windowClosing(WindowEvent e) {
        // Terminare program
        System.exit(0);
      }
    });
    setVisible(true);
  }
  
  public static void main (String args[])
     {exemplu f =  new exemplu();
     }

  public class Desenare implements GLEventListener {
    //clasa utilizator unde se precizeaza efectiv desenarea
    public void init(GLAutoDrawable drawable) {}
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
    public void display(GLAutoDrawable drawable) {}
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
  }
}
Observaţie: La adresa NetBeans OpenGL Pack se descrie un pachet care permite folosirea facilităţilor OpenGL în mediul NetBeans. Inceput

OpenGL - generalităţi

The OpenGL Programming Guide - The Redbook. The OpenGL Programming Guide, 5th Edition. The Official Guide to Learning OpenGL Version 2.1

Tipuri de date folosite în OpenGL

In OpenGL se folosesc multe constante şi comenzi (funcţii) de desenare. Constantele au prefixul "GL_", iar comenzile au, în general, formatul "glNumeCompletare(lista_parametri)". Partea de "completare" poate avea 1,2,3 sau 4 caractere:
Exemple:
glVertex2i(1,2);
glVertex3f(1.0f,10.5f,20.0f);

Multe dintre comenzile OpenGL au formate diferite, de exemplu: glVertex2f, glVertex3i, glVertex4dv, etc., diferenţierea dintre ele se face prin tipul argumentelor.

Activare/dezactivare facilităţi OpenGL

Există foarte multe facilităţi ale pachetului OpenGL (facilităţi precizate prin constante) care pot fi activate (se folosesc resurse suplimentare) sau dezactivate. Comenzile corespunzătoare sunt:

Buffere în OpenGL

Pentru realizarea desenelor în OpenGL se folosesc mai multe buffere (zone de memorie), dintre care amintim: Pentru ştergerea unui buffer se foloseşte comanda:
glClear(buffer)
Pentru ştergerea bufferului de culoare se foloseşte o culoare (va fi culoarea de fond pentru zona de desenare) care se precizează prin comanda:
glClearColor(red,green,blue,alpha)
unde valorile argumentelor sunt în intervalul [0,1] şi generează o culoare.

Execuţia comenzilor de desenare

Comenzile (funcţiile) de desenare din OpenGL sunt implementate în clasele:
Aceste obiecte se crează în cadrul uneia din metodele interfeţei GLEventListener. Crearea se face astfel:
GL gl = drawable.getGL();
unde drawable este obiectul precizat în metodele interfeţei GLEventListener (obiectul este precizat ca argument la aceste metode);
GLU glu = new GLU();
Funcţiile de desenare se folosesc prin intermediul acestor obiecte, de exemplu:
gl.Color3f(0.0f,0.5f,0.5f);

Culoare curentă

La precizarea unui punct dintr-o primitivă de desenare se ia în considerare o "culoare curentă". Precizarea acestei culori se face astfel:
glColor3{b|s|i|f|d|ub|us|ui}(r,g,b);
glColor4{b|s|i|f|d|ub|us|ui}(r,g,b,a);
Pentru argumente de tipul f sau d valorile argumentelor sunt în intervalul [0,1]. Pentru alte tipuri de valori se face conversia la valori din acest interval (valoarea maximă posibilă pentru argument corespunde la valoarea 1).

Precizarea unui vârf

Un vârf dintr-o primitivă de desenare se precizează astfel:
glVertex{2|3|4}{b|s|i|f|d|ub|us|ui}[v](coordonate)
Cu două dimensiuni se presupune că valoarea z=0, iar cu 4 valori se precizează coordonatele omogene.

Precizarea obiectelor grafice

Inceput

Proiecţie

Pentru desenare se foloseşte un tip de proiecţie şi o poziţie a observatorului în spaţiu. Deoarece execuţia fiecărei primitive de desenare generează imediat acţiuni de desenare, este necesar ca proiecţia să fie precizată înaintea apelării primitivelor de desenare.
Pentru a preciza matricea de proiecţie se folosesc comenzile amintite la descrierea matricei curente a modelului: glLoadIdentity, glLoadMatrix, glTranslate, glScale, glRotate, glMultMatrix. Aceste comenzi înmultesc o matrice curentă de proiecţie cu o matrice dedusă sau precizată de comenzi. Precizarea faptului că transformarea se face pentru matricea de proiecţie se face prin comanda:
glMatrixMode(GL_PROJECTION)
Această matrice curentă se poate încărca cu matricea unitate, cu o matrice oarecare, sau se poate înmulţi cu o matrice generată de o comandă de transformare particulară.

Proiecţia paralelă

Acest tip de proiecţie se precizează prin comanda:
glOrtho(GLdouble left, GLdouble right, GLdouble bottom, .GLdouble top, GLdouble near, GLdouble far)
Observatorul se presupune în origine, direcţia de observare este oz', iar argumentele din comandă se deduc din imaginea următoare:

Pentru ca obiectele din scena 3D să poată fi vizualizate, este necesar ca ele să fie aduse (prin translaţie, rotaţie, etc.) în "volumul de vedere".

Proiecţia centrală

Acest tip de proiecţie se precizează prin comanda:
gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far)
Si aici se consideră că observatorul este în origine şi direcţia de observare este oz'. Argumentele din comandă au semnificaţia din figura următoare.

Proiecţia centrală se poate preciza şi prin comanda:
glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
unde observatorul şi direcţia de observare este aceeaşi ca la comanda precedentă, iar argumentele au semnificaţia dedusă din imaginea următoare:

Precizarea poziţiei observatorului

Cu una din comenzile anterioare se precizează un tip de proiecţie şi volumul de vedere, care generează o matrice cu care se înmulţeşte matricea curentă de proiectie. Se pot face transformări astfel încât obiectele care se desenează să fie aduse în volumul de vedere, sau se poate deplasa observatorul la o poziţe în spaţiu. A doua variantă se poate preciza prin comanda:
gluLookAt(x0,y0,z0,xc,yc,zc,upx,upy,upz)
Această comandă precizeaza că observatorul se află în (x0,y0,z0), priveşte în punctul (xc,yc,zc), iar în planul de proiecţie verticală este dată de vectorul (upx,upy,upz). Matricea de proiecţie curentă se înmulţeste la dreapta cu matricea determinată de această comandă.

Inceput

Referinţe:

Inceput