Changes between Version 9 and Version 10 of opengl-intro
- Timestamp:
- Feb 13, 2009, 5:09:32 PM (16 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
opengl-intro
v9 v10 294 294 okenskega sistema. Ker imamo v našem primeru le enostaven izris, 295 295 smo se odločili le za en slikovni pomnilnik 296 (''GLUT \_SINGLE''), ki je primeren le za statične slike. Za296 (''GLUT_SINGLE''), ki je primeren le za statične slike. Za 297 297 aplikacije pri katerih se vsebina zaslona pogosto spreminja, je 298 298 primerneje uporabiti okno z dvema grafičnima pomnilnikoma 299 ''GLUT \_DOUBLE''. Prednost slednjega je v tem, da v en pomnilnik299 ''GLUT_DOUBLE''. Prednost slednjega je v tem, da v en pomnilnik 300 300 rišemo, drugega pa prikazujemo. Rišemo v ravnino, ki je v ozadju. 301 301 Ob koncu risanja pa le zamenjamo ravnini. Ker pa je to odvisno od … … 392 392 vozliščih nastajajo povsod tam kjer imajo ploskvice skupen rob, 393 393 za katerega želimo, da ima gladek prehod. To pa je povsod tam, kjer 394 aproksimiramo ´´gladko``površino z osnovnimi gradniki. Slika394 aproksimiramo 'gladko' površino z osnovnimi gradniki. Slika 395 395 2 kaže splošno postavitev treh točk v 396 396 prostoru. Normalo za trikotnik 397 z vozlišči $\vec{r}_0, \vec{r}_1, \vec{r}_2$izračunamo z397 z vozlišči '''r,,0,,''', '''r,,1,,''', '''r,,2,,''' izračunamo z 398 398 vektorskim produktom 399 $$ \vec{n} = \frac{ (\vec{r}_1-\vec{r}_0)\times (\vec{r}_2-\vec{r}_0) } 400 {|(\vec{r}_1-\vec{r}_0)\times (\vec{r}_2-\vec{r}_0)|} 401 $$ 402 403 Imenovalec zgornje enačbe je dolžina vektorja $\vec{n}$. 399 400 '''n''' = [('''r,,1,,''' - '''r,,0,,''')×('''r,,2,,''' - '''r,,0,,''')] / |('''r,,1,,''' - '''r,,0,,''')×('''r,,2,,''' - '''r,,0,,''')| 401 402 Imenovalec zgornje enačbe je dolžina vektorja '''n'''. 404 403 Normala je pravokotna na razliko vektorjev, ki podajajo 405 404 vozlišče gradnika. 406 405 406 [[Image(color-triangle.png)]] 407 408 Slika 1: Trikotnik s podanimi barvami v vozliščih 409 410 [[Image(normal.eps)]] 411 412 Slika 2: Normala 413 407 414 408 415 = Geometrijske transformacije = 416 409 417 Osnova vseh grafičnih knjižnic so tudi osnovne geometrijske 410 418 transformacije, kot so: 411 \begin{description} 412 \item[Translate(x, y, z)] Premik v smeri vektorja 413 \item[Rotate(fi, x, y, z)] Rotacija za \emph{fi} stopinj okoli osi 414 podane z (x, y, z) 415 \item[Scale(x, y, z)] Skaliranje po posameznih oseh 416 \end{description} 417 Ukazi za transformacije se ne smejo pojavljati med \emph{Begin/End}, 419 420 '''Translate(x, y, z)''' Premik v smeri vektorja 421 422 '''Rotate(fi, x, y, z)''' Rotacija za ''fi'' stopinj okoli osi 423 podane z (x, y, z) 424 425 '''Scale(x, y, z)''' Skaliranje po posameznih oseh 426 427 Ukazi za transformacije se ne smejo pojavljati med ''Begin/End'', 418 428 saj bi to pomenilo, da se transformacija spreminja med izrisom. 419 429 Geometrijske transformacije nam pomagajo pri modeliranju, saj lahko 420 430 podajamo vozlišča gradnikov v nekem poljubnem koordinatnem 421 431 sistemu. To je lahko svetovni koordinatni sistem ali lokalni 422 koordinatni sistem. Za primer izberimo izris krivulje $y(x)=\sin(x)$v432 koordinatni sistem. Za primer izberimo izris krivulje ''y(x)=sin(x)'' v 423 433 jeziku GL. Kot smo že opazili, je prednastavljeno okno v GLUT 424 434 obliki kvadrata, velikosti (-1,-1) do (1,1). Vsega skupaj torej dve 425 435 enoti. V zaslonskih koordinatah je prednastavljena velikost okna 426 $300\times 300$pikslov. Za nas je pomembno, da sinus narišemo v436 300×300 pikslov. Za nas je pomembno, da sinus narišemo v 427 437 mejah od -1 do 1. Vzemimo primer, ko predvidimo število točk. 428 438 Podprogram za izris je naslednji: 429 439 430 {\scriptsize\begin{verbatim} 431 subroutine display 432 include 'GL/fgl.h' 433 call fglClear(GL_COLOR_BUFFER_BIT) 434 call fglBegin(GL_LINE_STRIP) 435 do i=0,10 436 y = sin((i-5)/5.0*3.14) 437 call fglVertex2f((i-5)/5.0, y/3.14) 438 end do 439 call fglEnd 440 call fglFlush 441 end 442 \end{verbatim}} 440 {{{ 441 #!c 442 void display() 443 { 444 glClear(GL_COLOR_BUFFER_BIT); 445 glBegin(GL_LINE_STRIP); 446 for(i=0;i<=10;i++) 447 { 448 y=sin((i-5)/5.0*3.14); 449 glVertex2f((i-5)/5.0, y/3.14); 450 } 451 glEnd(); 452 glFlush(); 453 } 454 }}} 455 443 456 Da smo spravili naših 11 točk lomljenke v okvir -1, 1 je bilo 444 potrebno premakniti koordinatni sistem osi $x$za 5, ga nato še457 potrebno premakniti koordinatni sistem osi ''x'' za 5, ga nato še 445 458 skalirati tako, da smo iz območja [0,10] dobili območje [-3.14, 446 459 3.14]. čeprav smo za izračun koordinate y potrebovali na osi x 447 območje [-3.14, 3.14] pa je potrebna os $x$za izris v območju448 [-1,1]. Zato pri izrisu podajamo os $x$tako, da ponovno449 poračunavamo območje [0,10] v območje [-1,1], tako da \texttt{i}-ju460 območje [-3.14, 3.14] pa je potrebna os ''x'' za izris v območju 461 [-1,1]. Zato pri izrisu podajamo os ''x'' tako, da ponovno 462 poračunavamo območje [0,10] v območje [-1,1], tako da ''i''-ju 450 463 odštejemo 5 in delimo z 5. Lahko bi tudi delili s 5 in odšteli 451 464 1. Nekoliko bi poenostavili stvari, če bi imeli vsaj en kordinatni 452 sistem že takoj uporaben. Recimo os $x$. Zanka se nekoliko465 sistem že takoj uporaben. Recimo os ''x''. Zanka se nekoliko 453 466 poenostavi, še vedno pa je potrebno vse koordinate pomanjšati 454 467 za 3.14 oziroma poskalirati. 455 {\scriptsize\begin{verbatim} 456 do x=-3.14, 3.14, 0.6 457 y = sin(x) 458 call fglVertex2f(x/3.14, y/3.14) 459 end do 460 \end{verbatim}} 468 469 {{{ 470 #!c 471 for(x=-3.14;x<=3.14;i+=0.6) 472 { 473 y=sin(x); 474 glVertex2f(x/3.14, y/3.14); 475 } 476 }}} 477 461 478 Bolj razumljivo bi bilo risati kar v lokalnem koordinatnem sistemu in 462 479 prednastaviti pomanjšavo modela. Za pomanjšavo uporabimo 463 480 ukaz za skaliranje, ki posamezne koordinate množi s konstanto 1/3.14, 464 481 preden se izriše. Podprogram za izris je naslednji: 465 {\scriptsize\begin{verbatim} 466 subroutine display 467 include 'GL/fgl.h' 468 call fglClear(GL_COLOR_BUFFER_BIT) 469 call fglScalef(1/3.14, 1/3.14, 1.0) 470 call fglBegin(GL_LINE_STRIP) 471 do x=-3.14, 3.14, 0.6 472 y = sin(x) 473 call fglVertex2f(x, y) 474 end do 475 call fglEnd 476 call fglFlush 477 end 478 \end{verbatim}} 482 483 {{{ 484 #!c 485 void display() 486 { 487 glClear(GL_COLOR_BUFFER_BIT); 488 glScalef(1/3.14, 1/3.14, 1.0); 489 glBegin(GL_LINE_STRIP); 490 for(x=-3.14;x<=3.14;i+=0.6) 491 { 492 y=sin(x); 493 glVertex2f(x, y); 494 } 495 glEnd(); 496 glFlush(); 497 } 498 }}} 499 479 500 Prednost takega načina razmišljanja se pokaže, že ko 480 501 želimo pod sinusom narisati še krivuljo kosinusa. Seveda ni 481 možno obeh krivulj risati z \emph{GL\_LINE\_STRIP}v isti502 možno obeh krivulj risati z ''GL_LINE_STRIP'' v isti 482 503 zanki. Zato se odločimo za ponovno risanje v lokalnem 483 504 koordinatnem sistemu in prednastavimo pomik navzdol za 1.5 enote. 484 {\scriptsize\begin{verbatim} 485 subroutine display 486 include 'GL/fgl.h' 487 call fglClear(GL_COLOR_BUFFER_BIT) 488 call fglScalef(1/3.14, 1/3.14, 1.0) 489 call fglBegin(GL_LINE_STRIP) 490 do x=-3.14, 3.14, 0.6 491 y = sin(x) 492 call fglVertex2f(x, y) 493 end do 494 call fglEnd 495 call fglTranslatef(0.0, -1.5, 0.0) 496 call fglBegin(GL_LINE_STRIP) 497 do x=-3.14, 3.14, 0.6 498 y = cos(x) 499 call fglVertex2f(x, y) 500 end do 501 call fglEnd 502 call fglFlush 503 end 504 \end{verbatim}} 505 506 {{{ 507 #!c 508 void display() 509 { 510 glClear(GL_COLOR_BUFFER_BIT); 511 glScalef(1/3.14, 1/3.14, 1.0); 512 glBegin(GL_LINE_STRIP); 513 for(x=-3.14;x<=3.14;i+=0.6) 514 { 515 y=sin(x); 516 glVertex2f(x, y); 517 } 518 glEnd(); 519 glTranslatef(0.0, -1.5, 0.0); 520 glBegin(GL_LINE_STRIP); 521 for(x=-3.14;x<=3.14;i+=0.6) 522 { 523 y=cos(x); 524 glVertex2f(x, y); 525 } 526 glEnd(); 527 glFlush(); 528 } 529 }}} 530 505 531 Podani program za kosinus ne nastavlja ponovno skaliranja, saj je ukaz 506 532 že pred tem nastavil pomanjšavo. Translacija za -1.5 se izvede … … 510 536 vzgor. Transformacija, ki se izvede zadnja je torej napisana na prvem 511 537 mestu v programu. Tak način transformiranja točk nam 512 omogoča enostavnejše modeliranje. Koordinata $y$kosinusa se513 izračuna tako, da se pred izrisom najprej vsaki točki $y$538 omogoča enostavnejše modeliranje. Koordinata ''y'' kosinusa se 539 izračuna tako, da se pred izrisom najprej vsaki točki ''y'' 514 540 prišteje translacija -1.5 in potem se še izvede skaliranje 515 541 tako, da se ta vmesna točka pomnoži še z 1/3.14. 516 542 517 518 \subsection{Nadzor transformacijske matrike} 543 == Nadzor transformacijske matrike == 544 519 545 OpenGL pa za izračun koordinat ne hrani vse zgodovine posameznih 520 546 transformacij za nazaj, saj bi bilo to računsko potratno. Vse te … … 524 550 Prva matrika je modelna, druga pa je projekcijska. Mi bomo 525 551 uporabljali le modelno transformacijo in upoštevali, da 526 projekcijska matrika omogoča prikaz ravnine $(x,y)$v področju552 projekcijska matrika omogoča prikaz ravnine ''(x,y)'' v področju 527 553 [-1,1]. Modelna matrika je tudi stalno aktivna, če se ne 528 554 izbere projekcijsko. … … 530 556 Modelna matrika se ob vsakem klicu transformacijskega podprograma 531 557 popravi. Začetna oblika modelne matrike je enotska. Vsak klic 532 podprograma \emph{Translate}, \emph{Scale} in \emph{Rotate}pa matriko558 podprograma ''Translate'', ''Scale'' in ''Rotate'' pa matriko 533 559 popravi tako, da so upoštevane vse prejšnje transformacije in 534 560 nad njimi še novo podana transformacija. Matrika je torej stalna, … … 537 563 lahko preverimo tako, da okno prekrijemo s kakim drugim oknom in ga 538 564 potem ponovno odkrijemo. Kot že omenjeno, je na začetku 539 programa matrika enotska. S podprogramom \emph{fglLoadIdentity}na565 programa matrika enotska. S podprogramom ''glLoadIdentity'' na 540 566 začetku bi lahko to tudi zagotovili ob vsakem izrisu. 541 567 … … 543 569 shraniti in obnoviti. OpenGL ima v ta namen poseben pomnilnik v obliki 544 570 sklada, v katerega lahko shranjujemo trenutno 545 transformacijsko matriko. V pomnilniku oblike LIFO ( \emph{Last In,546 First Out}) je prostora je za najmanj 32 matrik. Pomnilnik si lahko571 transformacijsko matriko. V pomnilniku oblike LIFO (''Last In, 572 First Out'') je prostora je za najmanj 32 matrik. Pomnilnik si lahko 547 573 predstavljamo kot hladilnik, v katerega shranjujemo matrike. Matriko, ki 548 574 jo želimo shraniti, potisnemo na začetek in to tako, da … … 550 576 iz hladilnika, je to lahko le zadnja matrika. če 551 577 želimo predzadnjo, moramo poprej vzeti zadnjo. Za shranitev 552 trenutne matrike se uporabi \textbf{glPushMatrix}, za ponastavitev iz553 sklada pa uporabimo \textbf{glPopMatrix}. Izkaže se, da je za578 trenutne matrike se uporabi '''glPushMatrix''', za ponastavitev iz 579 sklada pa uporabimo '''glPopMatrix'''. Izkaže se, da je za 554 580 modeliranje taka oblika pomnilnika povsem primerna. 555 581 556 582 Za primer vzemimo primer kocke sestavljene iz šestih ploskev. Za 557 izris kvadrata obstaja že krajša funkcija \texttt{glRectf(x1,558 y1, x2, y2)} za ravnino $z=0$. če želimo imeti kvadrat v583 izris kvadrata obstaja že krajša funkcija ''glRectf(x1, 584 y1, x2, y2)'' za ravnino ''z=0''. če želimo imeti kvadrat v 559 585 poljubni ravnini, pa uporabimo transformacije. 560 {\scriptsize 561 \begin{verbatim} 562 subroutine kvadrat(i) 563 real r(6), g(6), b(6) 564 data r /1,0,0,1,1,1/, g /0,1,0,1,0,0/ 565 data b /0,0,1,0,1,1/ 566 call fglPushMatrix 567 call fglColor3f(r(i), g(i), b(i)) 568 call fglTranslatef(0.0, 0.0, 1.0) 569 call fglRectf(-1.0, -1.0, 1.0, 1.0) 570 call fglPopMatrix 571 end 572 573 subroutine display 574 implicit none 575 include 'GL/fgl.h' 576 call fglClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT) 577 call fglPushMatrix 578 call fglRotatef(30.0, 1.0, 0.0, 0.0) 579 call fglRotatef(30.0, 0.0, 1.0, 0.0) 580 call fglScalef(0.5, 0.5, 0.5) 581 call kvadrat(1) 582 call fglRotatef(90.0, 0.0, 1.0, 0.0) 583 call kvadrat(2) 584 call fglRotatef(90.0, 0.0, 1.0, 0.0) 585 call kvadrat(3) 586 call fglRotatef(90.0, 0.0, 1.0, 0.0) 587 call kvadrat(4) 588 call fglRotatef(90.0, 1.0, 0.0, 0.0) 589 call kvadrat(5) 590 call fglRotatef(180.0, 1.0, 0.0, 0.0) 591 call kvadrat(6) 592 call fglPopMatrix 593 call fglFlush 594 end 595 596 program kocka 597 external display 598 include 'GL/fglut.h' 599 include 'GL/fgl.h' 600 call fglutinit 601 call fglutInitDisplayMode(GLUT_SINGLE+GLUT_DEPTH) 602 call fglutCreateWindow('Fortran GLUT program') 603 call fglutDisplayFunc(display) 604 call fglEnable(GL_DEPTH_TEST) 605 call fglutmainloop 606 end 607 \end{verbatim} 608 } Podprogram \emph{kvadrat} je narejen tako, da riše transliran 609 kvadrat v ravnini $z=1$. To lahko razumemo kot nov primitiv, saj par 586 587 {{{ 588 #!c 589 float kvadrat(int i) 590 { 591 float r[6]={1,0,0,1,1,1}, g[6]={0,1,0,1,0,0}, b[6]={0,0,1,0,1,1}; 592 glPushMatrix(); 593 glColor3f(r[i], g[i], b[i]); 594 glTranslatef(0.0, 0.0, 1.0); 595 glRectf(-1.0, -1.0, 1.0, 1.0); 596 glPopMatrix(); 597 } 598 599 void display() 600 { 601 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 602 glPushMatrix(); 603 glRotatef(30.0, 1.0, 0.0, 0.0); 604 glRotatef(30.0, 0.0, 1.0, 0.0); 605 glScalef(0.5, 0.5, 0.5); 606 kvadrat(1); 607 glRotatef(90.0, 0.0, 1.0, 0.0); 608 kvadrat(2); 609 glRotatef(90.0, 0.0, 1.0, 0.0); 610 kvadrat(3); 611 glRotatef(90.0, 0.0, 1.0, 0.0); 612 kvadrat(4); 613 glRotatef(90.0, 1.0, 0.0, 0.0); 614 kvadrat(5); 615 glRotatef(180.0, 1.0, 0.0, 0.0); 616 kvadrat(6); 617 glPopMatrix(); 618 glFlush(); 619 } 620 621 int main(int argc, char *argv[]) 622 { 623 glutInit(&argc, argv); 624 glutInitDisplayMode(GLUT_SINGLE|GLUT_DEPTH); 625 glutCreateWindow("C GLUT program"); 626 glutDisplayFunc(display); 627 glEnable(GL_DEPTH_TEST); 628 glutMainLoop(); 629 return 0; 630 } 631 }}} 632 633 Podprogram ''kvadrat'' je narejen tako, da riše transliran 634 kvadrat v ravnini ''z=1''. To lahko razumemo kot nov primitiv, saj par 610 635 ukazov Push/Pop ne popravlja transformacije ob klicu podprograma. 611 šest stranic se riše z rotacijo osnovne stranice okoli osi y612 in x. Modelna matrika se shani z začetnim ukazom \emph{Push}in613 potem ponovno obnovi z ukazom \emph{Pop}.614 615 616 \subsection{Globinski pomilnik} 636 Šest stranic se riše z rotacijo osnovne stranice okoli osi y 637 in x. Modelna matrika se shani z začetnim ukazom ''Push'' in 638 potem ponovno obnovi z ukazom ''Pop''. 639 640 == Globinski pomilnik == 641 617 642 Da se ploskve v prostoru pravilno izrisujejo tudi takrat, ko 618 643 rišemo ploskvice za drugimi, je potrebno uporabiti globinski 619 pomnilnik ali \emph{z-buffer}. To pa mora omogočati že sam644 pomnilnik ali ''z-buffer''. To pa mora omogočati že sam 620 645 okenski sistem, zato je potrebno tak način prikaza zahtevati že 621 pri \texttt{fglutInitDisplayMode} in kasneje še dopovedati GL 622 stroju, da poleg barve točk na zaslonu shranjuje še koordinato 623 $z$ v svoj pomnilnik. S tem pomnilnikom GL ob rasterizaciji lika za 624 vsako točko ugotovi, če je že kakšna točka po 625 globini pred njim in jo zato ne riše. Z ukazom 626 \texttt{fglEnable(GL\_DEPTH\_TEST)} se zahteva izračunavanje 627 globine, ki jo je potrebno tako kot barvo pred vsakim začetkom 628 risanja pobrisati z ukazom \texttt{fglClear}. 629 630 \begin{figure}[htbp] 631 \centering 632 \includegraphics{half-cube} 633 \caption{Kocka brez spodnjega in zgornjega pokrova (kvadrat(5) in kvadrat(6)} 634 \label{fig:half-cube} 635 \end{figure} 646 pri ''fglutInitDisplayMode'' in kasneje še dopovedati GL 647 stroju, da poleg barve točk na zaslonu, shranjuje še koordinato 648 ''z'' v svoj pomnilnik. S tem pomnilnikom GL ob rasterizaciji lika za 649 vsako točko ugotovi, če je že kakšna točka po 650 globini pred njim in jo zato ne riše. Z ukazom 651 ''glEnable(GL_DEPTH_TEST)'' se zahteva izračunavanje 652 globine, ki jo je potrebno, tako kot barvo, pred vsakim začetkom 653 risanja pobrisati z ukazom ''glClear''. 654 655 [[Image(half-cube.png)]] 656 657 Slika 3: Kocka brez spodnjega in zgornjega pokrova (kvadrat(5) in kvadrat(6) 636 658 637 659 če rišemo zaprte modele, potem notranjosti ni možno 638 videti. Primer odprtega modela kaže slika \ref{fig:half-cube}. V660 videti. Primer odprtega modela kaže slika 3. V 639 661 takih primerih se ob uporabi prostorskega pomnilnika običajno kar 640 662 polovica ploskvic modela prekrije v celoti in kasneje na zaslonu ni 641 663 vidna. Skupna značilnost vseh teh ploskvic, ki se prekrijejo je, 642 da imajo normalo površine negativno ( $n_z < 0$). Da se izogemo664 da imajo normalo površine negativno (''n,,z,, < 0''). Da se izognemo 643 665 nepotrebni rasterizaciji teh ploskvic, vključimo 644 \texttt{GL\_CULL\_FACE}. Da pa bo izločanje delovalo, mora imeti666 ''GL_CULL_FACE''. Da pa bo izločanje delovalo, mora imeti 645 667 GL podatek za normalo površine, ki jo je potrebno podati pred 646 668 podatki v vozliščih. Za pravilno delovanje globinskega 647 pomnilnika je potrebna tudi nastavitev projekcijske matrike kot je to648 opisano v \S\ref{sec:viewing}.649 650 \subsection{Animacija} 651 \label{sec:animate} 669 pomnilnika je potrebna tudi nastavitev projekcijske matrike, kot je to 670 opisano v poglavju Transformacije pogleda. 671 672 == Animacija == 673 652 674 Imejmo primer animacije vozil na avtocesti. Predstavljeno bo 653 675 cestišče v eno smer z dvema pasovoma, voznim in prehitevalnim. … … 655 677 vozišče dolžine 500 metrov. Hitrost vozila med vožnjo se ne 656 678 spreminja. Spreminja se le položaj vozil (x, y) na 657 cestišču, ki jih izriše podprogram \texttt{vozilo}. 658 659 {\scriptsize\begin{verbatim} 660 subroutine display 661 implicit none 662 include 'GL/fgl.h' 663 common /vozila/ y(5), v(5) 664 real y, v, pas 665 integer i 666 data y /0,50,120,170,200/ 667 data v /50,30,45,31,33/ 668 call fglClear(GL_COLOR_BUFFER_BIT) 669 call fglPushMatrix 670 call fglRotatef(-45.0, 0.0, 0.0, 1.0) 671 call fglTranslatef(0.0, -1.0, 0.0) 672 call fglScalef(0.004, 0.004, 0.004) 673 call fglColor3f(0.0, 0.0, 0.0) 674 call fglRectf(-4.0, 0.0, 4.0, 500.0) 675 call fglTranslatef(0.0, -50.0, 0.0) 676 do i=1,5 677 if (i.ne.5 .and. y(i+1)-y(i).lt.10.0) then 678 pas=-2.0 679 else 680 pas = 2.0 681 end if 682 call vozilo(y(i), pas) 683 end do 684 call fglPopMatrix 685 call fglutSwapBuffers 686 end 687 688 subroutine vozilo(y, pas) 689 call fglPushMatrix 690 call fglColor3f(1.0, 1.0, 1.0) 691 call fglTranslatef(pas, y, 0.5) 692 call fglRectf(-2.0, 0.0, 2.0, 6.0) 693 call fglPopMatrix 694 end 695 696 subroutine ura(n) 697 common /vozila/ y(5), v(5) 698 real y, v, dt 699 dt = 0.1 700 do i=1,5 701 y(i)=y(i)+v(i)*dt 702 end do 703 call fglutPostRedisplay 704 call fglutTimerfunc(100, ura, 0) 705 end 706 707 program Mad Max 708 external display 709 external ura 710 include 'GL/fglut.h' 711 integer window 712 call fglutInit 713 call fglutInitDisplayMode(GLUT_RGB+GLUT_DOUBLE) 714 call fglutCreateWindow('Avtocesta') 715 call fglClearColor(0.0, 0.5, 0.0, 0.0) 716 call fglutDisplayFunc(display) 717 call fglutTimerFunc(100, ura, 0) 718 call fglutMainLoop 719 end 720 \end{verbatim} 721 } 722 723 Pas predstavlja odmik v smeri $x$ od sredine cestišča. Vse 679 cestišču, ki jih izriše podprogram ''vozilo''. 680 681 {{{ 682 #!c 683 #include <GL/glut.h> 684 685 float y[5]={0,50,120,170,200}; 686 float v[5]={50,30,45,31,33}; 687 float pas; 688 689 void ura() 690 { 691 float dt; 692 int i; 693 dt=0.1; 694 for(i=1;i<6;i++) 695 { 696 y[i]=y[i]+v[i]*dt; 697 } 698 glutPostRedisplay(); 699 glutTimerFunc(100, ura, 0); 700 } 701 702 float vozilo(float y, float pas) 703 { 704 glPushMatrix(); 705 glColor3f(1.0, 1.0, 1.0); 706 glTranslatef(pas, y, 0.5); 707 glRectf(-2.0, 0.0, 2.0, 6.0); 708 glPopMatrix(); 709 } 710 711 void display() 712 { 713 int i; 714 glClear(GL_COLOR_BUFFER_BIT); 715 glPushMatrix(); 716 glRotatef(-45.0, 0.0, 0.0, 1.0); 717 glTranslatef(0.0, -1.0, 0.0); 718 glScalef(0.004, 0.004, 0.004); 719 glColor3f(0.0, 0.0, 0.0); 720 glRectf(-4.0, 0.0, 4.0, 500.0); 721 glTranslatef(0.0, -50.0, 0.0); 722 for(i=1;i<6;i++) 723 { 724 if (i<5 && (y[i+1]-y[i])>10.0) 725 pas=-2.0; 726 else 727 pas=2.0; 728 729 vozilo(y[i], pas); 730 } 731 glPopMatrix(); 732 glutSwapBuffers(); 733 } 734 735 int main(int argc, char *argv[]) 736 { 737 glutInit(&argc, argv); 738 glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE); 739 glutCreateWindow("Avtocesta"); 740 glClearColor(0.0, 0.5, 0.0, 0.0); 741 glutDisplayFunc(display); 742 glutTimerFunc(100, ura, 0); 743 glutMainLoop(); 744 return 0; 745 } 746 }}} 747 748 Pas predstavlja odmik v smeri ''x'' od sredine cestišča. Vse 724 749 enote so v metrih. Vozilo je zaradi sorazmerja narisano 725 750 nekoliko večje. Za animacije je primernejša uporaba dvojnega 726 pomnilnika \texttt{GLUT\_DOUBLE}. S tem se izognemo težavam izrisa,751 pomnilnika ''GLUT_DOUBLE''. S tem se izognemo težavam izrisa, 727 752 saj v trenutku, ko se zgornja plast izrisuje, nemoteno rišemo v 728 753 spodnjo plast. Ko je spodnja plast izdelana z ukazom 729 \emph{fglutSwapBuffers}, zamenjamo trenutni prikaz.730 731 Za animacijo, pri kateri je zahtevano točno časovno zaporedje je732 primerno uporabiti uro ( \emph{timer}), ki program opozori, da je754 ''glutSwapBuffers'', zamenjamo trenutni prikaz. 755 756 Za animacijo, pri kateri je zahtevano točno časovno zaporedje, je 757 primerno uporabiti uro (''timer''), ki program opozori, da je 733 758 pretekel predpisani čas in da je potrebno izračunati nov 734 položaj vozil. V našem primeru je podana spremeba vsakih 100 ~ms735 in zato nov položaj v smeri $y$ linearno narašča za $v(i)736 dt $, kjer je hitrost podana v metrih na sekundo. Izbor 0.1s za premik759 položaj vozil. V našem primeru je podana spremeba vsakih 100 ms 760 in zato nov položaj v smeri ''y'' linearno narašča za ''v(i) 761 dt'', kjer je hitrost podana v metrih na sekundo. Izbor 0.1s za premik 737 762 pomeni 1/0.1=10 posnetkov na sekundo, kar je spodnja meja pri 738 763 animacijah. Po poračunu novih položajev pošljemo 739 sporočilo \emph{fglutPostRedisplay}, da se na novo izriše740 scena. Lahko bi tudi neposredno klicali \texttt{display}, vendar bi764 sporočilo ''glutPostRedisplay'', da se na novo izriše 765 scena. Lahko bi tudi neposredno klicali ''display'', vendar bi 741 766 bilo potem potrebno zagotoviti še kompenzacijo hitrosti, saj 742 že v podprogramu ura izgubimo nekaj časa pri izr ečunu767 že v podprogramu ura izgubimo nekaj časa pri izračunu 743 768 novih položajev. Prostorski pomnilnik v tem primeru ni potreben, 744 769 saj je zagotovljeno, da se izrisi prekrijejo v pravilnem vrstnem redu. 745 770 746 \subsection{Transformacije pogleda} 747 \label{sec:viewing} 771 == Transformacije pogleda == 772 748 773 Za zahtevnejše načine gledanja na model je potrebno nastaviti 749 774 projekcijo modela iz svetovnih koordinat v normalizirane oz. zaslonske … … 753 778 želimo poudariti bližino in oddaljenost določenih 754 779 objektov, se uporablja tudi perspektivna projekcija. 755 \begin{figure}[htbp] 756 \centering 757 \includegraphics[width=3in]{viewing} 758 \caption{Zaporedje pretvorbe koordinat vozlišč} 759 \label{fig:viewing} 760 \end{figure} 780 781 [[Image(viewing.eps)]] 782 783 Slika 4: Zaporedje pretvorbe koordinat vozlišč 761 784 762 785 OpenGL ločuje projekcijsko matriko in modelno matriko zato, 763 da ni potrebno nastavljati projekcije pri vsakem izrisu. Slika 764 \ref{fig:viewing}kaže zaporedje transformacij iz svetovnih786 da ni potrebno nastavljati projekcije pri vsakem izrisu. Slika 787 4 kaže zaporedje transformacij iz svetovnih 765 788 koordinat v zaslonske. Pri risanju modela običajno začnemo z 766 enotsko \emph{ModelView}matriko.789 enotsko ''ModelView'' matriko. 767 790 768 791 Najpreprostejši način prikaza, kot je bil prikazan tudi v … … 777 800 pri sistemu GLUT le enovrstičen ukaz: 778 801 779 {\scriptsize\texttt{call fglViewport (0, 0, width, height)}} 802 {{{ 803 #!c 804 glViewport (0, 0, width, height); 805 }}} 780 806 781 807 Nekoliko zahtevnejša je sorazmerna sprememba, 782 808 ki ne bo anamorfično popravljala velikosti okna: 783 {\scriptsize\begin{verbatim} 784 subroutine reshape (w, h) 785 integer w, h 786 implicit none 787 include 'GL/fgl.h' 788 common /viewport/ width, height 789 integer width, height 790 real*8 left, right, bottom, top, znear, zfar 791 width = w 792 height = h 793 if (w .ge. h) then 794 left = -width/(1.0*height) 795 right = width/(1.0*height) 796 bottom = -1.0 797 top = 1.0 798 else 799 left = -1.0 800 right = 1.0 801 bottom = -height/(1.0*width) 802 top = height/(1.0*width) 803 end if 804 znear = -1.0 805 zfar = 1.0 806 call fglViewport (0, 0, width, height) 807 call fglMatrixMode (GL_PROJECTION) 808 call fglLoadIdentity 809 call fglOrtho(left, right, bottom, top, znear, zfar) 810 call fglMatrixMode(GL_MODELVIEW) 811 end 812 \end{verbatim} 813 } 814 809 810 {{{ 811 #!c 812 void reshape (int w, int h) 813 { 814 815 int width, height; 816 double left, right, bottom, top, znear, zfar; 817 width = w; 818 height = h; 819 820 if (w == h) 821 { 822 left = -width/(1.0*height); 823 right = width/(1.0*height); 824 bottom = -1.0; 825 top = 1.0; 826 } 827 else 828 { 829 left = -1.0; 830 right = 1.0; 831 bottom = -height/(1.0*width); 832 top = height/(1.0*width); 833 } 834 znear = -1.0; 835 zfar = 1.0; 836 glViewport (0, 0, width, height); 837 glMatrixMode (GL_PROJECTION); 838 glLoadIdentity(); 839 glOrtho(left, right, bottom, top, znear, zfar); 840 glMatrixMode(GL_MODELVIEW); 841 } 842 }}} 843 815 844 Predstavljeni podprogram se priporoča v uporabo za vse programe, 816 ki pripravljajo model v velikosti [-1, ~1] za \emph{ModelView}. če817 bi želeli dodati modelno transformacijo v \emph{reshape}, potem za845 ki pripravljajo model v velikosti [-1, 1] za ''ModelView''. Če 846 bi želeli dodati modelno transformacijo v ''reshape'', potem za 818 847 zadnjo vrstico dopišemo še modelno transformacijo in nato v 819 848 programu za izris pred začetkom le obnovimo stanje modelne 820 matrike. Primer animacije \ref{sec:animate}bi tako imel namesto821 nastavitve modelne transformacije slednje v podprogramu \emph{reshape}.849 matrike. Primer animacije bi tako imel namesto 850 nastavitve modelne transformacije slednje v podprogramu ''reshape''. 822 851 Začetna nastavitev modelne matrike pred začetkom izrisa v 823 podprogramu \emph{display} pa bi bila: 824 {\scriptsize\begin{verbatim} 825 call fglClear(GL_COLOR_BUFFER_BIT) 826 call fglPushMatrix 852 podprogramu ''display'' pa bi bila: 853 854 {{{ 855 #!c 856 glClear(GL_COLOR_BUFFER_BIT); 857 glPushMatrix(); 827 858 ... izris 828 call fglPopMatrix 829 \end{verbatim}830 } 831 Takoj za brisanjem zaslona z ukazom \emph{Push}shranimo modelno859 glPopMatrix(); 860 }}} 861 862 Takoj za brisanjem zaslona z ukazom ''Push'' shranimo modelno 832 863 matriko in jo ob koncu ponovno nastavimo na začetno vrednost. 833 V podprogramu \emph{reshape}, pa modelno matriko popravljamo: 834 {\scriptsize\begin{verbatim} 835 call fglMatrixMode(GL_MODELVIEW) 836 call fglLoadIdentity 837 call fglRotatef(-45.0, 0.0, 0.0, 1.0) 838 call fglTranslatef(0.0, -1.0, 0.0) 839 call fglScalef(0.004, 0.004, 0.004) 840 \end{verbatim} 841 } 864 V podprogramu ''reshape'', pa modelno matriko popravljamo: 865 866 {{{ 867 #!c 868 glMatrixMode(GL_MODELVIEW); 869 glLoadIdentity(); 870 glRotatef(-45.0, 0.0, 0.0, 1.0); 871 glTranslatef(0.0, -1.0, 0.0); 872 glScalef(0.004, 0.004, 0.004); 873 }}} 874 842 875 Tak pristop nekoliko jasneje predstavi program, saj so vse enote, s 843 876 katerimi manipuliramo, v programu za izris v svetovnih oz. modelnih … … 845 878 vse modele, ki uporabljajo izris ploskev. To pa zaradi tega, ker je 846 879 privzeta projekcijska matrika enotska. Poglejmo to na primeru 847 paralelne projekcije \emph{glOrtho(l,r,b,,n,f)}: 848 $$ 849 PM = \left[ 850 \begin{array}{cccc} 851 \frac{2}{r-l} & 0 & 0 & \frac{r+l}{l-r} \cr 852 0 & \frac{2}{t-b} & 0 & \frac{t+b}{t-b} \cr 853 0 & 0 & \frac{2}{f-n} & \frac{f+n}{f-n} \cr 854 0 & 0 & 0 & 1 \cr 855 \end{array} 856 \right]\quad . 857 $$ 880 paralelne projekcije ''glOrtho(l,r,b,,n,f)'': 881 882 ''PM = [2/(r-l), 0, 0, (r+l)/(l-r); 0, 2/(t-b), 0, (t+b)/(t-b); 0, 0, 2/(f-n), (f+n)/f-n); 0, 0, 0, 1]'' 883 858 884 Za primer normalizacijskega prostora v obsegu [-1,1] je tako matrika paralelne 859 885 projekcije 860 $$ 861 PM(-1, 1, -1, 1, -1, 1) = \left[ 862 \begin{array}{cccc} 863 1 & 0 & 0 & 0 \cr 864 0 & 1 & 0 & 0 \cr 865 0 & 0 & -1 & 0 \cr 866 0 & 0 & 0 & 1 \cr 867 \end{array} 868 \right]\quad , 869 $$ 870 kar se razlikuje od enotske prav v koordinati $z$. če bi 886 887 ''PM(-1, 1, -1, 1, -1, 1) = [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, -1, 0; 0, 0, 0, 1]'' 888 889 kar se razlikuje od enotske prav v koordinati ''z''. Če bi 871 890 projekcijsko matriko ohranili enotsko, potem bi to pomenilo, da objekt 872 891 gledamo kot zrcalno sliko zadnje strani. Nastavitev projekcijske matrike … … 875 894 nelogično postavil v ospredje modro stranico in ne rdečo. 876 895 896 877 897 = Osvetlitev = 898 878 899 Do sedaj predstavljeni primeri so uporabljali le sintetične barve. 879 900 To pomeni, da se barva vsake ploskvice ne spreminja v odvisnosti od … … 881 902 omejen nabor prostorskih modelov. Neprimeren je že za vse modele, 882 903 ki imajo površine sestavljene iz primitivov in te površine 883 niso ravninske. Za primer kocke (slika \ref{fig:half-cube}) je bilo904 niso ravninske. Za primer kocke (slika 3) je bilo 884 905 potrebno za vsako stranico nastaviti svojo barvo, da smo lahko dobili 885 vtis prostora. če bi kocko risali le z eno barvo, potem bi dobili906 vtis prostora. Če bi kocko risali le z eno barvo, potem bi dobili 886 907 na zaslon le obris. 887 908 888 909 Za bolj realističen izris je potrebno vključiti računanje 889 osvetlitve. žal osvetlitev zajema veliko parametrov, ki jih je910 osvetlitve. Žal osvetlitev zajema veliko parametrov, ki jih je 890 911 potrebno nastaviti preden lahko karkoli dobimo na zaslonu. Tako je 891 912 potrebno nastavljati položaj in lastnosti luči, osvetlitveni … … 899 920 barvo. S tem vpeljemo veliko predpostavk, ki pa so za šolsko rabo 900 921 povsem uporabne. Predpostavljena je le ena luč bele svetlobe s 901 položajem $(0, 0, 1)$in difuzni odboj svetlobe na922 položajem ''(0, 0, 1)'' in difuzni odboj svetlobe na 902 923 površini. Barvo površine podajamo kar z običajnim ukazom 903 924 za barvo. Program za izris osenčenega modela kocke je tako v 904 925 minimalni obliki naslednji: 905 926 906 {\scriptsize\begin{verbatim} 907 subroutine kvadrat() 908 call fglPushMatrix 909 call fglTranslatef(0.0, 0.0, 1.0) 910 call fglNormal3f(0.0, 0.0, 1.0) 911 call fglRectf(-1.0, -1.0, 1.0, 1.0) 912 call fglPopMatrix 913 end 914 915 subroutine display 916 implicit none 917 include 'GL/fgl.h' 918 call fglClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT) 919 call fglColor3f(0.7, 0.6, 0.2) 920 call fglPushMatrix 921 call fglScalef(0.5, 0.5, 0.5) 922 call kvadrat 923 call fglRotatef(90.0, 0.0, 1.0, 0.0) 924 call kvadrat 925 call fglRotatef(90.0, 0.0, 1.0, 0.0) 926 call kvadrat 927 call fglRotatef(90.0, 0.0, 1.0, 0.0) 928 call kvadrat 929 call fglRotatef(90.0, 1.0, 0.0, 0.0) 930 call kvadrat 931 call fglRotatef(180.0, 1.0, 0.0, 0.0) 932 call kvadrat 933 call fglPopMatrix 934 call fglFlush 935 end 936 937 938 program kocka 939 external display 940 external reshape 941 include 'GL/fglut.h' 942 include 'GL/fgl.h' 943 call fglutinit 944 call fglutinitdisplaymode(GLUT_SINGLE+GLUT_DEPTH) 945 call fglutcreatewindow('Osencena kocka') 946 call fglutDisplayFunc(display) 947 call fglutReshapeFunc(reshape) 948 call fglClearColor(1.0, 1.0, 1.0, 1.0) 949 call fglEnable(GL_LIGHTING) 950 call fglEnable(GL_LIGHT0) 951 call fglEnable(GL_DEPTH_TEST) 952 call fglEnable(GL_COLOR_MATERIAL) 953 call fglutMainLoop 954 end 955 956 subroutine reshape (w, h) 957 integer w, h 958 implicit none 959 include 'GL/fgl.h' 960 real*8 l 961 l = 1.0 962 call fglViewport (0, 0, w, h) 963 call fglMatrixMode (GL_PROJECTION) 964 call fglLoadIdentity 965 call fglOrtho(-l, l, -l, l, -l, l) 966 call fglMatrixMode(GL_MODELVIEW) 967 call fglLoadIdentity 968 call fglRotatef(30.0, 1.0, 0.0, 0.0) 969 call fglRotatef(30.0, 0.0, 1.0, 0.0) 970 end 971 \end{verbatim} 972 } 927 {{{ 928 #!c 929 #include <GL/glut.h> 930 931 float kvadrat() 932 { 933 glPushMatrix(); 934 glTranslatef(0.0, 0.0, 1.0); 935 glNormal3f(0.0, 0.0, 1.0); 936 glRectf(-1.0, -1.0, 1.0, 1.0); 937 glPopMatrix(); 938 } 939 940 void display() 941 { 942 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 943 glColor3f(0.7, 0.6, 0.2); 944 glPushMatrix(); 945 glScalef(0.5, 0.5, 0.5); 946 kvadrat(); 947 glRotatef(90.0, 0.0, 1.0, 0.0); 948 kvadrat(); 949 glRotatef(90.0, 0.0, 1.0, 0.0); 950 kvadrat(); 951 glRotatef(90.0, 0.0, 1.0, 0.0); 952 kvadrat(); 953 glRotatef(90.0, 1.0, 0.0, 0.0); 954 kvadrat(); 955 glRotatef(180.0, 1.0, 0.0, 0.0); 956 kvadrat(); 957 glPopMatrix(); 958 glFlush(); 959 } 960 961 void reshape (int w, int h) 962 { 963 double l; 964 l = 1.0; 965 glViewport (0, 0, w, h); 966 glMatrixMode (GL_PROJECTION); 967 glLoadIdentity(); 968 glOrtho(-l, l, -l, l, -l, l); 969 glMatrixMode(GL_MODELVIEW); 970 glLoadIdentity(); 971 glRotatef(30.0, 1.0, 0.0, 0.0); 972 glRotatef(30.0, 0.0, 1.0, 0.0); 973 } 974 975 int main(int argc, char *argv[]) 976 { 977 glutInit(&argc, argv); 978 glutInitDisplayMode(GLUT_SINGLE|GLUT_DEPTH); 979 glutCreateWindow("Osencena kocka"); 980 glutDisplayFunc(display); 981 glutReshapeFunc(reshape); 982 glClearColor(1.0, 1.0, 1.0, 1.0); 983 glEnable(GL_LIGHTING); 984 glEnable(GL_LIGHT0); 985 glEnable(GL_DEPTH_TEST); 986 glEnable(GL_COLOR_MATERIAL); 987 glutMainLoop(); 988 return 0; 989 } 990 }}} 973 991 974 992 Razširjeni primitiv smo poenostavili tako, da ne vsebuje več 975 993 definicije barve, ampak le geometrijo. Obvezno je bilo potrebno podati 976 izračun normale. Za naš primitiv kvadrata je to $(0,0,1)$.994 izračun normale. Za naš primitiv kvadrata je to ''(0,0,1)''. 977 995 Program za izris v bistvu ni spremenjen, le da je sedaj 978 996 transformacija modela preseljena v podprogram za nastavitev velikosti 979 okna \texttt{reshape}. V glavnem programu pa je potrebno najprej980 vključiti računanje osvetlitve \emph{GL\_LIGHTING},997 okna ''reshape''. V glavnem programu pa je potrebno najprej 998 vključiti računanje osvetlitve ''GL_LIGHTING'', 981 999 prižgati je potrebno luč št 0, ki ima začetni 982 položaj $(0,0,1)$. 983 984 \begin{figure}[htbp] 985 \centering 986 \includegraphics[width=2.5in]{cube-l} 987 \caption{Osenčen model kocke} 988 \label{fig:cube-l} 989 \end{figure} 990 991 Z vključitvijo \emph{GL\_COLOR\_MATERIAL} 1000 položaj ''(0,0,1)''. 1001 1002 [[Image(cube-l.png)]] 1003 1004 Slika 5: Osenčen model kocke 1005 1006 Z vključitvijo ''GL_COLOR_MATERIAL'' 992 1007 pa poenostavimo podajanje barve za material površine tako, da vsi 993 klici podprogramov \emph{Color}nastavljajo privzeto difuzno in994 ambientno barvo površine. Slika \ref{fig:cube-l}prikazuje1008 klici podprogramov ''Color'' nastavljajo privzeto difuzno in 1009 ambientno barvo površine. Slika 5 prikazuje 995 1010 rezultat upodabljanja z osvetlitvijo. 996 1011 997 1012 998 999 1013 = Tekst = 1014 1000 1015 OpenGL sam ne podpira teksta in je zato potrebno uporabiti razne 1001 1016 prijeme za izris teksta v prostoru. Možnih je več načinov 1002 1017 za risanje besedila: 1003 \begin{description} 1004 \item[stroke] črke so izrisane s črtami v prostoru modela 1005 \item[bitmap] črke so izrisane na zaslon 1006 \item[teksture] črke so izrisane rastrsko v prostoru modela 1007 \end{description} 1018 1019 '''stroke''' črke so izrisane s črtami v prostoru modela 1020 1021 '''bitmap''' črke so izrisane na zaslon 1022 1023 '''teksture''' črke so izrisane rastrsko v prostoru modela 1024 1008 1025 V šolskih primerih so najbolj uporabni že izdelani fonti v 1009 1026 knjižnici GLUT. Možne so naslednje številke fontov: 1010 {\small 1011 \begin{enumerate} 1012 \item GLUT\_STROKE\_ROMAN 1013 \item GLUT\_STROKE\_MONO\_ROMAN 1014 \item GLUT\_BITMAP\_9\_BY\_15 1015 \item GLUT\_BITMAP\_8\_BY\_13 1016 \item GLUT\_BITMAP\_TIMES\_ROMAN\_10 1017 \item GLUT\_BITMAP\_TIMES\_ROMAN\_24 1018 \item GLUT\_BITMAP\_HELVETICA\_10 1019 \item GLUT\_BITMAP\_HELVETICA\_12 1020 \item GLUT\_BITMAP\_HELVETICA\_18 1021 \end{enumerate} 1022 } 1027 1028 1. GLUT_STROKE_ROMAN 1029 1030 2. GLUT_STROKE_MONO_ROMAN 1031 1032 3. GLUT_BITMAP_9_BY_15 1033 1034 4. GLUT_BITMAP_8_BY_13 1035 1036 5. GLUT_BITMAP_TIMES_ROMAN_10 1037 1038 6. GLUT_BITMAP_TIMES_ROMAN_24 1039 1040 7. GLUT_BITMAP_HELVETICA_10 1041 1042 8. GLUT_BITMAP_HELVETICA_12 1043 1044 9. GLUT_BITMAP_HELVETICA_18 1023 1045 1024 1046 Za primer razširimo program za izris osenčene kocke z 1025 besedilom na vsaki stranici. Podprogram \emph{kvadrat}kot argument1047 besedilom na vsaki stranici. Podprogram ''kvadrat'' kot argument 1026 1048 vzame besedilo. Začetek izpisa premakne za malenkost višje in 1027 začne v koordinati $x=-0.8$. Ker pa ne želimo, da se besedilo1028 senči je tu potrebno izklapljanje senčenja takrat, ko1049 začne v koordinati ''x=-0.8''. Ker pa ne želimo, da se besedilo 1050 senči, je tu potrebno izklapljanje senčenja takrat, ko 1029 1051 izrisujemo posamezne črke. Ker so črke v vnaprej določeni 1030 1052 velikost, jih je potrebno ustrezno pomanjšati s 1031 skaliranjem. Podprogram \texttt{fglutStrokeCharacter}po vsaki1053 skaliranjem. Podprogram ''glutStrokeCharacter'' po vsaki 1032 1054 izrisani črti sam nastavi pomik v smeri x za širino izrisane 1033 1055 črke. 1034 1056 1035 {\scriptsize\begin{verbatim} 1036 subroutine kvadrat(s) 1037 include 'GL/fgl.h' 1038 character s*(*), c 1039 call fglPushMatrix 1040 call fglTranslatef(0.0, 0.0, 1.0) 1041 call fglNormal3f(0.0, 0.0, 1.0) 1042 call fglRectf(-1.0, -1.0, 1.0, 1.0) 1043 call fglTranslatef(-0.8, 0.0, 0.01) 1044 call fglDisable(GL_LIGHTING) 1045 call fglScalef(0.003, 0.003, 0.003) 1046 call fglColor3f(1.0, 0.0, 0.0) 1047 lenc = len(s) 1048 do i=1,lenc 1049 c = s(i:i) 1050 call fglutStrokeCharacter(1, ichar(c)) 1051 end do 1052 call fglEnable(GL_LIGHTING) 1053 call fglPopMatrix 1054 end 1055 1056 subroutine display 1057 implicit none 1058 include 'GL/fgl.h' 1059 real mat(4) 1060 data mat /0.9, 0.6, 0.3, 1.0/ 1061 call fglClear(GL_COLOR_BUFFER_BIT) 1062 call fglClear(GL_DEPTH_BUFFER_BIT) 1063 call fglPushMatrix 1064 call fglRotatef(30.0, 1.0, 0.0, 0.0) 1065 call fglRotatef(30.0, 0.0, 1.0, 0.0) 1066 call fglScalef(0.5, 0.5, 0.5) 1067 call fglMaterialfv(GL_FRONT, GL_DIFFUSE, mat) 1068 call kvadrat('Spredaj') 1069 call fglRotatef(90.0, 0.0, 1.0, 0.0) 1070 call kvadrat('Desno') 1071 call fglRotatef(90.0, 0.0, 1.0, 0.0) 1072 call kvadrat('Zadaj') 1073 call fglRotatef(90.0, 0.0, 1.0, 0.0) 1074 call kvadrat('Levo') 1075 call fglRotatef(90.0, 1.0, 0.0, 0.0) 1076 call kvadrat('Spodaj') 1077 call fglRotatef(180.0, 1.0, 0.0, 0.0) 1078 call kvadrat('Zgoraj') 1079 call fglPopMatrix 1080 call fglFlush 1081 end 1082 1083 subroutine reshape(w, h) 1084 include 'GL/fgl.h' 1085 integer w, h 1086 real*8 l 1087 l = 1 1088 call fglViewPort(0, 0, w, h) 1089 call fglMatrixMode(GL_PROJECTION) 1090 call fglLoadIdentity 1091 call fglOrtho(-l,l,-l,l,-l,l) 1092 call fglMatrixMode(GL_MODELVIEW) 1093 call fglLoadIdentity 1094 end 1095 1096 program crta 1097 external display 1098 external reshape 1099 include 'GL/fglut.h' 1100 include 'GL/fgl.h' 1101 call fglutinit 1102 call fglutinitdisplaymode(GLUT_SINGLE+GLUT_DEPTH) 1103 call fglutcreatewindow('Fortran GLUT program') 1104 call fglutDisplayFunc(display) 1105 call fglutReshapeFunc(reshape) 1106 call fglEnable(GL_DEPTH_TEST) 1107 call fglEnable(GL_LIGHTING) 1108 call fglEnable(GL_LIGHT0) 1109 call fglClearColor(1.0, 1.0, 1.0, 1.0) 1110 call fglutmainloop 1111 end 1112 \end{verbatim} 1113 } 1114 1115 \begin{figure}[htbp] 1116 \centering 1117 \includegraphics[width=2.5in]{cube-f} 1118 \caption{Osenčen model kocke z napisi} 1119 \label{fig:cube-f} 1120 \end{figure} 1057 {{{ 1058 #!c 1059 #include <GL/glut.h> 1060 1061 float kvadrat(char *s) 1062 { 1063 char *c; 1064 glPushMatrix(); 1065 glTranslatef(0.0, 0.0, 1.0); 1066 glNormal3f(0.0, 0.0, 1.0); 1067 glRectf(-1.0, -1.0, 1.0, 1.0); 1068 glTranslatef(-0.8, 0.0, 0.01); 1069 glDisable(GL_LIGHTING); 1070 glScalef(0.003, 0.003, 0.003); 1071 glColor3f(1.0, 0.0, 0.0); 1072 for(c=s; *c; c++) 1073 { 1074 glutStrokeCharacter(GLUT_STROKE_ROMAN, *c); 1075 } 1076 glEnable(GL_LIGHTING); 1077 glPopMatrix(); 1078 } 1079 1080 void display() 1081 { 1082 float mat[4]={0.9, 0.6, 0.3, 1.0}; 1083 glClear(GL_COLOR_BUFFER_BIT); 1084 glClear(GL_DEPTH_BUFFER_BIT); 1085 glPushMatrix(); 1086 glRotatef(30.0, 1.0, 0.0, 0.0); 1087 glRotatef(30.0, 0.0, 1.0, 0.0); 1088 glScalef(0.5, 0.5, 0.5); 1089 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat); 1090 kvadrat("Spredaj"); 1091 glRotatef(90.0, 0.0, 1.0, 0.0); 1092 kvadrat("Desno"); 1093 glRotatef(90.0, 0.0, 1.0, 0.0); 1094 kvadrat("Zadaj"); 1095 glRotatef(90.0, 0.0, 1.0, 0.0); 1096 kvadrat("Levo"); 1097 glRotatef(90.0, 1.0, 0.0, 0.0); 1098 kvadrat("Spodaj"); 1099 glRotatef(180.0, 1.0, 0.0, 0.0); 1100 kvadrat("Zgoraj"); 1101 glPopMatrix(); 1102 glFlush(); 1103 } 1104 1105 void reshape (int w, int h) 1106 { 1107 double l; 1108 l = 1; 1109 glViewport (0, 0, w, h); 1110 glMatrixMode (GL_PROJECTION); 1111 glLoadIdentity(); 1112 glOrtho(-l, l, -l, l, -l, l); 1113 glMatrixMode(GL_MODELVIEW); 1114 glLoadIdentity(); 1115 } 1116 1117 int main(int argc, char *argv[]) 1118 { 1119 glutInit(&argc, argv); 1120 glutInitDisplayMode(GLUT_SINGLE|GLUT_DEPTH); 1121 glutCreateWindow("C GLUT program"); 1122 glutDisplayFunc(display); 1123 glutReshapeFunc(reshape); 1124 glEnable(GL_DEPTH_TEST); 1125 glEnable(GL_LIGHTING); 1126 glEnable(GL_LIGHT0); 1127 glClearColor(1.0, 1.0, 1.0, 1.0); 1128 glutMainLoop(); 1129 return 0; 1130 } 1131 }}} 1121 1132 1122 1133 Podajanje barve za površino je spremenjeno tako, da se ne uporabi 1123 funkcije \emph{Color}ampak normalno funkcijo za podajanje lastnosti1124 materialaf \texttt{glMaterialfv}. Rezultat kaže slika1125 \ref{fig:cube-f}. če bi napisali komentar pred izrisom1134 funkcije ''Color'' ampak normalno funkcijo za podajanje lastnosti 1135 materialaf ''glMaterialfv''. Rezultat kaže slika 1136 6. Če bi napisali komentar pred izrisom 1126 1137 štirikotnika, potem bi bilo vidno besedilo tudi za ostale 1127 1138 (skrite) strani. 1139 1140 [[Image(cube-f.png)]] 1141 1142 Slika 6: Osenčen model kocke z napisi 1128 1143 1129 1144 Včasih pa raje želimo, da se besedilo na zaslonu ne 1130 1145 izrisuje rotirano in senčeno, temveč da se le pojavi na 1131 1146 določenem položaju v prostoru in potem izriše v zaslonskih 1132 koordinatah. V ta namen uporabimo \emph{bitmap}fonte in naslednji1147 koordinatah. V ta namen uporabimo ''bitmap'' fonte in naslednji 1133 1148 podprogram za izpis besedila: 1134 {\scriptsize\begin{verbatim} 1135 subroutine output(x,y,z,s) 1136 character s*(*) 1137 call fglRasterPos3f(x,y,z) 1138 lenc = len(s) 1139 do i=1,lenc 1140 call fglutBitmapCharacter(6, ichar(s(i:i))) 1141 end do 1142 end 1143 \end{verbatim} 1144 } 1145 Primer izrisa z bitmap fonti kaže slika \ref{fig:cube-b} 1146 \begin{figure}[htbp] 1147 \centering 1148 \includegraphics[width=2.5in]{cube-b} 1149 \caption{Osenčen model kocke z \emph{bitmap} napisi} 1150 \label{fig:cube-b} 1151 \end{figure} 1149 1150 {{{ 1151 #!c 1152 float output(x,y,z,char *s) 1153 { 1154 char *c; 1155 glRasterPos3f(x,y,z); 1156 for(c=s; *c; c++) 1157 { 1158 glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c); 1159 } 1160 } 1161 }}} 1162 1163 Primer izrisa z bitmap fonti kaže slika 7. 1164 1165 [[Image(cube-b.png)]] 1166 1167 Slika 7: Osenčen model kocke z ''bitmap'' napisi 1152 1168 1153 1169 1154 1170 = Uporabniški vmesnik = 1171 1155 1172 V nadaljevanju so prikazani primeri programov, ki izkoriščajo 1156 1173 dodatne funkcionalnost knjižnice GLUT za vnos dodatnih podatkov v 1157 1174 program. To je predvsem uporaba tipk in miške. 1158 1175 1159 \subsection{Rotacija s tipkami} 1160 Rotiramo že vgrajeni geometrijski model čajnika s tipkami \textbf{x, 1161 y, z}. Vsak pritisk na tipko poveča kot rotacije za pet stopinj. 1162 Podatke o trenutni rotaciji prenašamo s poljem \texttt{common}. Ker 1163 izrisujemo žični model, podprogram za \emph{reshape} ni 1164 potreben. Podprogram \emph{keyboard} ob pritisku na tipko dobi tudi 1176 == Rotacija s tipkami == 1177 1178 Rotiramo že vgrajeni geometrijski model čajnika s tipkami '''x, 1179 y, z'''. Vsak pritisk na tipko poveča kot rotacije za pet stopinj. 1180 Ker 1181 izrisujemo žični model, podprogram za ''reshape'' ni 1182 potreben. Podprogram ''keyboard'' ob pritisku na tipko dobi tudi 1165 1183 informacijo o zaslonskem položaju miške. 1166 1184 1167 {\scriptsize\begin{verbatim} 1168 subroutine display 1169 implicit none 1170 include 'GL/fgl.h' 1171 common /rotation/ rx, ry, rz 1172 real rx, ry, rz 1173 call fglClear(GL_COLOR_BUFFER_BIT) 1174 call fglColor3f(0.5, 0.4, 1.0) 1175 call fglPushMatrix 1176 call fglRotatef(rx, 1.0, 0.0, 0.0) 1177 call fglRotatef(ry, 0.0, 1.0, 0.0) 1178 call fglRotatef(rz, 0.0, 0.0, 1.0) 1179 call fglutWireTeapot(dble(r)) 1180 call fglPopMatrix 1181 call fglutSwapBuffers 1182 end 1183 1184 subroutine keyboard(key,x,y) 1185 common /rotation/ rx, ry, rz 1186 integer key,x,y 1187 print *, 'Key ', char(key), key, ' at', x, y 1188 if (key .eq. ichar('x')) rx = rx + 5.0 1189 if (key .eq. ichar('y')) ry = ry + 5.0 1190 if (key .eq. ichar('z')) rz = rz + 5.0 1191 call fglutpostredisplay 1192 end 1193 1194 program teapot 1195 external display 1196 external keyboard 1197 include 'GL/fglut.h' 1198 integer window 1199 call fglutInit 1200 call fglutInitDisplayMode(ior(GLUT_DOUBLE,GLUT_RGB)) 1201 window = fglutCreateWindow('Use keys x, y, and z') 1202 call fglutDisplayFunc(display) 1203 call fglutKeyboardFunc(keyboard) 1204 call fglutMainLoop 1205 end 1206 \end{verbatim} 1207 } 1208 1209 1210 \subsection{Miška in inverzna projekcija} 1185 {{{ 1186 #!c 1187 #include <stdio.h> 1188 #include <GL/glut.h> 1189 1190 float rx, ry, rz; 1191 1192 void display() 1193 { 1194 glClear(GL_COLOR_BUFFER_BIT); 1195 glColor3f(0.5, 0.4, 1.0); 1196 glPushMatrix(); 1197 glRotatef(rx, 1.0, 0.0, 0.0); 1198 glRotatef(ry, 0.0, 1.0, 0.0); 1199 glRotatef(rz, 0.0, 0.0, 1.0); 1200 glutWireTeapot(0.5); 1201 glPopMatrix(); 1202 glutSwapBuffers(); 1203 } 1204 1205 void keyboard(unsigned char key, int x, int y) 1206 { 1207 fprintf (stderr,"Key %c at %d, %d\n", key, x, y); 1208 if (key=='x') 1209 rx = rx + 5.0; 1210 if (key=='y') 1211 ry = ry + 5.0; 1212 if (key=='z') 1213 rz = rz + 5.0; 1214 glutPostRedisplay(); 1215 } 1216 1217 int main(int argc, char *argv[]) 1218 { 1219 glutInit(&argc, argv); 1220 glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); 1221 glutCreateWindow("Use keys x, y, and z"); 1222 glutDisplayFunc(display); 1223 glutKeyboardFunc(keyboard); 1224 glutMainLoop(); 1225 return 0; 1226 } 1227 }}} 1228 1229 == Miška in inverzna projekcija == 1230 1211 1231 Za vsak pritisk gumba miške lahko dobimo poleg koordinate tudi 1212 1232 še stanje gumbov. Naslednji primer prikazuje risanje črte v … … 1494 1514 Na urejanje kode lahko uporabimo DOS-ov urejevalnik EDIT ali Windows 1495 1515 notepad. Oba imata svoje slabosti; EDIT ima težave z daljšimi 1496 imeni datotek, NOTEPAD pa nima pri 1516 imeni datotek, NOTEPAD pa nima prikaza trenutne vrstice in ob prvem 1517 shranjevanju datoteke lepi konŔnico \texttt{.txt}, tako da moramo 1518 datoteko kasneje preimenovati v \texttt{.f}. Kljub slabostim sta oba 1519 urejevalnika primerna za Üolske probleme. 1520 1521 V trenutnem imeniku DOS okna odtipkamo izbrani ukaz: 1522 \begin{verbatim} 1523 notepad teapot.f 1524 edit teapot.f 1525 \end{verbatim} 1526