OpenGL is een krachtige 3D-programmeer-tool die wordt gebruikt om complexe driedimensionale scènes te tekenen van eenvoudige primitieven. In dit artikel leer je hoe je een eenvoudige kubus kunt tekenen die je kunt draaien om in drie dimensies te bekijken!

Voor dit project heb je een code-editor nodig en enige kennis van C-programmeren.

Deel een van de vier:
Eerste installatie en hoofd ()

1) Installeer OpenGL

  • Volg deze stappen om te beginnen met het installeren van OpenGL op uw systeem. Als u al OpenGL en een c-compiler hebt geïnstalleerd, kunt u deze stap overslaan en naar de volgende gaan.

2) Maak het document

  • Maak een nieuw bestand in uw favoriete codebewerker en sla het op als mycube.c

3) # omvat

  • Dit zijn de basis die we nodig hebben voor ons programma. Het is belangrijk om te beseffen dat er eigenlijk verschillende onderdelen zijn vereist voor de verschillende besturingssystemen. Zorg ervoor dat u al deze elementen opneemt om ervoor te zorgen dat uw programma veelzijdig is en voor elke gebruiker kan worden gebruikt.
     // Inclusief #include  #include  #include  #define GL_GLEXT_PROTOTYPES #ifdef __APPLE__ #include  #anders #include  #stop als 

4) Functie-prototypen en globale variabelen

  • Onze volgende stap is om een ​​aantal functie-prototypen te declareren.
     // Functie-prototypen leegte tonen(); leegte specialKeys(); // Globale variabelen dubbele rotate_y=0; dubbele rotate_x=0; 
  • Ik zal elk van deze functies en de globale variabelen in detail uitleggen wanneer we ze later in deze zelfstudie implementeren. Voor nu is het belangrijk dat u ze declareert.

5) De hoofdfunctie () instellen

  •  int hoofd(int argc, verkolen* argv[]) // GLUT initialiseren en gebruikersparameters verwerken glutInit(&argc,argv); // Vraag dubbel gebufferd kleurenvenster met Z-buffer aan glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 
  • Deze verklaring zet onze omgeving op. Een groot ding om te onthouden bij het schrijven van OpenGL-programma's is dat je alles moet vragen. Dit vereist dat u meer inzicht heeft in hoe uw programma werkt en wat u moet opnemen om de functionaliteit te krijgen die u wilt. In deze regel stellen we de weergave in met dubbele buffering, RGB-kleur en een Z-buffer.
  • Dubbele buffering is een techniek die wordt gebruikt in grafische programma's om een ​​probleem op te lossen dat ontstaat door de manier waarop afbeeldingen naar het scherm worden getrokken. Telkens wanneer we de scène opnieuw tekenen, moet het display eerst worden gewist en de nieuwe informatie worden getekend. Zonder dubbele buffering ziet u een flikkerend effect terwijl het scherm wordt gewist en herhaaldelijk opnieuw wordt getekend.
    Dit probleem wordt opgelost door een tweede buffer toe te voegen om naartoe te tekenen. Met deze methode wordt een afbeelding getekend naar de eerste buffer en wordt die buffer aan u getoond. Het volgende frame wordt naar de tweede buffer getrokken en als dat is gebeurd, wisselen de twee buffers van positie. We zullen onmiddellijk de tweede buffer zien, maar voor ons verborgen, wordt de eerste buffer gewist en opnieuw getekend met het derde frame dat zal worden verwisseld wanneer voltooid.
  • We willen ook de RGB-kleur systeem in ons venster. Ik zal meer uitleggen over hoe kleur wordt gebruikt in OpenGL wanneer we werken aan de weergavefunctie.
  • Z-buffering is hoe we de 3D-effecten krijgen die we willen hebben. OpenGL gebruikt een driedimensionaal coördinatensysteem met x-, y- en z-assen. Om het effect te geven dat een voorwerp dichter bij u staat, wordt zijn positie op de z-as vergroot, maar om het verder weg te laten lijken, wordt zijn positie op de z-as verminderd. Ik zal hier wat meer over vertellen wanneer we onze hoekpunten voor de kubus tekenen.

6) Het venster maken

  • De volgende stap is om maak het venster waarbinnen we de kubus tekenen. In deze tutorial bel ik ons ​​venster "Awesome Cube".
     // Maak een venster glutCreateWindow("Awesome Cube"); 

7) Dieptetest inschakelen

  • OpenGL is een strikte taal omdat het er niet vanuit gaat dat speciale functies zijn ingeschakeld. Om ons programma op de juiste manier weer te geven in 3D-dimensies met behulp van de Z-buffer waarnaar we eerder hebben gekeken, moeten we dit doen maak dieptetest mogelijk. Terwijl u doorgaat met het verkennen van OpenGL, zult u vele functies ontdekken die u nodig hebt, zoals verlichting, texturen, ruiming en nog veel meer.
     // Z-buffer dieptetest inschakelen glEnable(GL_DEPTH_TEST); 

8) Callback-functies

  • Hier zijn de callback-functies die we eerder voor de prototypes hebben geschreven. Elke keer via de hoofdlus worden deze functies opgeroepen. De weergavefunctie hertekent de scène opnieuw op basis van eventuele wijzigingen in variabelen die zijn gemaakt sinds de vorige oproep. Met de functie SpecialKeys kunnen we het programma gebruiken.
     // Terugbelfuncties glutDisplayFunc(tonen); glutSpecialFunc(specialKeys); 

9) Terugroepfuncties

  • De laatste stap in onze initiële setup is om start de MainLoop. Hiermee wordt de hoofdfunctie opgeroepen totdat we het programma sluiten om animaties en gebruikersinteractie mogelijk te maken.
     // Geef controle door aan GLUT voor evenementen glutMainLoop(); // Keer terug naar OS terugkeer 0;  

Deel twee van vier:
De display () functie

  • Al het werk van het tekenen van onze kubus zal in deze functie gedaan worden. Het algemene idee achter onze kubus is om alle zes zijden afzonderlijk te tekenen en ze in de juiste positie te plaatsen.
  • Conceptueel wordt elke zijde getekend door de vier hoeken te definiëren en OpenGL de lijnen te laten verbinden en in te vullen met een kleur die we definiëren. Hieronder zijn de stappen om dit te doen.

1) glClear ()

  • De eerste stap die we moeten zetten in deze functie is om wis de kleur en Z-buffer. Zonder deze stappen kunnen de oude tekeningen nog steeds zichtbaar zijn onder de nieuwe tekeningen en mogen de getekende objecten niet op de juiste locatie op het scherm staan.
     leegte tonen() // Scherm en Z-buffer wissen glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 

2) glBegin () en glEnd ()

  • OpenGL definieert objecten als combinaties van verschillende polygonen. De ... gebruiken glBegin () opdracht, we plaatsen een potlood dat een vorm zal tekenen.Om het potlood op te tillen en een nieuwe vorm te beginnen, moeten we de Glend () opdracht. In deze zelfstudie gebruiken we GL_POLYGON om elke kant van de kubus te tekenen, maar het is mogelijk om andere parameteropties te gebruiken, zoals GL_LINE, GL_QUAD of GL_TRIANGLE om andere vormen te maken.
  • Hier zullen we beginnen met de voorkant van onze kubus. Later zullen we kleur toevoegen aan alle 6 zijden.
     // Multi-gekleurde zijde - FRONT glBegin(GL_POLYGON); // Vertices worden in de volgende stap toegevoegd Glend(); 

3) glVertex3f ()

  • Zodra we hebben aangegeven dat we met onze polygoon willen beginnen, moeten we dit doen definieer de hoekpunten van het object. glVertex heeft meerdere formulieren, afhankelijk van wat u met uw object wilt doen.
  • De eerste is het aantal dimensies waarin je werkt. De 3 hierboven in glVertex3f zegt dat we in 3 dimensies tekenen. Het is ook mogelijk om in 2 of 4 dimensies te werken. Het bovenstaande in glVertex3f zegt dat we werken met getallen met een drijvende komma. U kunt ook shorts, gehele getallen of dubbele items gebruiken.
  • Merk op dat deze punten zijn gedefinieerd in a tegen de klok in manier. Dit is op dit moment niet erg belangrijk, maar wanneer we beginnen te werken met verlichting, texturen en opruimen, zal dit ongelooflijk belangrijk worden, dus maak er een gewoonte van om je punten tegen de klok in te definiëren.
  • Nu voegen we de hoekpunten toe tussen de regels glBegin () en glEnd ().
     // Multi-gekleurde zijde - 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 werkt op dezelfde manier als glVertex. We kunnen punten definiëren als shorts, integers, doubles of floats. Elke kleur heeft een waarde van 0 tot 1. Alle 0's maken het punt zwart en alle 1's zullen het punt wit maken. De 3 in glColor3f () verwijst naar het RGB-kleursysteem zonder alfakanaal. De alpha van een kleur definieert de transparantie ervan. Als u het alfaniveau wilt wijzigen, gebruikt u glColor4f (), waarbij de laatste parameter de waarde 0 tot 1 heeft voor dekkend tot transparant.
  • Wanneer we glColor3f () aanroepen, is elke vertex die vanaf dat punt wordt getekend van die kleur. Daarom, als we willen dat alle vier de hoekpunten rood zijn, stel dan de kleur eenmaal in voor de opdrachten glVertex3f () en alle hoekpunten rood.
  • De hieronder gedefinieerde voorkant laat zien hoe een nieuwe kleur voor elke vertex moet worden gedefinieerd. Wanneer we dit doen, zien we een interessante eigenschap van de OpenGL-kleuren. Omdat elk hoekpunt van de polygoon zijn eigen kleur heeft, zal OpenGL automatisch de kleuren mengen! De volgende stap laat zien hoe vier hoekpunten met dezelfde kleur kunnen worden toegewezen.
     // Multi-gekleurde zijde - FRONT glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.5, -0.5, -0.5 ); // P1 is rood glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( 0.5, 0.5, -0.5 ); // P2 is groen glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( -0.5, 0.5, -0.5 ); // P3 is blauw glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( -0.5, -0.5, -0.5 ); // P4 is paars Glend(); 

5) De andere kanten

  • Ik moedig je aan om uit te zoeken wat de locatie van elke vertex is voor de andere vijf zijden van de kubus, maar omwille van de eenvoud heb ik die voor je berekend en ze opgenomen in onze laatste weergave () functie hieronder.
     // Witte zijde - RUG 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(); // Paarse kant - RECHTS 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(); // Groene kant - LINKS 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(); // Blauwe zijde - 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(); // Rode zijde - BODEM 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();  


  • We willen ook twee laatste coderegels toevoegen voor deze functie. Dit zijn glFlush (); en glutSwapBuffers (); die ons het dubbele bufferende effect geven dat we eerder hebben geleerd.

Deel drie van vier:
Gebruikersinteractiviteit

1) specialKeys ()

  • We zijn bijna klaar, maar op dit moment kunnen we een kubus tekenen, maar we kunnen hem niet draaien. Om dit te doen, zullen we maak een specialKeys () functie om ons toe te staan ​​de pijltjestoetsen in te drukken en de kubus te draaien!
  • Deze functie verklaart waarom de globale variabelen rotate_x en rotate_y hebben gedeclareerd. Wanneer we op de pijltoetsen rechts en links drukken, wordt rotate_y met 5 graden verhoogd of verlaagd. Op dezelfde manier zal rotate_x overeenkomstig veranderen wanneer we op de pijltoetsen omhoog en omlaag drukken.
     leegte specialKeys( int sleutel, int X, int Y )  // Pijl naar rechts - rotatie met 5 graden verhogen als (sleutel == GLUT_KEY_RIGHT) rotate_y += 5; // Pijl naar links - rotatie met 5 graden verlagen anders als (sleutel == GLUT_KEY_LEFT) rotate_y -= 5; anders als (sleutel == GLUT_KEY_UP) rotate_x += 5; anders als (sleutel == GLUT_KEY_DOWN) rotate_x -= 5; // Verzoek om update van het display glutPostRedisplay();  

2) glRotate ()

  • Onze laatste verklaring is om de verklaring toe te voegen die ons object zal roteren. Ga terug naar de display () functie en vóór de FRONT-kant, voeg deze regels toe:
     // Transformaties resetten glLoadIdentity(); // Roteren wanneer gebruiker rotate_x en rotate_y wijzigt glRotatef( rotate_x, 1.0, 0.0, 0.0 ); glRotatef( rotate_y, 0.0, 1.0, 0.0 ); // Multi-gekleurde zijde - FRONT


  • Merk eerst op dat de syntaxis van glRotatef () is vergelijkbaar met glColor3f () en glVertex3f () maar heeft altijd 4 parameters nodig. De eerste parameter is de mate van rotatie die moet worden toegepast. De volgende drie parameters bepalen welke as ongeveer moet worden gedraaid, waarbij de eerste de x-as is, de tweede de y-as en de derde de z-as. Op dit moment hoeven we alleen maar rond de x- en y-as te draaien.
  • Alle transformaties die we in ons programma schrijven, hebben soortgelijke lijnen nodig. Conceptueel beschouwen we dit als het roteren van ons object rond de x-as met de hoeveelheid gedefinieerd door rotate_x en dan roterend rond de y-as door rotate_y. OpenGL combineert al deze instructies echter tot één matrixtransformatie. Elke keer dat we de weergavefunctie aanroepen, bouwen we een transformatiematrix en glLoadIdentity () zorgt ervoor dat we in elke gang beginnen met een nieuwe matrix.
  • De andere transformatiefuncties die we kunnen toepassen zijn glTranslatef () en glScalef (). Deze functies zijn vergelijkbaar met glRotatef () met de uitzondering dat ze slechts 3 parameters in beslag nemen, de x, y en z bedragen om het object te vertalen of te schalen.
  • Om het juiste effect te krijgen bij het toepassen van alle drie transformaties op één object, moeten we ze in de juiste volgorde toepassen. Schrijf ze altijd in de volgorde glTranslate, glRotate, then glScale. OpenGL past de transformaties in essentie op een bottom-up manier toe. Om dit te begrijpen, probeer je voor te stellen hoe een eenvoudige 1x1x1-kubus eruit zou zien met de transformaties als OpenGL ze van boven naar beneden toepaste en of OpenGL ze van onder naar boven toepaste.
  • Voeg de volgende opdrachten toe om de kubus langs de x-as met 2 te schalen, 2 langs de y-as, draai de kubus 180 graden rond de y-as en verplaats de kubus met 0,1 langs de x-as. Zorg ervoor dat deze evenals de vorige glRotate () -opdrachten in de juiste volgorde worden geplaatst zoals hierboven beschreven. (Als u het niet zeker weet, heb ik dit aan het einde van de zelfstudie gedaan in de definitieve code.)
     // Andere transformaties glTranslatef( 0.1, 0.0, 0.0 ); glRotatef( 180, 0.0, 1.0, 0.0 ); glScalef( 2.0, 2.0, 0.0 ); 

Het compileren

  • De allerlaatste stap om uw eerste OpenGL-project te voltooien is om compileer en voer je code uit. Ervan uitgaande dat u gcc als uw compiler gebruikt, voert u deze opdrachten uit vanaf uw terminal om uw programma te compileren en te testen.
     Op Linux: gcc cube.c -O kubus -lglut -lGL ./ mycube op Mac: gcc -O foo foo.c -kader GLUT -kader OpenGL./ mycube op Windows: gcc -Muur -ofoo foo.c -lglut32cu -lglu32 -lopengl32 ./ mycube 

Deel vier van vier:
Eindcode

  • Daar heb je het. Je eerste OpenGL-programma! Ik heb je mijn onderstaande broncode als referentiepunt verstrekt.
     // // Bestand: mycube.c // Auteur: Matt Daisley // Gecreëerd: 25/04/2012 // Project: broncode voor het maken van een kubus in OpenGL // Beschrijving: maakt een OpenGL-venster en tekent een 3D-kubus // Dat de gebruiker kan draaien met de pijltjestoetsen //  // Besturing: Pijl naar links - Links draaien // Right Arrow - Rotate Right // Pijl-omhoog - omhoog draaien // Pijl-omlaag - draai omlaag  // ---------------------------------------------------------- // Inclusief // ---------------------------------------------------------- #include  #include  #include  #define GL_GLEXT_PROTOTYPES #ifdef __APPLE__ #include  #anders #include  #stop als // ---------------------------------------------------------- // Functie-prototypen // ---------------------------------------------------------- leegte tonen(); leegte specialKeys(); // ---------------------------------------------------------- // Globale variabelen // ---------------------------------------------------------- dubbele rotate_y=0; dubbele rotate_x=0; // ---------------------------------------------------------- // weergave () Terugbelfunctie // ---------------------------------------------------------- leegte tonen() // Scherm en Z-buffer wissen glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Transformaties resetten glLoadIdentity(); // Andere transformaties // glTranslatef (0,1, 0,0, 0,0); // Niet inbegrepen // glRotatef (180, 0,0, 1,0, 0,0); // Niet inbegrepen // Roteren wanneer gebruiker rotate_x en rotate_y wijzigt glRotatef( rotate_x, 1.0, 0.0, 0.0 ); glRotatef( rotate_y, 0.0, 1.0, 0.0 ); // Andere transformaties // glScalef (2.0, 2.0, 0.0); // Niet inbegrepen // Multi-gekleurde zijde - FRONT glBegin(GL_POLYGON); glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.5, -0.5, -0.5 ); // P1 is rood glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( 0.5, 0.5, -0.5 ); // P2 is groen glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( -0.5, 0.5, -0.5 ); // P3 is blauw glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( -0.5, -0.5, -0.5 ); // P4 is paars Glend(); // Witte zijde - RUG 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(); // Paarse kant - RECHTS 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(); // Groene kant - LINKS 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(); // Blauwe zijde - 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(); // Rode zijde - BODEM 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 () Terugbelfunctie // ---------------------------------------------------------- leegte specialKeys( int sleutel, int X, int Y )  // Pijl naar rechts - rotatie met 5 graden verhogen als (sleutel == GLUT_KEY_RIGHT) rotate_y += 5; // Pijl naar links - rotatie met 5 graden verlagen anders als (sleutel == GLUT_KEY_LEFT) rotate_y -= 5; anders als (sleutel == GLUT_KEY_UP) rotate_x += 5; anders als (sleutel == GLUT_KEY_DOWN) rotate_x -= 5; // Verzoek om update van het display glutPostRedisplay();  // ---------------------------------------------------------- // hoofdfunctie // ---------------------------------------------------------- int hoofd(int argc, verkolen* argv[]) // GLUT initialiseren en gebruikersparameters verwerken glutInit(&argc,argv); // Vraag dubbel gebufferd kleurenvenster met Z-buffer aan glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // Maak een venster glutCreateWindow("Awesome Cube"); // Z-buffer dieptetest inschakelen glEnable(GL_DEPTH_TEST); // Terugbelfuncties glutDisplayFunc(tonen); glutSpecialFunc(specialKeys); // Geef controle door aan GLUT voor evenementen glutMainLoop(); // Keer terug naar OS terugkeer 0;