OpenGL er et kraftfuldt 3D programmeringsværktøj, der bruges til at tegne komplekse tredimensionale scener fra simple primitiver. Denne artikel vil lære dig at tegne en simpel terning, som du kan spinde for at se i tre dimensioner!

Til dette projekt skal du have en kode editor og en vis viden om C programmering.

Første del af fire:
Initial Setup og main ()

1) Installer OpenGL

  • For at begynde skal du følge disse trin for at installere OpenGL på dit system. Hvis du allerede har OpenGL og en compiler installeret, kan du springe over dette trin og gå til det næste.

2) Opret dokumentet

  • Opret en ny fil i din foretrukne kode editor og gem den som mycube.c

3) #includes

  • Dette er de grundlæggende forudsætninger, vi har brug for til vores program. Det er vigtigt at indse, at der faktisk er forskellige, der er nødvendige for de forskellige operativsystemer. Sørg for at inkludere alle disse for at sikre, at dit program er alsidigt og kan køre for enhver bruger.
     // Inkluderer #omfatte  #omfatte  #omfatte  #define GL_GLEXT_PROTOTYPES #ifdef __APPLE__ #omfatte  #andet #omfatte  #Afslut Hvis 

4) Funktionsprototyper og globale variabler

  • Vores næste skridt er at erklære nogle funktionsprototyper.
     // Funktion Prototyper ugyldig Skærm(); ugyldig specialKeys(); // Globale Variabler dobbelt rotate_y=0; dobbelt rotate_x=0; 
  • Jeg vil forklare hver af disse funktioner og de globale variabler i detaljer, som vi implementerer dem senere i denne vejledning. For nu er det vigtigt at du erklærer dem.

5) Indstilling af hovedfunktionen ()

  •  int vigtigste(int argc, char* argv[]) // Initialiser GLUT og behandle brugerparametre glutInit(&argc,argv); // Forespørg dobbeltbuffet ægte farvevindue med Z-buffer glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 
  • Denne erklæring opstiller vores miljø. En stor ting at huske, når du skriver OpenGL-programmer er, at du skal bede om alt. Dette kræver, at du har en større forståelse for, hvordan dit program fungerer, og hvad du skal medtage for at få den funktionalitet, du ønsker. I denne linje opretter vi displayet med dobbeltbuffering, RGB-farve og en Z-buffer.
  • Dobbelt buffering er en teknik, der bruges i grafikprogrammer til at eliminere et problem, der opstår på grund af, hvordan billeder trækkes på skærmen. Hver gang vi redraver scenen, skal displayet først slettes, så de nye oplysninger trækkes. Uden dobbelt buffering vil du observere en flimrende effekt, da skærmen slettes og gentages gentagne gange.
    Dette problem løses ved at tilføje en anden buffer til at tegne til. Med denne metode trækkes et billede til den første buffer og den buffer vises til dig. Den næste ramme vil blive trukket til den anden buffer, og når det er gjort, vil de to buffere skifte steder. Vi vil straks se den anden buffer, men skjult fra os bliver den første buffer slettet og genoptaget med den tredje ramme, som vil blive byttet ind, når den er færdig.
  • Vi ønsker også at aktivere RGB farve system i vores vindue. Jeg vil forklare mere om, hvordan farve bruges i OpenGL, når vi arbejder på displayfunktionen.
  • Z-buffering er, hvordan vi får de 3D-effekter, vi ønsker. OpenGL bruger et tredimensionalt koordinatsystem med x, y og z akser. For at give den effekt, at et objekt er tættere på dig, er dets position på z-aksen øget, men for at gøre det længere væk, sænkes dets position på z-aksen. Jeg vil tale lidt mere om dette, når vi tegner vores hjørner til terningen.

6) Oprettelse af vinduet

  • Det næste skridt er at opret vinduet indenfor hvilken vi trækker terningen. I denne vejledning kalder jeg vores vindue "Awesome Cube".
     // Opret vindue glutCreateWindow("Awesome Cube"); 

7) Aktiver dybdestest

  • OpenGL er et strengt sprog, fordi det ikke går ud fra, at specielle funktioner er aktiveret. For vores program til korrekt visning i 3-dimensioner ved hjælp af Z-bufferen, som vi kiggede på tidligere, skal vi aktiver dybdestest. Som du fortsætter med at udforske OpenGL, vil du opdage mange funktioner, som du skal bruge for at muliggøre lys, teksturer, cull-facing og meget mere.
     // Aktiver Z-buffer dybde test glEnable(GL_DEPTH_TEST); 

8) Tilbagekaldelsesfunktioner

  • Her er tilbagekaldsfunktionerne, vi skrev prototyperne til tidligere. Hver gang gennem hovedløkken kaldes disse funktioner. Displayfunktionen genopretter scenen baseret på ændringer af variabler, der blev foretaget siden det foregående opkald. Funktionen SpecialKeys giver os mulighed for at interagere med programmet.
     // Tilbagekaldsfunktioner glutDisplayFunc(Skærm); glutSpecialFunc(specialKeys); 

9) Tilbagekaldelsesfunktioner

  • Det sidste trin i vores første opsætning er at start MainLoop. Dette vil huske hovedfunktionen, indtil vi lukker programmet for at tillade animationer og brugerinteraktion.
     // Send kontrol til GLUT for begivenheder glutMainLoop(); // Tilbage til OS Vend tilbage 0;  

Del to på fire:
Displayet () Funktion

  • Alt arbejdet med at tegne vores terning skal udføres i denne funktion. Den generelle ide bag vores terning er at tegne alle seks sider individuelt og placere dem i den rigtige position.
  • Konceptuelt vil hver side tegnes ved at definere de fire hjørner og lade OpenGL forbinde linjerne og udfylde det med en farve, som vi definerer. Nedenfor er trinnene til at gøre dette.

1) glClear ()

  • Det første skridt, vi skal tage i denne funktion er at Fjern farven og Z-bufferen. Uden disse trin kan de gamle tegninger stadig være synlige under de nye tegninger, og objekter trukket ville ikke være i den rigtige placering på skærmen.
     ugyldig Skærm() // Ryd skærm og Z-buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 

2) glBegin () og glEnd ()

  • OpenGL definerer objekter som kombinationer af forskellige polygoner. Bruger glBegin () kommando, vi sætter effektivt en blyant, der vil tegne en form.For at løfte blyanten og begynde en ny form, skal vi bruge glEnd () kommando. I denne øvelse bruger vi GL_POLYGON til at tegne hver side af terningen, men det er muligt at bruge andre parameterindstillinger som GL_LINE, GL_QUAD eller GL_TRIANGLE for at oprette andre former.
  • Her begynder vi med vores kubes front. Senere vil vi tilføje farve til alle 6 sider.
     // Multi-farvet side - FRONT glBegin(GL_POLYGON); // Overskrifter vil blive tilføjet i næste trin glEnd(); 

3) glVertex3f ()

  • Når vi har sagt, at vi vil begynde vores polygon, skal vi definer hjørnerne af objektet. glVertex har flere former afhængigt af hvad du vil gøre med dit objekt.
  • Den første er, hvor mange dimensioner du arbejder i. De 3 ovenfor i glVertex3f siger, at vi tegner i 3 dimensioner. Det er også muligt at arbejde i 2 eller 4 dimensioner. F ovenfor i glVertex3f siger, at vi arbejder med flydende punktnumre. Du kan også bruge shorts, heltal eller doubler.
  • Bemærk, at disse punkter er defineret i a mod uret måde. Dette er ikke meget vigtigt i øjeblikket, men når vi begynder at arbejde med belysning, teksturer og cull-facing, bliver det utrolig vigtigt, så du bliver vant til at definere dine point mod uret nu.
  • Nu tilføjer vi punkterne mellem glBegin () og glEnd () linjerne.
     // Multi-farvet side - FRONT glBegin(GL_POLYGON); glVertex3f( -0.5, -0.5, -0.5); // P1 glVertex3f( -0.5, 0.5, -0.5); // P2 glVertex3f( 0.5, 0.5, -0.5); // P3 glVertex3f( 0.5, -0.5, -0.5); // P4 glEnd(); 

4) glColor3f ()

  • glColor fungerer på samme måde som glVertex. Vi kan definere punkter som shorts, heltal, doubler eller floats. Hver farve har en værdi fra 0 til 1. Alle 0'erne gør punktet sort og alle 1'erne vil gøre punktet hvidt. De 3 i glColor3f () refererer til RGB-farvesystemet uden alfakanal. Alfabetet i en farve definerer gennemsigtigheden. For at ændre alfa-niveauet skal du bruge glColor4f (), hvor den sidste parameter er en værdi på 0 til 1 for uigennemsigtig til gennemsigtig.
  • Når vi kalder glColor3f (), vil hvert vertex trukket fra dette punkt være af den farve. Derfor, hvis vi vil have alle fire hjørner til at være røde, skal du bare indstille farven en gang helst før kommandoerne glVertex3f () og alle hjørner bliver røde.
  • Forsiden defineret nedenfor viser, hvordan du definerer en ny farve for hvert hjørne. Når vi gør dette, kan vi se en interessant egenskab af OpenGL farverne. Da hvert hjørne af polygonen har sin egen farve, vil OpenGL automatisk blande farverne! Det næste trin viser, hvordan du tildeler fire hjørner med samme farve.
     // Multi-farvet side - FRONT glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.5, -0.5, -0.5 ); // P1 er rød glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( 0.5, 0.5, -0.5 ); // P2 er grøn glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( -0.5, 0.5, -0.5 ); // P3 er blå glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( -0.5, -0.5, -0.5 ); // P4 er lilla glEnd(); 

5) De andre sider

  • Jeg opfordrer dig til at finde ud af, hvor placeringen af ​​hvert hjørne vil være for de andre fem sider af terningen, men for enkelhed har jeg beregnet dem til dig og har medtaget dem i vores endelig visning () funktion under.
     // Hvid side - TILBAGE glBegin(GL_POLYGON); glColor3f( 1.0, 1.0, 1.0 ); glVertex3f( 0.5, -0.5, 0.5 ); glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( -0.5, 0.5, 0.5 ); glVertex3f( -0.5, -0.5, 0.5 ); glEnd(); // Lilla side - HØJRE glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( 0.5, -0.5, -0.5 ); glVertex3f( 0.5, 0.5, -0.5 ); glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( 0.5, -0.5, 0.5 ); glEnd(); // Grøn side - VENSTRE glBegin(GL_POLYGON); glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( -0.5, -0.5, 0.5 ); glVertex3f( -0.5, 0.5, 0.5 ); glVertex3f( -0.5, 0.5, -0.5 ); glVertex3f( -0.5, -0.5, -0.5 ); glEnd(); // Blå side - TOP glBegin(GL_POLYGON); glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( 0.5, 0.5, -0.5 ); glVertex3f( -0.5, 0.5, -0.5 ); glVertex3f( -0.5, 0.5, 0.5 ); glEnd(); // Rød side - BOTTOM glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.5, -0.5, -0.5 ); glVertex3f( 0.5, -0.5, 0.5 ); glVertex3f( -0.5, -0.5, 0.5 ); glVertex3f( -0.5, -0.5, -0.5 ); glEnd(); glFlush(); glutSwapBuffers();  


  • Vi vil også tilføje i to sidste linjer kode for denne funktion. Disse er glFlush (); og glutSwapBuffers (); som giver os den dobbeltbufferende effekt, vi lærte om tidligere.

Del tre af fire:
Brugerinteraktivitet

1) specialKeys ()

  • Vi er næsten færdige, men i øjeblikket kan vi tegne en terning, men har ingen måde at rotere den på. For at gøre dette, vil vi opret en specialKeys () funktion, så vi kan trykke piletasterne og dreje terningen!
  • Denne funktion er hvorfor vi erklærede de globale variabler rotate_x og rotate_y. Når vi trykker på højre og venstre piletasterne, vil rotat_i blive forøget eller formindsket med 5 grader. På samme måde, når vi trykker op og ned piletasterne, vil rotate_x ændre sig i overensstemmelse hermed.
     ugyldig specialKeys( int nøgle, int x, int y )  // Højre pil - øg rotation med 5 grader hvis (nøgle == GLUT_KEY_RIGHT) rotate_y += 5; // Venstre pil - mindsk rotationen med 5 grader andet hvis (nøgle == GLUT_KEY_LEFT) rotate_y -= 5; andet hvis (nøgle == GLUT_KEY_UP) rotate_x += 5; andet hvis (nøgle == GLUT_KEY_DOWN) rotate_x -= 5; // Request display update glutPostRedisplay();  

2) glRotate ()

  • Vores sidste erklæring er at tilføje den erklæring, der vil rotere vores objekt. Gå tilbage til Skærm() funktion og før FRONT side, tilføj disse linjer:
     // Nulstil transformationer glLoadIdentity(); // Rotere, når brugeren ændrer rotate_x og rotate_y glRotatef( rotate_x, 1.0, 0.0, 0.0 ); glRotatef( rotate_y, 0.0, 1.0, 0.0 ); // Multi-farvet side - FRONT


  • Først bemærk at syntaksen af glRotatef () ligner den af ​​glColor3f () og glVertex3f () men kræver altid 4 parametre. Den første parameter er den rotationsgrad, der skal anvendes. De næste tre parametre definerer hvilken akse der skal roteres om, idet den første er x-aksen, den anden er y-aksen, og tredje er z-akse. Lige nu behøver vi kun at rotere om x og y-aksen.
  • Alle transformationer, som vi skriver i vores program, har brug for linjer svarende til dette. Konceptuelt tænker vi på dette som at rotere vores objekt om x-aksen med det beløb, der er defineret af rotate_x og derefter rotere rundt om y-aksen ved at rotere_y. OpenGL kombinerer imidlertid alle disse udsagn i en matrix transformation. Hver gang vi kalder displayfunktionen, bygger vi en transformationsmatrix og glLoadIdentity () sikrer, at vi vil starte med en ny matrix i hvert pass.
  • De andre transformationsfunktioner, vi kunne anvende, er glTranslatef () og glScalef (). Disse funktioner ligner glRotatef () med den undtagelse, at de kun tager 3 parametre, x, y og z svarer til at oversætte eller skala objektet.
  • For at få den korrekte effekt, når du anvender alle tre transformationer til et objekt, skal vi anvende dem i den rigtige rækkefølge. Skriv dem altid i ordren glTranslate, glRotate, derefter glScale. OpenGL anvender i det væsentlige transformationerne i bunden. For at forstå dette, prøv at forestille sig, hvad en enkel 1x1x1 kube vil se ud med transformationerne, hvis OpenGL anvender dem fra top til bund, og hvis OpenGL anvender dem fra bund til top.
  • Tilføj følgende kommandoer for at skala terningen med 2 langs x-aksen, 2 langs y-aksen, drej terningen 180 grader om y-aksen og oversæt terningen med 0,1 langs x-aksen. Sørg for at arrangere disse såvel som de foregående kommandoer glRotate () i den korrekte rækkefølge som beskrevet ovenfor. (Hvis du er i tvivl, har jeg gjort det i den endelige kode i slutningen af ​​vejledningen.)
     // Andre transformationer glTranslatef( 0.1, 0.0, 0.0 ); glRotatef( 180, 0.0, 1.0, 0.0 ); glScalef( 2.0, 2.0, 0.0 ); 

kompilering

  • Det allerførste skridt til at afslutte dit første OpenGL-projekt er at kompilere og kør din kode. Hvis du antager at du bruger gcc som din compiler, skal du køre disse kommandoer fra din terminal for at kompilere og teste dit program.
     På Linux: gcc cube.c -o terning -lglut -lGL ./ mycube på Mac: gcc -o foo foo.c -framework GLUT -framework OpenGL./ mycube på Windows: gcc -Væg -ofoo foo.c -lglut32cu -lglu32 -lopengl32 ./ mycube 

Del fire på fire:
Endelig kode

  • Der har du det. Dit første OpenGL-program! Jeg har forsynet dig med min kildekode nedenfor som et referencepunkt.
     // // Fil: mycube.c // Forfatter: Matt Daisley // Oprettet: 4/25/2012 // Projekt: Kildekode for Make a Cube i OpenGL // Beskrivelse: Opretter et OpenGL-vindue og tegner en 3D-terning // At brugeren kan rotere ved hjælp af piletasterne //  // Kontrol: Venstrepil - Drej til venstre // Højre pil - Drej til højre // Pil op - Roter op // Pil ned - Roter ned  // ---------------------------------------------------------- // Inkluderer // ---------------------------------------------------------- #omfatte  #omfatte  #omfatte  #define GL_GLEXT_PROTOTYPES #ifdef __APPLE__ #omfatte  #andet #omfatte  #Afslut Hvis // ---------------------------------------------------------- // Funktion Prototyper // ---------------------------------------------------------- ugyldig Skærm(); ugyldig specialKeys(); // ---------------------------------------------------------- // Globale Variabler // ---------------------------------------------------------- dobbelt rotate_y=0; dobbelt rotate_x=0; // ---------------------------------------------------------- // display () Tilbagekaldsfunktion // ---------------------------------------------------------- ugyldig Skærm() // Ryd skærm og Z-buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Nulstil transformationer glLoadIdentity(); // Andre transformationer // glTranslatef (0,1, 0,0, 0,0); // Ikke inkluderet // glRotatef (180, 0,0, 1,0, 0,0); // Ikke inkluderet // Rotere, når brugeren ændrer rotate_x og rotate_y glRotatef( rotate_x, 1.0, 0.0, 0.0 ); glRotatef( rotate_y, 0.0, 1.0, 0.0 ); // Andre transformationer // glScalef (2,0, 2,0, 0,0); // Ikke inkluderet // Multi-farvet side - FRONT glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.5, -0.5, -0.5 ); // P1 er rød glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( 0.5, 0.5, -0.5 ); // P2 er grøn glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( -0.5, 0.5, -0.5 ); // P3 er blå glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( -0.5, -0.5, -0.5 ); // P4 er lilla glEnd(); // Hvid side - TILBAGE glBegin(GL_POLYGON); glColor3f( 1.0, 1.0, 1.0 ); glVertex3f( 0.5, -0.5, 0.5 ); glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( -0.5, 0.5, 0.5 ); glVertex3f( -0.5, -0.5, 0.5 ); glEnd(); // Lilla side - HØJRE glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( 0.5, -0.5, -0.5 ); glVertex3f( 0.5, 0.5, -0.5 ); glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( 0.5, -0.5, 0.5 ); glEnd(); // Grøn side - VENSTRE glBegin(GL_POLYGON); glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( -0.5, -0.5, 0.5 ); glVertex3f( -0.5, 0.5, 0.5 ); glVertex3f( -0.5, 0.5, -0.5 ); glVertex3f( -0.5, -0.5, -0.5 ); glEnd(); // Blå side - TOP glBegin(GL_POLYGON); glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( 0.5, 0.5, 0.5 ); glVertex3f( 0.5, 0.5, -0.5 ); glVertex3f( -0.5, 0.5, -0.5 ); glVertex3f( -0.5, 0.5, 0.5 ); glEnd(); // Rød side - BOTTOM glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.5, -0.5, -0.5 ); glVertex3f( 0.5, -0.5, 0.5 ); glVertex3f( -0.5, -0.5, 0.5 ); glVertex3f( -0.5, -0.5, -0.5 ); glEnd(); glFlush(); glutSwapBuffers();  // ---------------------------------------------------------- // specialKeys () Tilbagekaldelsesfunktion // ---------------------------------------------------------- ugyldig specialKeys( int nøgle, int x, int y )  // Højre pil - øg rotation med 5 grader hvis (nøgle == GLUT_KEY_RIGHT) rotate_y += 5; // Venstre pil - mindsk rotationen med 5 grader andet hvis (nøgle == GLUT_KEY_LEFT) rotate_y -= 5; andet hvis (nøgle == GLUT_KEY_UP) rotate_x += 5; andet hvis (nøgle == GLUT_KEY_DOWN) rotate_x -= 5; // Request display update glutPostRedisplay();  // ---------------------------------------------------------- // main () funktion // ---------------------------------------------------------- int vigtigste(int argc, char* argv[]) // Initialiser GLUT og behandle brugerparametre glutInit(&argc,argv); // Forespørg dobbeltbuffet ægte farvevindue med Z-buffer glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // Opret vindue glutCreateWindow("Awesome Cube"); // Aktiver Z-buffer dybde test glEnable(GL_DEPTH_TEST); // Tilbagekaldsfunktioner glutDisplayFunc(Skærm); glutSpecialFunc(specialKeys); // Send kontrol til GLUT for begivenheder glutMainLoop(); // Tilbage til OS Vend tilbage 0;