Buna ziua si bine v-am gasit
la intalnirea cu grafica on-line, in OpenGL, pe Linux
Este prima intalnire de acest gen deci urmeaza sa ne organizam un pic,
cel putin in prima jumatate de ora.
PLANUL DE LUCRU:
1)
Instalarea: Aveti nevoie de un Linux (Ubuntu 18 este ok) cu instrumentele OpenGl
Teoria spune ca trebuie sa instalati:
- gl,
- glut, (freeglut)
- mesa
- si compilatorul gcc
- (eventual si un IDE) de Linux cum este Codeblocks. Desi va recomand sa lucrati in cea mai simpla maniera, cu:
- un terminal in care veti da comenzile de compilare
- si un editor de texte (Gedit, TextEditor, Kate, Kwrite, sau cele clasice in mod text: mc, nano, pico - editoare)
2) Dat fiind ca in fiecare an distributia se schimba putin, in urmatoarea jumatate de ora voi face setup-ul din nou, si va anunt ce indicatii mai sunt necesare.
3) Va trimit capitolul de manual pe e-mail.
4) Voi face o recapitulare
5) Voi comenta pe blog, a doua parte a manualului, atat cat se poate.
Nota: Aveti nevoie de acel
Manual introductiv de OpenGL de la Editura Alma Mater, editia 2014 (tradus de Dan P. - nu editia 2007) care traduce manualul spaniol, pe care vi l-am prezentat: Curso de introducción a OpenGL (v1.1).Seful de grupa a primit deja manualul pe e-mail.
ACTIVITATEA
1) Instalarea:
Ubuntu: 18.04
Incercati intai varianta:
sudo apt-get install gcc g++ codeblocks build-essential freeglut3-dev mesa-utils
O varianta minimala, in cazul in care ati programat deja cu gcc pe Linux, ar fi sa instalati:
mesa-utils si
freeglut3-dev
Dintr-un an anterior aveam o notita:
sudo apt-get install libgl1-mesa-dev freeglut3-dev messa-common-dev
(cred ca am folosit-o pentru Ubuntu 14.x sau 16.)
Fedora 25 (ar trebui s amearga si la urmatoarele):
Daca nu stiti exact numele pachetelor incercati:
yum install mesa*
yum install freeglut
2) Testarea:
Daca ati fost la orele anterioare ar trebui sa aveti setul de exemple deja lucrate:
Ar trebui sa puteti lucra, dupa codul existent, exemplele:
Exemplul 1:
Compilarea se facea cu:
gcc ex1.c -lglut -lGL -lGLU -o ex1-2020.exe
la promptul $, in directorul sursei.
Rularea se facea la acelasi prompt $:
./ex1-2020.exe
adica rulam din directorul curent outputul compilatorului.
Obs: Numele cu .exe nu este obligatoriu, am vrut sa sugerez ca este executabil, stiam ca o sa ma intrebati.
Iar sursa era:
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
/*
A. myfirstopenglprogram.c (ex1.c)
Capitolul1: Concepte fundamentale despre OpenGL
*/
/*
Am inclus doua biblioteci “gl.h” si “glut.h”.
*/
void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoarea de pefundal: negru, netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Am sters continutul din fereastra
glMatrixMode(GL_PROJECTION);
// Modul de lucru OpenGL - Proiectie
glLoadIdentity();
// Am incarcat in masina cu stiva elementul neutru la inmultirea matricelor
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
// Spatiu de vizualizat in proiectie "ortographica", este un cub
glMatrixMode(GL_MODELVIEW);
// Modul de lucru OpenGl - Model pt a fi vazut
// Vom incepe desenarea - punctele vor semnifica triunghiuri
glBegin(GL_TRIANGLES);
// Dand trei puncte desenam un triunghi
glColor3f(1.0,0.0,0.0);
// Dam intai culoarea primului varf:rosu
glVertex3f(0.0,0.8,0.0);
// si coordonatele sale
glColor3f(0.0,1.0,0.0);
// Dam apoi culoarea varfului al II-lea :verde
glVertex3f(-0.6,-0.2,0.0);
// si coordonatele varfului
glColor3f(0.0,0.0,1.0);
// Dam apoi culoarea varfului al III-lea :albastru
glVertex3f(0.6,-0.2,0.0);
// si coordonatele varfului
glEnd();
// Terminam seria de date destinate desenului
glFlush();
// Impunem procesarea lor
sleep(10);
// Asteptam 10 secunde
exit(0);
// Oprim programul,dupa aceste 10 secunde.
}
int main(int argc, char ** argv)
{
glutInit(&argc,argv);
// Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
// Display-ul va functiona single-buffer si pe culori RGBA
glutInitWindowPosition(20,20);
// Fereastra va fi fixata cu coltul stang in pct. 20,20
glutInitWindowSize(500,500);
// Si va avea dimensiunea 500 x 500
glutCreateWindow("Ex1.c"); //in loc de argv[0]
// La crearea ferestrei se specifica si titlul
glutDisplayFunc(display);
// Comunicam OpenGL-ului ce functie display sa foloseasca
glutMainLoop();
return 0;
}
/* sleep cere <unistd.h> pe Unix.
radacina@computer:~/practica/opengl$ gcc ex1.c -lglut -lGL -lGLU -o ex1.exe
radacina@computer:~/practica/opengl$ ./ex1.exe
radacina@computer:~/practica/opengl$
*/
Explicatiile s-au dat la intalnirea precedenta.
Exemplul Nr 2:
Este din Cap 3.5.2, Afisarea in perspectiva, si reprezinta ... oare ce ?
Sursa:
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
/*
A.b quadortho.c (ex2.c)
Am inclus doua biblioteci “gl.h” si “glut.h”.
*/
void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
// Spatiul e proiectat orthografic, in cubul specificat
glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL la definirea modelelor
/*
Aici vom descrie modelele intre GLBegin si GLEnd.
*/
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
// Coordonatele celui de-al patrulea varf (superior-dreapta)
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam 10 secunde
exit(0);
// Oprim programul.
}
int main(int argc, char ** argv)
{
glutInit(&argc,argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex2.c"); //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex2.c -lglut -lGL -lGLU -o ex2.exe
radacina@computer:~/practica/opengl$ ./ex2.exe
radacina@computer:~/practica/opengl$
*/
Desenati dvs un cub, ca la geometrie, in jurul axelor XOY, atat in partea cu plus cat si in cea cu minus. (-0,5 , +0,5) sunt pe fiecare axa. Coordonatele le luati din cod !
Marcati pe cub cele patru varfuri si directia de privire, axa OZ.
Ati remarcat ca patrulaterul este de fapt un dreptunghi, avand o latura mai aproape de observator si una mai departe ?
Intrebare de control: Care este mai aproape, cea de sus sau cea de jos ?
Chestia se vede daca activati proiectia perspectiva, vedeti codul modificat:
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
/*
A.c quadpersp.c (ex3.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
*/
void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate
// Dar nu se va vedea nimic din aceasta perspectiva -> Ex4.c
gluPerspective(60.0,1.0,1.0,100.0);
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0
glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL in modul: reprezentare modele
/*
Aici vom descrie modelele intre GLBegin si GLEnd.
*/
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
// Coordonatele celui de-al patrulea varf (superior-dreapta)
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam 10 secunde
exit(0);
// Oprim programul.
}
int main(int argc, char * argv)
{
glutInit(&argc,&argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex3.c"); //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex3.c -lglut -lGL -lGLU -o ex3.exe
radacina@computer:~/practica/opengl$ ./ex3.exe
radacina@computer:~/practica/opengl$
Tema: Explicati de ce nu se vede nimic ! Unde e patratul si unde este
trunchiul de piramida al spatiului proiectat, vizibil noua ?
*/
Atentie la compilarea acestui exemplu, este necesar sa aveti toate cele trei biblioteci in linia de comanada specificate:
Totusi ati vazut ca nu se vede nimic cand rulam programul:
Ceea ce se intampla din cauza faptului ca suntem in origine, chiar in planul prin care trece dreptunghiul, dar daca ne dam doua unitati mai in spate, iata:
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
/*
A.c quadpersp.c (ex4.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
*/
void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate
// Dar nu se va vedea nimic din aceasta perspectiva
gluPerspective(60.0,1.0,1.0,100.0);
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0
glTranslatef(0.0,0.0,-2.0);
// Ne dam inapoi doi pasi, adica supunem pozitia observatorului,
// (a aparatului sau foto) unei translatii pe axa z cu -2.0 unitati.
glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL in modul: reprezentare modele
/*
Aici vom descrie modelele intre GLBegin si GLEnd.
*/
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
// Coordonatele celui de-al patrulea varf (superior-dreapta)
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam 10 secunde
exit(0);
// Oprim programul.
}
int main(int argc, char * argv)
{
glutInit(&argc,&argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex4.c"); //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex4.c -lglut -lGL -lGLU -o ex4.exe
radacina@computer:~/practica/opengl$ ./ex4.exe
radacina@computer:~/practica/opengl$
*/
De data aceasta se vede in perspectiva:
Capitolul 3.5.3 Suprapunerea obiectelor si asanumitul Z-buffer.
Daca adaugam un triunghi, care ar trebui sa se intersecteze cu patrulaterul constatam ca totusi OpenGl le deseneaza unul peste altul, cel putin cu setarile curente:
Iata un exemplu cu setarile curente:
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
/*
A.e simpleguy.c (ex5.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
Am corectat ! DEPTH
*/
void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //!
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate
gluPerspective(60.0,1.0,1.0,100.0);
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0
glTranslatef(0.0,0.0,-2.0);
// Ne dam inapoi doi pasi, adica supunem pozitia observatorului,
// (a aparatului sau foto) unei translatii pe axa z cu -2.0 unitati.
glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL in modul: reprezentare modele
// Inainte de desenare adaugam
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0);
// Aici am adaugat triunghul tricolor intre GLBegin si GLEnd.
// Vom incepe desenarea - punctele vor semnifica triunghiuri
glBegin(GL_TRIANGLES);
// Dand trei puncte desenam un triunghi
glColor3f(1.0,0.0,0.0);
// Dam intai culoarea primului varf:rosu
glVertex3f(0.0,0.8,0.0);
// si coordonatele sale
//glColor3f(0.0,1.0,0.0);
// Dam apoi culoarea varfului al II-lea :verde
glVertex3f(-0.6,-0.2,0.0);
// si coordonatele varfului
//glColor3f(0.0,0.0,1.0);
// Dam apoi culoarea varfului al III-lea :albastru
glVertex3f(0.6,-0.2,0.0);
// si coordonatele varfului
glEnd();
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena patrat(e) in sens antiorar.@, nn. este doar o conventie.
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-2.5); //-1.5); //-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,-1.5); //-0.5); //0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,-1.5); //-0.5); //0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-2.5); //-1.5); //-0.5);
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam 10 secunde
exit(0);
// Oprim programul.
}
int main(int argc, char * argv)
{
glutInit(&argc,&argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA| GLUT_DEPTH); //!
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex5.c"); //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex5.c -lglut -lGL -lGLU -o ex5.exe
radacina@computer:~/practica/opengl$ ./ex5.exe
radacina@computer:~/practica/opengl$
*/
Imagine cu poligoanele suprapuse incorect din cauza neactivarii optiunii Z-Buffer:
Si acum o varianta corecta, in care Z-Bufferul fiind activat, se vad cele doua poligoane intrepatrunse:
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
/*
A.d zbuffer-yes.c (ex5v2.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
*/
void display(void)
{
// Activam Z-Buffer-ul pt ordonarea in perspectiva
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0);
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Golim atat buffer-ul de culori cat si Z-Buffer-ul
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0,0.0,-2.0);
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
glEnd();
// Terminarea definirii punctelor de sprijin
// Acum desenam alt triunghi care "inteapa" patratul
glBegin(GL_TRIANGLES);
glColor3f(1.0,0.0,0.0);
glVertex3f(0.0,0.5,0.0);
glVertex3f(-0.7,-0.5,0.0);
glVertex3f(0.7,-0.5,0.0);
glEnd();
glFlush();
sleep(20);
exit(0);
}
int main(int argc, char * argv)
{
glutInit(&argc,&argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); //Cerem si adancime
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex5v2.c");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex5v2.c -lglut -lGL -lGLU -o ex5v2.exe
radacina@computer:~/practica/opengl$ ./ex5v2.exe
radacina@computer:~/practica/opengl$
*/
Imagine cu Z-Buffer activat! Acum fragmentele sunt corect desenate si impresia este de poligoane care se inteapa.
In capitolul 3.5.4 este vorba de ierarhii de componente grafice.
Ideea esentiala este ca pentru a desena ceva, (exemplul clasic este o mana de robot) sau un arbore cu ramificatii, sau o piesa pe care sunt montate alte piese, sau o mina marina, sau un coronavirus,
ei bine,
se deseneaza piesa centrala cu reperul mutat in centrul ei,
se face un PushMatrix pt a salva matricea transformarii
se muta reperul in centrul primului subansablu (deget, etc)
(ceea ce poate presupune translatie dar si rotatie )
se deeneaza acel deget / piesa cu tot ce are el
se face un PopMatrix pt a reveni la reperul din centrul piesei de baza.
si se continua cu al doilea deget / varf / subansamblu.
In final se revine la reperul initial, al centrului piesei de baza.
Iata un exemplu de cod cu o ierarhie 2D , de patrate:
Si codul pentru crearea ei:
#include "GL/glut.h"
//A.f jerarquia-cuadro.c (ex6.c)
void desenarePatrat(float lat)
{
glBegin(GL_QUADS);
glVertex3f(-lat/2.0,lat/2.0,0.0);
glVertex3f(-lat/2.0,-lat/2.0,0.0);
glVertex3f(lat/2.0,-lat/2.0,0.0);
glVertex3f(lat/2.0,lat/2.0,0.0);
glEnd();
}
void display()
{
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-6.0);
glColor4f(1.0,0.0,0.0,1.0);
desenarePatrat(1.0);
glPushMatrix();
glTranslatef(0.0, 2.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glPushMatrix();glTranslatef(0.0, -2.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glPushMatrix();glTranslatef(2.0, 0.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glPushMatrix();glTranslatef(-2.0, 0.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc,argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex6.c");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex6.c -lglut -lGL -lGLU -o ex6.exe
radacina@computer:~/practica/opengl$ ./ex6.exe
radacina@computer:~/practica/opengl$
*/
Pauza s-a terminat.
Exercitiu de control:
Desenati, dupa aceleasi reguli, o mana cu 5 degete diferit colorate, in 2D, de
aceasta forma, v-o desenez in stil ASCII ART:
---------------------------------------------------------------------------
| | |
- ----------------------------------
| | |
- ----------------------------------
| | |
- ----------------------------------
| | |
---------------------------------------------------------------------------
| |
------------------------------------
3) Seful de grupa a primit deja manualul pe e-mail. Scrieti la adresa autorului blog-ului pentru a-l primi si dumneavoastra.
In acest moment va fac o selectie de pagini de manual , de la acest capitol incolo , e vorba de paginile 33-75. Nu include explicatiile de la prima intalnire, dar aveti pagina de blog, aceasta.
In final setul dvs de materiale va include cel putin:
- Aceasta pagina de blog: video4linux.blogspot.com - Pagina intitulata Grafica - IFR
- Selectia din manual cu pg 35-75,123
- Codurile sursa din editia spaniola.
- Manualul tiparit de la Alma Mater, tradus de Dan P.
- Alte carti de Open Gl: RedBook, OrangeBook
Ok, aveti 10 minute pauza de cafea si ca sa examinati materialele trimise,
continuam dupa pauza de la capitolul 3.5.4
3.5.4 Ierarhii
Cititi va rog din materialul trimis pe e-mail (OpenGLv12-[pg1-6,33-75,123].pdf)
inceputul capitolului 3.5.4 pina la:
void desenarePatrat(float lat)
{
glBegin(GL_QUADS);
glVertex3f(lat/2.0,lat/2.0,0.0);
glVertex3f(lat/2.0,lat/2.0,0.0);
glVertex3f(lat/2.0,lat/2.0,0.0);
glVertex3f(lat/2.0,lat/2.0,0.0);
glEnd(); }
Si treceti la pg -35- fizica, pg 9 in e-bookul selectie. Aveti aici o selectie din codul de mai sus.Desenarea decurge in felul urmator,
[
atentie, in editia electronica a draftului cartii pe care ati primit-o este o greseala de tipar (-2.0 boldit, sunt doar 2.0 -uri), corectati, ce gasiti -2.0 bold mai jos:]
- primul apel al functiei desenarePatrat() deseneaza patratul central:
glLoadIdentity();
glTranslatef(0.0,0.0,6.0);
glColor4f(1.0,0.0,0.0,1.0);
desenarePatrat(1.0); <- deseneaza patratul central
- Acum se salveaza matricea !
glPushMatrix();
<-- Acum se salveaza matricea !
- si acum ne deplasa me axa Y in sus
glTranslatef(0.0, 2.0, 0.0);
<- si acum ne deplasa pe axa Y in sus
desenarePatrat(0.5);
<- deseneaza patratul
glPopMatrix();
<- revenim la reperul initial
glPushMatrix();
glTranslatef(0.0,
-2.0, 0.0);
<- si acum ne deplasa pe axa Y in jos
desenarePatrat(0.5);
<- deseneaza patratul
glPopMatrix();
<- revenim la reperul initial
glPushMatrix();
glTranslatef(2.0, 0.0, 0.0);
<- si acum ne deplasa pe axa X la dreapta
desenarePatrat(0.5);
<- deseneaza patratul
glPopMatrix();
<- revenim la reperul initial
...
glPushMatrix();
<- si acum ne deplasa pe axa X la stanga
glTranslatef(
-2.0, 0.0, 0.0);
<- deseneaza patratul
desenarePatrat(0.5);
<- revenim
glPopMatrix();
...
glFlush();
Folositi aceeasi idee pentru rezolvarea exercitiului anterior.
Imaginea 3.15, cu ierarhia fractala, pg -36-, explicatii:
In anumite sitiuatii in care ceea ce vrem sa desenam este un fractal, o structura arborescenta in care substructurile sunt asemenea cu piesa de baza, subrutina care deseneaza sub-componentele , componentele subordonate - se apeleaza pe ea insasi in mod recursiv.
Se pot desena astfel: copaci, plante, (uneori cladiri - rar), nori, pietre, munti, valuri (rar). Pentru detalii cautati fractali. Cu exceptia unor fractali speciali, o mare parte dintre ei pot fi desenati cu astfel de functii recursive - si ma refer aici la fractalii autoasemenea.
In imagine: Exemplu de copac fractal, vom reveni la el, va fi un viitor exercitiu pentru dvs.
Totusi autorul manualului si al setului initial de exemple opteaza pentru o ierarhie de patrate 2D, recursiva, pe aceeasi idee a fractalului.
- In loc de un trunchi de planta paralelipipedic in 3D pune un patrat in 2D,
- in loc de cele 4 ramuri 3D (paralelipipezi articulati pe mijloacele laturilor de sus, in repere rotite) pune cele 4 patrate 2D mai mici,
ideea este insa aceeasi.
De data aceasta mergem mai departe... cu desenarea recursiva, astfel incat sa ajungem la acest fel de imagine:
Cdul sursa este:
#include <GL/gl.h>
#include <GL/glut.h>
// A.g jerarquia-cuadro-recursivo.c (ex6v2.c)
void desenarePatrat(float lat)
{
glBegin(GL_QUADS);
glVertex3f(-lat/2.0,lat/2.0,0.0);
glVertex3f(-lat/2.0,-lat/2.0,0.0);
glVertex3f(lat/2.0,-lat/2.0,0.0);
glVertex3f(lat/2.0,lat/2.0,0.0);
glEnd();
}
void desenarePatrateRecursive(float lat)
{
if (lat > 0.005)
{
desenarePatrat(lat);
glPushMatrix();
glTranslatef(0.0, lat * 2.0, 0.0);
desenarePatrateRecursive(lat / 2.0);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0, -lat * 2.0, 0.0);
desenarePatrateRecursive(lat / 2.0);
glPopMatrix();
glPushMatrix();
glTranslatef(lat * 2.0, 0.0, 0.0);
desenarePatrateRecursive(lat / 2.0);
glPopMatrix();
glPushMatrix();
glTranslatef(-lat * 2.0, 0.0, 0.0);
desenarePatrateRecursive(lat / 2.0);
glPopMatrix();
}
}
void display()
{
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-6.0);
glColor4f(1.0,0.0,0.0,1.0);
desenarePatrateRecursive(1.0);
glFlush();
}
int main(int argc, char *argv)
{
glutInit(&argc,&argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex6v2.c");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex6v2.c -lglut -lGL -lGLU -o ex6v2.exe
radacina@computer:~/practica/opengl$ ./ex6v2.exe
radacina@computer:~/practica/opengl$
*/
Exercitiul nr 2: Transformati acest cod in codul care sa deseneze un copac asa cum este cel din imaginea de mai sus.
Indicatii: Aveti nevoie de o subrutina pt desenat cubul, care prin scalare va deveni un paralelipiped.
Puteti stabili niste constante pt dim tulpinii:
#define TULP_HEIGHT 20
#define TULP_WIDTH 2
#define TULP_DEPTH 2
Asa se deseneaza cubul in OpenGL, folosind o functie GLUT:
void desenareCub(float lat)
{
glPushMatrix();
glScalef(TULP_WIDTH,TULP_DEPTH,TULP_HEIGHT);
glutSolidCube(lat);
glPopMatrix();
}
Ne vom uita in perspectiva , in directia copacului nostru:
gluPerspective(60.0,1.0,1.0,100.0);
glTranslatef(0.0,0.0,-1.6*TULP_HEIGHT);
gluLookAt(0,0,0, TULP_HEIGHT,TULP_HEIGHT,TULP_HEIGHT,0.0,0.0,1.0);
Vom folosi desenareCub pentru a desena paralelipipedul initial:
(in reper scalat insa, dar de asta se ocupa desenareCub() !):
glColor4f(0.2,0.8,0.0,0.0);
desenareCub(1.0);
Si apoi ne ducem in partea de sus a tulpinii, pe un mijloc de latura, rotim reperul, ne ducem pe "oblica" pina la jumatatea ramurii (sfertul tulpinii) cu o translatie si desenam "cubul" pardon, ramura, la scara 1/2.
glPushMatrix(); //sus
glTranslatef(0.0, TULP_DEPTH/2, TULP_HEIGHT/2);
glRotatef(-35.0, 1.0, 0.0, 0.0);
glTranslatef(0.0,0.0, TULP_HEIGHT/4);
desenareCub(0.5);
glPopMatrix();
Si asemanator se procedeaza pentru toate cele 4 ramuri. pentru aceasta nu v-ar strica niste manuale ale API-urilor OpenGL si GLUT, cum este
The OpenGL Utility Toolkit (GLUT),Programming Interface,API Version 3,Mark J. Kilgard,Silicon Graphics, Inc.
In orice caz caz va trebuie niste carti in care sa gasiti toti parametrii acestor functii.
Succes!
Pauza ...
Exemplul numarul 7, umanoidul colorat: pg -36- -37- -38- -39-
Sursa este, in editia spaniola, in anexa: simpleguy.c la pagina 73, pdf -ul in spaniola.
Exercitiu: Printati pe o foaie A4 imaginea de mai sus la scara mare, cat foaia,
si desenati pe ea, sub forma de vectori -----> cum se misca originea sistemului de coordonate, si sub forma de unghiuri
/|
/ |
-30 grade
sau
|\
| \
30 grade
felul cum se misca prin rotire reperul.
Nota: La acel popMatrix de dupa scalare, bineinteles ca reperul revine la norml, de exemplu se restaureaza si dimensiunile vectorilor unitate.
Fotografiati foaia cu desenul si trimiteti-o.
Capitolul al 4-lea: Animatii [pg -40- -> pg 46]
Se ocupa cu animatia... cititi va rog capitolul al 4-lea. Programul va anima o sfera aflata in interiorul uni cub. Programul este facut in maniera poo in C++, deoarece mai tarziu vom anima mai multe sfere.
Sfera e definita astfel:
/////////////////////////////////////////////////////////
// Ex8: Fisierul sphere.h
/////////////////////////////////////////////////////////
#ifndef sphere_h
#define sphere_h
#include <stdlib.h>
#include <time.h>
#include <math.h>
typedef
class TSphere
{
private:
float maxpos;
float pos[3];
float dir[3];
float speed;
public:
TSphere(float maxpos, float speed);
void test();
void modifySpeed(float inc);
float * getPosv();
} TSphere;
#endif
Si este implementata astfel:
/////////////////////////////////////////////////////////
// Fisierul sphere.cpp
/////////////////////////////////////////////////////////
#include "sphere.h"
int pass=0;
TSphere::TSphere(float maxpos, float speed)
{
this->maxpos = maxpos;
if (!pass)
{
srandom(time(NULL));
pass = 1;
}
pos[0] = (random() % (int)maxpos) - maxpos/2;
pos[1] = (random() % (int)maxpos) - maxpos/2;
pos[2] = (random() % (int)maxpos) - maxpos/2;
dir[0] = random();
dir[1] = random();
dir[2] = random();
float dirmod = sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]);
dir[0] /= dirmod;
dir[1] /= dirmod;
dir[2] /= dirmod;
dir[0] *= speed;
dir[1] *= speed;
dir[2] *= speed;
}
void TSphere::test()
{
((pos[0] < -maxpos) || (pos[0] > maxpos))?dir[0]*=-1:0;
((pos[1] < -maxpos) || (pos[1] > maxpos))?dir[1]*=-1:0;
((pos[2] < -maxpos) || (pos[2] > maxpos))?dir[2]*=-1:0;
pos[0] += dir[0];
pos[1] += dir[1];
pos[2] += dir[2];
}
void TSphere::modifySpeed(float inc)
{
float factor = (speed+inc)/speed;
speed += inc;
dir[0] *= factor;
dir[1] *= factor;
dir[2] *= factor;
}
float * TSphere::getPosv()
{
return pos;
}
Remarcati ca asa este implementata doar geometria si miscarea sferei, pe o directie aleatoare normalizata. De asemenea , sfera se va misca intre niste limite maxpos, -maxpos pe toate directiile, adica intr-un cub. Iar daca iese din cubul acesta i se schimba ca semn vectorul de viteza, pe componenta aceea, ca sa reintre in cub.
Programul principal este acesta:
/////////////////////////////////////////////////////////
// Fisierul Ex8.cpp
/////////////////////////////////////////////////////////
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
#include "sphere.h"
float * pos;
TSphere * sphere = NULL;
void initgl()
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.0,0.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Folosind proiectia orthografica sau o...
glOrtho(-12.0,12.0,-12.0,12.0,-30.0,30.0);
// gluPerspective(60.0,1.0,1.0,100.0);
// ...proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0
sphere = new TSphere(5,0.1);
glMatrixMode(GL_MODELVIEW);
gluLookAt(3,3,14,0,0,0,0,1,0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
glutWireCube(10);
glPushMatrix();
glColor3f(0.0,0.0,1.0);
pos = sphere->getPosv(); // afla parametrii sferei
glTranslatef(pos[0],pos[1],pos[2]); // aplica o translatie
glutSolidSphere(1,10,10); // o deseneaza acolo
glPopMatrix();
glFlush();
}
void idle(void)
{
sphere->test();
usleep(33);
glutPostRedisplay();
}
int main(int argc, char ** argv)
{
glutInit(&argc,argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex8.cpp");
initgl();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}
// De notat si faptul ca programul nu are functie care sa faca
// redimensionarea ferestrei (pastrand forma cubului)
/* Ubuntu 14.04 (aprox)
Compilati cu:
radacina@computer:~/practica/opengl$ gcc -c sphere.cpp
radacina@computer:~/practica/opengl$ gcc -c Ex8.cpp
radacina@computer:~/practica/opengl$ gcc -o Ex8.exe Ex8.o sphere.o -lglut -lGL -lGLU
radacina@computer:~/practica/opengl$ ./Ex8.exe
*/
/*
Ubuntu 18.04
matlab@computer66:~/!practica cu cartev5/opengl/Ex8$ g++ -c Ex8.cpp
matlab@computer66:~/!practica cu cartev5/opengl/Ex8$ g++ -c sphere.cpp
matlab@computer66:~/!practica cu cartev5/opengl/Ex8$ g++ -o Ex8.exe Ex8.o sphere.o -lglut -lGL -lGLU
*/
Dar fiind C++ va trebui sa il compilati cu g++
Directorul meu cu fisiere arata asa:
Iar app. in executie arata asa:
Bineinteles ca bila se va misca, ceea ce nu se vede in imagine.
Cap 4.2. desenarea cu doua buffere. pg -45-
Exercitiu: Verificati daca programul de mai sus lucreaza cu doua buffere si in caz contrar faceti modificarile necesare.
Cum se vede deosebirea pe un display LCD ?
Exercitiu: Modificati programul astfel incat sa anime mai multe sfere ca in Fig 4.5
Indicatie: Modificati call-back-ul, functia, display() al OpenGl-ului.
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0); // alb = rosu + verde + albastru
glutWireCube(10);
for (int i=0;i<NUM_SPHERES;i++)
{
glPushMatrix();
glColor3f(0.0,0.0,1.0);
pos = sphere[i]->getPosv();
glTranslatef(pos[0],pos[1],pos[2]);
glutSolidSphere(SPHERE_RADIUS,10,10);
glPopMatrix();
sphere[i]->test();
}
glFlush();
glutSwapBuffers();
}
Constantele trebuiesc definite inainte:
#define NUM_SPHERES 55
#define SPHERE_RADIUS 0.4
Si nu uitati modificarile din paragraful 4.2.
Capitolul al 5-lea : Lumina , pg -47-
Incepeti sa cititi de la pg -47- incolo ...deocamdata pina la pagina 54, paragraful 5.1.3
In principiu,pe partea de lumina, OpenGl este un calculator vectorial al vectorilor de culoare a luminii care vin pe anumite directii, de la anumite surse, se reflecta, geometric sau difuz, totul intr-un mediu care are implicit o constanta (a anumita lumina) in toate punctele - lumina de culoarea umbrei.
Ca efect sunt 4 feluri de lumina:
- ambietala: lumina de la umbra, cea care, ca in Biblie, a facut-o Dzeu sa umple spatiul, si ea nu provenea de la luminatori (soare luna si alte surse de lumina), care atunci, spune legenda, nu existau inca.
- emisa: lumina venita de la sursele de lumina, indiferent ce lumini sunt in jur, sursele emit lumina lor proprie
- speculara: lumina care se reflecta ca la geometrie, raza incidenta si cea care pleaca sunt in acelasi plan, la unghi eglal. Asa se reflecta lumina in oglinzi, pe suprafete metalice lustruite.
- difuza: lumina care se reflecta dar in toate directiile, difuz, nu formeaza imagine in oglinda.
5.1.2 Materiale.
Veti gasi in alte colectii de exemple OpenGL si exemple cu materiale de culori diferite. Nu sunt inclus aici.
5.1.3Normala la suprafata este importanta. Schimbarea directiei ei provoaca o schimbare de efect de culoare, un fel de falsa texturare, fiindca lumina se va reflecta in raport cu normala perturbata.
Vom reveni la exemplul numarul 11a.
Ex11a.c
// EX11A.c - normals-perp.c ok
#include <GL/glut.h>
#include <stdlib.h>
#include <unistd.h> // <- Ubunt 18, pentru functia sleep
#define SINGLE_NORMAL //comentati linia
void display(void)
{
GLfloat mat_color [] = {0.0,1.0,1.0,1.0};
GLfloat light_color [] = {1.0,1.0,1.0,1.0};
GLfloat light_ambient [] = {0.0,0.0,0.0,1.0};
GLfloat normal [] = {0.0,1.0,0.0};
GLfloat light_dir [] = {0.0,1.0,0.0,0.0};
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_color);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_color);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_color);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(-0.3,-0.6,-4.0);
glLightfv(GL_LIGHT0,GL_POSITION,light_dir);
glBegin(GL_QUADS);
glVertex3f(-1.0,0.0,-1.0);
#ifdef SINGLE_NORMAL
glNormal3fv(normal);
#else
glNormal3f(1.0,1.0,-1.0);
#endif
glVertex3f(-1.0,0.0,1.0);
glNormal3fv(normal);
glVertex3f(1.0,0.0,1.0);
#ifdef SINGLE_NORMAL
glNormal3fv(normal);
#else
glNormal3f(-1.0,1.0,-1.0);
#endif
glNormal3fv(normal);
glVertex3f(1.0,0.0,-1.0);
glEnd();
glFlush();
sleep(20);
exit(0);
}
int main(int argc, char ** argv)
{
glutInit(&argc,argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc ex11a.c -lglut -lGL -lGLU -o ex11a.exe
*/
Observati perturbarea, fata de o suprafata uniform colorata.
Dar pentru ca in acest exemplu apar deja mai multe notiuni despre iluminat, cititi va rog:
Capitolul 5.2 Utilizarea luminilor: pg -49-
... va las timp sa il cititi !
Sa rezumam cateva chestiuni:
- Iluminatul ca si alte optiuni OpenGl se activeaza: glEnable(GL_LIGHTING
).
- Numarul de surse de lumina e o putere a lui doi, initial a fost 2 la a 3-a = 8
- Fiecare sursa de lumina se va seta separat folosind un apel glLight*() unde * indica o continuare a numelui functiei care ne sufla cu ce tip de argumente lucram, de exemplu:
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_color);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_color);
...
glLightfv(GL_LIGHT0,GL_POSITION,light_dir);
- Functiile glLight*() sunt un fel de atribuiri de parametri care descriu o sursa de lumina: primul argument este indica, sursa (aici sursa 0), al doilea spune
carei variabile a sursei ii setam valoarea, abia al treilea argument e valoarea.
- Pozitionarea sursei de lumina presupune setarea valorii pentru "variabila" (ganditi "atributul") GL_POSITION al sursei de lumina.
glLightfv(GL_LIGHT0,GL_POSITION,light_dir);
- In cazul spoturilor care arunca un con de lumina din focar (lumina focala-le-am zis noi), folosim doua informatii, vectorul 3D al directiei (val_prt aici) si unghiul conului de lumina emis:
glLightfv(GL_LIGHTn,GL_SPOT_DIRECTION,val_prt);
glLightf(GL_LIGHTn,GL_SPOT_CUTOFF,val);
- Un vector 3D cu 4 componente,cum e bineinteles val_prt si alti vectori se defineste dinainte cam asa:
GLfloat val_prt [] = {0.0, 1.0, 0.0, 0.0};
Vedeti la pg -52- alte exemple de parametri:
- GL_SPOT_EXPONENT - pt atenuarea luminii - valoarea setata e un coef
- GL_AMBIENT - valoarea setata e un vector de culori
- GL_DIFUSE - valoarea setata e un vector de culori
- GL_SPECULAR - valoarea setata e un vector de culori
(pentru aceste trei tipuri de componente ale unei lumini)
- GL_CONSTANT
- GL_LINEAR
- GL_QUADRATIC
Acestia din urma modifica felul cum se atenueaza lumina in ceata. Ar mai fi multe de spus aici.
- Aprinderea luminii cu numarul n:
glEnable(GL_LIGHTn);
Exercitiu: In codul de mai sus, comentati toate instructiunile, fiecare pe un rand separat, folosind explicatiile din capitolul 5.2.1. Trimiteti pe e-mail fisierul de mai sus cu (ex11a.c) cu tot cu comentarii.
Exercitiu:
Rulati varianta "sphere-rebotes-multi.c", cu tot cu setari de iluminat si cu culori.Va arata asa:
Cap 5.2.2. Materiale
Cititi ceva despre materiale, de aici dar si din alte carti de OpenGL!
Cap 5.2.3 Iluminarea directa pe o suprafata
Abia aici este exemplul Ex11a.c de mai inainte, cu toate explicatiile.
Daca nu ati facut exercitiul anterior, cu comentarea ex11a.c, puteti lua cu copy -paste din carte tot subcapitolul si sa il transformati intr-un exemplu comentat.
Cap 5.2.4 Miscarea unei surse in jurul unei sfere
Veti scrie un program in care conul se invarte in jurul sferei si animatia este de tip dual-buffer.
Codul este:
//Ex10.c - A.k lit-sphere.c
#include <GL/glut.h>
#include <unistd.h>
#define ROT_INC 1.0
float light_ambient [] = {0.0,0.2,0.0,1.0};
float light_diffuse_specular [] = {0.8,0.8,0.8,1.0};
float light_pos [] = {0.0,0.0,2.0,1.0};
float spot_dir [] = {0.0,0.0,-1.0};
float spot_cutoff = 30.0;
float spot_exponent = 1.0;
float mat_ambient_diffuse [] = {0.0,0.8,1.0,1.0};
float mat_specular [] = {0.7,0.0,0.0,1.0};
float mat_emission [] = {0.0,0.0,0.0,1.0};
float mat_shininess = 0.4;
float focus_emission [] = {0.8,0.8,0.8,1.0};
float rot_angle_y = 0.0;
float rot_angle_x = 0.0;
void initgl()
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.0,0.0,0.0,0.0);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_FALSE);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse_specular);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_diffuse_specular);
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,spot_cutoff);
glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,spot_exponent);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_ambient_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialf(GL_FRONT,GL_SHININESS,mat_shininess);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0,0.0,-5.0);
}
void idle(void)
{
rot_angle_y = (rot_angle_y > 360.0)?0:rot_angle_y + ROT_INC;
rot_angle_x = (rot_angle_x > 360.0)?0:rot_angle_x + ROT_INC/(2*3.1416);
glutPostRedisplay();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(30.0,0.0,0.0,1.0);
glRotatef(rot_angle_y,0.0,1.0,0.0);
glRotatef(rot_angle_x,1.0,0.0,0.0);
glLightfv(GL_LIGHT0,GL_POSITION,light_pos);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spot_dir);
glTranslatef(light_pos[0],light_pos[1],light_pos[2]);
glColorMaterial(GL_FRONT,GL_EMISSION);
glEnable(GL_COLOR_MATERIAL);
glColor4fv(focus_emission);
glutSolidCone(0.2,0.5,7,7);
glColor4fv(mat_emission);
glDisable(GL_COLOR_MATERIAL);
glPopMatrix();
glutSolidSphere(1.0,20,20);
glFlush();
glutSwapBuffers();
}
int main(int argc, char ** argv)
{
glutInit(&argc,argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(20,20);
glutInitWindowSize(350,350);
glutCreateWindow(argv[0]);
initgl();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}
// Compilati cu:
// radacina@computer:~/practica/opengl$ gcc Ex10.c -lglut -lGL -lGLU -o Ex10.exe
// Apoi: radacina@computer:~/practica/opengl$ ./Ex10.exe
Explicatii: Pg -56- pina la -59-.
De citit explicatiile, de scris un fisier de cod completat cu comentarii.
Cap 6. Texturi, pg -63- pina la -pg 70-
Trebuie sa ne grabim, citit-l dvs.
Nota: Coordonatele unei texturi sunt numite coordonate (u,v) spre deosebire de cele (x,y,z) ale spatiului si sunt intr-un reper:
-|------------------->
| O u
|
|
\|/
v
Pentru a rula exemplul cu aplicarea texturii aveti nevoie si de ... texturi si de programul GIMP (www.gimp.org) care poate salva fisierele grafice sub forma de surse C.
bricktexture.png
grasstexture.png
Toate, inclusiv imaginea capturata dintr-un vechi joc video, se pot extrage sub Linux din fisierul .pdf al manualului spaniol.
game.png, (salvati-o in formatul C cu GIMP).
Atentie: Acest exemplu cu texturi are nevoie de o optiune speciala la compilatorul gcc: -trigraphs
Linia de comanda ar putea fi:
gcc ex11.c -lglut -lGL -lGLU -o ex11-2020.exe -trigraphs
Codul sursa, atentie, aveti nevoie si de fisierul "textura1.c", obtinut cu GIMP, prin salvarea texturii sa zicem
game.png in format .c
//Ex11: normals-perp-texture.c nt
#include <GL/glut.h>
#include <stdlib.h>
#include <unistd.h>
//88
//dupa
//Curso de introducción a OpenGL (v1.1)
#include "textura1.c"
void display(void)
{
GLfloat mat_color [] = {0.5,1.0,1.0,1.0};
GLfloat light_color [] = {1.0,1.0,1.0,1.0};
GLfloat light_ambient [] = {0.2,0.2,0.2,1.0};
GLfloat normal [] = {0.0,1.0,0.0};
GLfloat light_dir [] = {0.0,1.0,0.0,0.0};
int texture;
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D,texture);
//Aici puteti folosi GL_REPLACE sau GL_MODULATE
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// Comentati aceasta linie --^ si decomentati-o pe cea similara,
// care urmeaza atunci cand vreti sa folositi GL_REPLACE--v
//glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
gluBuild2DMipmaps( GL_TEXTURE_2D, gimp_image.bytes_per_pixel,
gimp_image.width, gimp_image.height,GL_RGB, GL_UNSIGNED_BYTE,
gimp_image.pixel_data );
glEnable(GL_TEXTURE_2D);
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_color);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_color);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_color);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(-0.3,-0.6,-4.0);
glRotatef(90.0,1.0,0.0,0.0);
glLightfv(GL_LIGHT0,GL_POSITION,light_dir);
glBegin(GL_QUADS);
glNormal3f(1.0,-1.0,1.0);
glTexCoord2d(0.0,0.0);
glVertex3f(-1.5,0.0,-1.5);
glNormal3fv(normal);
glTexCoord2d(0.0,1.0);
glVertex3f(-1.5,0.0,1.5);
glNormal3f(1.0,-1.0,1.0);
glTexCoord2d(1.0,1.0);
glVertex3f(1.5,0.0,1.5);
glNormal3fv(normal);
glTexCoord2d(1.0,0.0);
glVertex3f(1.5,0.0,-1.5);
glEnd();
glFlush();
sleep(20);
exit(0);
}
int main(int argc, char ** argv)
{
glutInit(&argc,argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(350,350);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/* Fisierul cu imaginea cere o optiune speciala: -trigraphs
radacina@computer:~/practica/opengl$ gcc Ex11.c -lglut -lGL -lGLU -o Ex11.exe -trigraphs
radacina@computer:~/practica/opengl$ ./Ex11.exe
*/
Iar la executie, daca totul merge bine, textura ajunge in fereastra:
Exercitiu: Dimensiunile nu corespund, faceti ca textura sa incapa exact in fereastra.
Cap 6.2 Multiplicarea unei texturi
Atunci cand multiplicam o textura, efectul in prim plan poate fi deranjant.
Codul:
// Ex12-texture-no-clamp.c + texture-yes-clamp.c
#include <unistd.h>
#include <GL/glut.h>
// Cele doua fisiere de inclus contin si
// datele care descriu imaginea texturilor
// precum si declaratiile structurilor
// formatelor de date
// asa cum le salveaza in format .c GIMP-ul
#include "grass_texture.c"
//Dupa exportul din GIMP in format .c
// editati fisierul obtinut si inlocuiti
/* gimp_image -> grass_texture */
#include "brick_texture.c"
//Dupa exportul din GIMP in format c.
//editati fisierul obtinut si inlocuiti
/* gimp_image -> brick_texture */
void display(void)
{
int texture_floor;
int texture_wall;
glGenTextures(1,&texture_floor);
glBindTexture(GL_TEXTURE_2D,texture_floor);
gluBuild2DMipmaps( GL_TEXTURE_2D,grass_texture.bytes_per_pixel,
grass_texture.width,grass_texture.height,GL_RGB, GL_UNSIGNED_BYTE,
grass_texture.pixel_data );
glGenTextures(1,&texture_wall);
glBindTexture(GL_TEXTURE_2D,texture_wall);
gluBuild2DMipmaps( GL_TEXTURE_2D,brick_texture.bytes_per_pixel,
brick_texture.width,brick_texture.height,GL_RGB, GL_UNSIGNED_BYTE,
brick_texture.pixel_data );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// In cazul cand nu doriti sa se repete textura, comentati
// aceste doua linii cu GL_REPEAT iar mai jos dati numerele necesare
// pentru a preciza de cate ori sa se repete texturile
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
glEnable(GL_TEXTURE_2D);
glClearColor(0.1,0.6,1.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(-0.0,3.0,6.0,0.0,2.0,0.0,0.0,1.0,0.0);
// In cazul in care nu cereti sa se repete textura de pe
// intervalul 0 .. 1 (schimbati 6 cu 1 in glTextCoord2d).
glBindTexture(GL_TEXTURE_2D,texture_floor);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(0.0,1.0); // 1<->6
glVertex3f(-6.0,0.0,6.0);
glTexCoord2d(1.0,1.0); // 1<->6
glVertex3f(6.0,0.0,6.0);
glTexCoord2d(1.0,0.0); // 1<->6
glVertex3f(6.0,0.0,-6.0);
glEnd();
// In cazul cand nu cereti sistemului sa repete textura de pe
// intervalul 0..1 (schimbati 3 cu 1 in glTexCoord2d).
glBindTexture(GL_TEXTURE_2D,texture_wall);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,4.0,-6.0);
glTexCoord2d(0.0,1.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(1.0,1.0); // 1<->3
glVertex3f(6.0,0.0,-6.0);
glTexCoord2d(1.0,0.0); // 1<->3
glVertex3f(6.0,4.0,-6.0);
glEnd();
glFlush();
sleep(20);
exit(0);
}
int main(int argc, char ** argv)
{
glutInit(&argc,argv); // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(300,300);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
/*
radacina@computer:~/practica/opengl$ gcc Ex12.c -lglut -lGL -lGLU -o Ex12.exe -trigraphs
radacina@computer:~/practica/opengl$ ./Ex12.exe
*/
Folositi modificarile indicate la pagina -69- si pg -70-, pentru a elimina efectul deranjant. Pe cod sunt indicate ca schimbari 1 <->6.
Ar trebui sa obtineti nu o textura expandata de 6x4 = 24 de ori ci aceeasi textura, plasata de 24 de ori, ca 24 de piese de gresie cu desen similar.
Efectul vizual este altul:
In imagine textura ierbii de jos este multiplicata!
Pauza...
Urmeaza:
Cap 7: Bazele comunicarii cu GLUT.
Va rog sa il cititi dvs. si sa rulati programul dat ca exemplu.
Miscati conul de lumina prin rotatii in jurul axei x si in jurul axei y cu ajutorul tastelor cu sageti.
Rotiti conul in jurul sferei folosind tasetel cu sageti.
Ce ati mai putea face in continuare, daca sunteti pasionati de grafica.
1) Cititi o carte romaneasca despre OpenGL
2) Lucrati dupa RedBook
3) Eventual lucrati dupa OrangeBook
4) Studiati OpenGLES, exista o carte buna, "OpenGL ES Programming Guide" de Aaftab Munsh ,Dan Ginsburg, Dave Shreiner la editura Addison Wesley, au aparut si alte editii mai noi 2.0, 3.0 etc
5) Unii vor dori sa se apuce de Vulkan, dar atentie, este un API de nivel inferior, si desi ruleaza si pe Linux si pe Windows cantitatea de cod care se scrie pentru niste programe simple este proportional mai mare. Am fost surprins cate linii de cod mi-au trebuit ca sa obtin un cib texturat cu sigla Vulkan.
6) Urmariti revistele de specialitate. SIGGRAF.
7) Treceti la niste medii de dezvoltare care se bazeaza pe OpenGL, cum sunt Unity 3D, Unreal Engine etc.
8) Treceti pe la Khronos Ag.
Sunt enorm de multe resurse si continuari in zona graficii, ceea ce ati vazut aici este doar un curs introductiv. La ora actuala se folosesc foarte mult modele 3D obtinute cu diferite tehnologii si incarcate ca atare in software.
Sfarsit. Deocamdata.
Weekend placut !
Nota: Toate exemplele comentate in limba romana sunt sub licenta libera Creative Common Non Comercial. Au fost stranse intr-un volum in limba spaniola de Jorge García.