Geschrieben von javadomi am 14.08.2005, 20:21

Hinweis:
Einige verstehen immer noch nicht, dass dieser Workshop nicht für Anfänger geeignet ist. Man sollte schon etwas mit der WinAPI vertraut sein. Wer die Quellcodes für die Programme möchte, soll mir schreiben

Einleitung:
Mit OpenGL kannst du Grafiken auf den Bildschirm ausgeben. Sogar Spiele kannst du damit programmieren (wie, erkläre ich in einen späteren Workshop). Nun werden wir uns mit den Grundlagen vertraut machen. Das Ziel dieses Workshops wird es sein ein rotierenden Würfel auszugeben.

Vorraussetztungen:
Du solltest schon etwas mit C++ vertraut sein. Einen C++ Compiler mit OpenGL musst du auch haben. Falls du noch keinen hast, dann lade dir einen unter http://www.borland.com herunter. Wie du mit ihn umgehst, erfährst du im einen späteren Workshop von mir.

Kapitel 1: OpenGL Fenster
Nun werden wir ein OpenGL taugliches Fenster erstellen. Ich werde mich bemühen jeden Befehl einzeln durch ein Kommentar zu erklären. Am Ende jedes Kapitels werde ich den fertigen Quellcode für das komplette Programm zusammenfassen, so, dass du ihn dir direkt abschreiben kannst und die Kompilierung durchführen kannst. Ich werde jedes mal davon ausgehen, dass du den Borland BCC 5.5 Compiler benutzts. Es wird immer empfohlen die OpenGL Programme mit den Borland BCC 5.5 Compiler so zu kompilieren:

1. Lege nach der Installation des Borland BCC 5.5 Compilers im Bin Verzeichnis eine Datei Namens Build.bat (sorge dafür, dass es eine Batch Datei ist).
2. Die wird mit einen belibigen Editor (am besten den standart Windows Editor) so bearbeitet:

bcc32 -c -tW quellcode.cpp
ilink32 /nologo -C -q -c -Gl -Rr -Gt -Gpd -Gpr -Gn -x /aa quellcode.obj c0w32.obj, quellcode.exe,, import32.lib cw32.lib uuid.lib,,

quellcode musst du mit den Namen deiner Cpp Datei ersetzen. Nach diesen Schritten, kannst du ein Quelltext kompilieren. So, jetzt fangen wir mit den wesentlichen an. Für jedes OpenGL Programm, solltest du folgende Include Dateien einbinden:

#include <windows.h> // Definitionen für ein Fenster
#include <glgl.h> // Definitionen für OpenGL
#include <glglu.h> // Definitionen für OpenGL
#include <glglaux.h> // Definitionen für OpenGL

Mit diesen Include Dateien kannst du bereits alle OpenGL Befehle benutzten und musst dich nicht mehr darum kümmern, ob die richtigen Include Dateien eingebunden sind. Aber falls du z.B. Mathematische Befehle wie Sinus benutzen willst, dann musst du die entsprechenden Include Dateien einbinden. Nun sollten wir folgende globale Variablen deklarieren:

HDC hDC=NULL; // Eine Variable für das OpenGl Fenster
HGLRC hRC=NULL; // Eine Variable für das OpenGl Fenster
HWND hWnd=NULL; // Eine Variable für das normale Windows Fenster
HINSTANCE hInstance; // Die Instanz des Fensters

bool fullscreen=true; // Soll der Fullscreen Modus Aktiviert werden?
bool active=true; // Reagiert das Programm?
bool bQuit=false; // Soll das Programm beendet werden?
bool keys[256]; // Welche Tasten sind gedrückt?

Das in der ersten Zeile definierte hDC nennt sich auch Device Context. Das hDC verbindet das Fenster mit den GDI (Graphics Device Interface). Die zweite Zeile definiert das hRC, das Rendering Context. Dies stellt eine Verbindung zu den DC her. Jetzt deklarieren wir unsere Funktionen:

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void ReSizeGLScene(GLsizei width, GLsizei height);
void EnableOpenGL(HWND hWnd, HDC *hDC, HGLRC *hRC);
void KillGLWindow();
void DrawGLScene();

int InitGL();

Nun kommt die Haupt Funktion, die als erstes gestartet wird und in der Objekt Datei c0w32.obj, die bei den Link Vorgang eingebunden wird, als Startfunktion gesetzt wird:

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR, int nCmdShow) // WinMain Funktion definieren
{
DWORD style=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Den Typ des Fensters festlegen
hInstance=hInst; // Den Parameter von WinMain global machen
WNDCLASSEX wincls; // Die Window Klasse erstellen
MSG msg; // Den Window Message erstellen

if (fullscreen) // Den Fullscreen aktivieren falls ja
{
DEVMODE dmScreenSettings; // Den Fullscreen einstellen
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = 640; // 640
dmScreenSettings.dmPelsHeight = 480; // 480
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) // Wenn nicht erfolgreich, dann zurücksetzen
{
if (MessageBox(NULL,"Wollen sie ohne Vollbild fortfahren?","GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE;
}
else
{
MessageBox(NULL,"Fehler!","ERROR",MB_OK|MB_ICONSTOP);
return 0;
}
}
}

if (fullscreen) // Wenn erfolgreich, dann Fenster ändern
{
style=WS_BORDER | WS_VISIBLE | WS_POPUPWINDOW; // Den Typ besser anpassen
ShowCursor(FALSE); // Mauszeiger verstecken
}

if (!hPrevInstance) // Das Fenster einstellen
{
wincls.cbSize = sizeof(wincls);
wincls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wincls.lpfnWndProc = WndProc;
wincls.cbClsExtra = 0;
wincls.cbWndExtra = 0;
wincls.hInstance = hInstance;
wincls.hIcon = NULL; // LoadIcon(hInstance, (LPCSTR)IDI_MAINICON);
wincls.hIconSm = NULL; // LoadIcon(hInstance, (LPCSTR)IDI_MAINICONSM);
wincls.hCursor = LoadCursor(NULL, IDC_ARROW);
wincls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wincls.lpszMenuName = NULL;
wincls.lpszClassName = "GLFenster";
RegisterClassEx(&wincls);
}

// Das Fenster erstellen
hWnd = CreateWindow("GLFenster",
"glwindowclass",
style,
0,
0,
640,
480,
NULL,
NULL,
hInstance,
NULL);

EnableOpenGL(hWnd, &hDC, &hRC); // OpenGL aktivieren
ReSizeGLScene(640, 480); // Auf Fenstergröße setzen

ShowWindow(hWnd, nCmdShow); // Das Fenster zeigen
UpdateWindow(hWnd); // Das Fenster aktualisieren

InitGL(); // OpenGL Initialisieren

while (!bQuit) // Solange nicht beendet
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // Message aktualisieren
{
if (msg.message == WM_QUIT) // Wenn beendet
{
bQuit = true;
}
else
{
TranslateMessage(&msg); // Ansonsten Message übersetzen
DispatchMessage(&msg);
}
}
else
{
if (active) // Solange aktiv
{
if (keys[VK_ESCAPE]) // Beenden, wenn Esc gedrückt wird
{
bQuit = true;
}
else
{
DrawGLScene(); // Alles zeichnen
}
}
}
}

ChangeDisplaySettings(NULL,0); // Vollbild zurücksetzen
ShowCursor(TRUE); // Mauszeiger zeigen

KillGLWindow(); // OpenGL Fenster beenden
DestroyWindow(hWnd); // Fenster löschen

return 0; // Normal beendet
}

So, das war etwas viel auf einmal. Aber ich habe ja alles gut auskommentiert. Jetzt wenden wir uns der Funktion zum Übersetzen der Messages zu, die in der WNDCLASSEX Klasse auf lpfnWndProc gesetzt wurde.

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) // Wir nennen sie mal WndProc
{
switch (uMsg) // Message wählen
{
case WM_ACTIVATE: // Ob aktiviert überprüfen
{
if (!HIWORD(wParam))
{
active=TRUE;
}
else
{
active=FALSE;
}

return 0;
}

case WM_CLOSE: // Wenn beendet
{
PostQuitMessage(0); // Beenden Message senden
return 0;
}

case WM_KEYDOWN: // Wenn Taste gedrückt
{
keys[wParam] = TRUE; // Entsprechende Taste auf gedrückt setzen
return 0;
}

case WM_KEYUP: // Wenn Taste losgelassen
{
keys[wParam] = FALSE; // Entsprechende Taste auf losgelassen setzen
return 0;
}

case WM_SIZE: // Wenn Fenstergröße verändert
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // OpenGL Fenstergröße entsprechend verändern
return 0;
}
}

return DefWindowProc(hWnd,uMsg,wParam,lParam); // Ansonsten nichts machen
}

So, mit dieser Funktion kann man also die Message übersetzen. Nun müssen wir ja noch das OpenGL Fenster aktivieren. Das geschieht mit dieser Funktion:

void EnableOpenGL(HWND hWnd, HDC *hDC, HGLRC *hRC) // Wir nennen sie EnableOpenGL
{
int iFormat; // Für das Pixelformat
PIXELFORMATDESCRIPTOR pfd; // Für den DESCRIPTOR

*hDC = GetDC(hWnd); // hDC setzten
ZeroMemory(&pfd, sizeof(pfd)); // Memory leeren

// Den DESCRIPTOR einstellen
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;

// Sonstiges einstellen
iFormat = ChoosePixelFormat(*hDC,&pfd);
SetPixelFormat(*hDC,iFormat,&pfd);
*hRC = wglCreateContext(*hDC); // Den Context für OpenGL setzten
wglMakeCurrent(*hDC,*hRC); // Den Context erstellen
}

Bald können wir unsere Grafiken rendern, das heißt, dass wir sie zeichnen können. Vorher müssen wir noch einiges für OpenGL aktiviern und setzten:

int InitGL() // Wir nennen sie InitGL
{
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Hintergrundfarbe setzten
// Sonstige Kleinigkeiten aktivieren
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

return 1;
}

Diese Kleinigkeiten werden nicht oft verändert. Wir brauchen noch eine Funktion für das Verändern der Größe des Fensters. Diese lautet so:

void ReSizeGLScene(GLsizei width, GLsizei height)
{
if (height==0) // Falls ungültige Größe
height=1; // setzte auf gültige Größe

glViewport(0, 0, width, height); // Ausgangspunkt
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // Die Modelview Matrix zurücksetzten
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

Am ende des Programmes müssen wir noch das Fenster "zerstören", damit keine Reste vom Programm im Speicher bleiben. Dies geschieht mit dieser Funktion:

void KillGLWindow()
{
if (fullscreen) // Wenn Vollbild, dann zurücksetzten
{
ChangeDisplaySettings(NULL,0);
ShowCursor(TRUE); // Mauszeiger zeigen
}

if (hRC) // Sonstiges löschen
{
wglMakeCurrent(NULL,NULL);
wglDeleteContext(hRC);
hRC=NULL;
}

ReleaseDC(hWnd,hDC);
}

Folgende Funktion heben wir uns auf für das rendern der Grafiken:

void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Den Bildschirm säubern
glLoadIdentity(); // Die Modelview Matrix zurücksetzten
}

So, wir haben alles fertig behandelt, das heißt, dass ich nun den ganzen Code zum direkten Kopieren in eine Cpp Datei aufschreiben werde:

#include <windows.h> // Definitionen für ein Fenster
#include <glgl.h> // Definitionen für OpenGL
#include <glglu.h> // Definitionen für OpenGL
#include <glglaux.h> // Definitionen für OpenGL

HDC hDC=NULL; // Eine Variable für das OpenGl Fenster
HGLRC hRC=NULL; // Eine Variable für das OpenGl Fenster
HWND hWnd=NULL; // Das Handle für das normale Windows Fenster
HINSTANCE hInstance; // Die Instanz des Fensters

bool fullscreen=true; // Soll der Fullscreen Modus Aktiviert werden?
bool active=true; // Reagiert das Programm?
bool bQuit=false; // Soll das Programm beendet werden?
bool keys[256]; // Welche Tasten sind gedrückt?

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void ReSizeGLScene(GLsizei width, GLsizei height);
void EnableOpenGL(HWND hWnd, HDC *hDC, HGLRC *hRC);
void KillGLWindow();
void DrawGLScene();

int InitGL();

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR, int nCmdShow) // WinMain Funktion definieren
{
DWORD style=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Den Typ des Fensters festlegen
hInstance=hInst; // Den Parameter von WinMain global machen
WNDCLASSEX wincls; // Die Window Klasse erstellen
MSG msg; // Den Window Message erstellen

if (fullscreen) // Den Fullscreen aktivieren falls ja
{
DEVMODE dmScreenSettings; // Den Fullscreen einstellen
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = 640; // 640
dmScreenSettings.dmPelsHeight = 480; // 480
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) // Wenn nicht erfolgreich, dann zurücksetzen
{
if (MessageBox(NULL,"Wollen sie ohne Vollbild fortfahren?","GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE;
}
else
{
MessageBox(NULL,"Fehler!","ERROR",MB_OK|MB_ICONSTOP);
return 0;
}
}
}

if (fullscreen) // Wenn erfolgreich, dann Fenster ändern
{
style=WS_BORDER | WS_VISIBLE | WS_POPUPWINDOW; // Den Typ besser anpassen
ShowCursor(FALSE); // Mauszeiger verstecken
}

if (!hPrevInstance) // Das Fenster einstellen
{
wincls.cbSize = sizeof(wincls);
wincls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wincls.lpfnWndProc = WndProc;
wincls.cbClsExtra = 0;
wincls.cbWndExtra = 0;
wincls.hInstance = hInstance;
wincls.hIcon = NULL; // LoadIcon(hInstance, (LPCSTR)IDI_MAINICON);
wincls.hIconSm = NULL; // LoadIcon(hInstance, (LPCSTR)IDI_MAINICONSM);
wincls.hCursor = LoadCursor(NULL, IDC_ARROW);
wincls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wincls.lpszMenuName = NULL;
wincls.lpszClassName = "GLFenster";
RegisterClassEx(&wincls);
}

// Das Fenster erstellen
hWnd = CreateWindow("GLFenster",
"glwindowclass",
style,
0,
0,
640,
480,
NULL,
NULL,
hInstance,
NULL);

EnableOpenGL(hWnd, &hDC, &hRC); // OpenGL aktivieren
ReSizeGLScene(640, 480); // Auf Fenstergröße setzen

ShowWindow(hWnd, nCmdShow); // Das Fenster zeigen
UpdateWindow(hWnd); // Das Fenster aktualisieren

InitGL(); // OpenGL Initialisieren

while (!bQuit) // Solange nicht beendet
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // Message aktualisieren
{
if (msg.message == WM_QUIT) // Wenn beendet
{
bQuit = true;
}
else
{
TranslateMessage(&msg); // Ansonsten Message übersetzen
DispatchMessage(&msg);
}
}
else
{
if (active) // Solange aktiv
{
if (keys[VK_ESCAPE]) // Beenden, wenn Esc gedrückt wird
{
bQuit = true;
}
else
{
DrawGLScene(); // Alles zeichnen
}
}
}
}

ChangeDisplaySettings(NULL,0); // Vollbild zurücksetzen
ShowCursor(TRUE); // Mauszeiger zeigen

KillGLWindow(); // OpenGL Fenster beenden
DestroyWindow(hWnd); // Fenster löschen

return 0; // Normal beendet
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) // Wir nennen sie mal WndProc
{
switch (uMsg) // Message wählen
{
case WM_ACTIVATE: // Ob aktiviert überprüfen
{
if (!HIWORD(wParam))
{
active=TRUE;
}
else
{
active=FALSE;
}

return 0;
}

case WM_CLOSE: // Wenn beendet
{
PostQuitMessage(0); // Beenden Message senden
return 0;
}

case WM_KEYDOWN: // Wenn Taste gedrückt
{
keys[wParam] = TRUE; // Entsprechende Taste auf gedrückt setzen
return 0;
}

case WM_KEYUP: // Wenn Taste losgelassen
{
keys[wParam] = FALSE; // Entsprechende Taste auf losgelassen setzen
return 0;
}

case WM_SIZE: // Wenn Fenstergröße verändert
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // OpenGL Fenstergröße entsprechend verändern
return 0;
}
}

return DefWindowProc(hWnd,uMsg,wParam,lParam); // Ansonsten nichts machen
}

void EnableOpenGL(HWND hWnd, HDC *hDC, HGLRC *hRC) // Wir nennen sie EnableOpenGL
{
int iFormat; // Für das Pixelformat
PIXELFORMATDESCRIPTOR pfd; // Für den DESCRIPTOR

*hDC = GetDC(hWnd); // hDC setzten
ZeroMemory(&pfd, sizeof(pfd)); // Memory leeren

// Den DESCRIPTOR einstellen
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;

// Sonstiges einstellen
iFormat = ChoosePixelFormat(*hDC,&pfd);
SetPixelFormat(*hDC,iFormat,&pfd);
*hRC = wglCreateContext(*hDC); // Den Context für OpenGL setzten
wglMakeCurrent(*hDC,*hRC); // Den Context erstellen
}

int InitGL() // Wir nennen sie InitGL
{
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Hintergrundfarbe setzten
// Sonstige Kleinigkeiten aktivieren
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

return 1;
}

void ReSizeGLScene(GLsizei width, GLsizei height)
{
if (height==0) // Falls ungültige Größe
height=1; // setzte auf gültige Größe

glViewport(0, 0, width, height); // Ausgangspunkt
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // Die Modelview Matrix zurücksetzten
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void KillGLWindow()
{
if (fullscreen) // Wenn Vollbild, dann zurücksetzten
{
ChangeDisplaySettings(NULL,0);
ShowCursor(TRUE); // Mauszeiger zeigen
}

if (hRC) // Sonstiges löschen
{
wglMakeCurrent(NULL,NULL);
wglDeleteContext(hRC);
hRC=NULL;
}

ReleaseDC(hWnd,hDC);
}

void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Den Bildschirm säubern
glLoadIdentity(); // Abhängigkeit zurücksetzten
}

Kapitel 2:
Erste Polygone Jetzt werden wir ein Dreieck rendern. Wir müssen aus dem Fenster die vorherigen Polygone, die wegen der Schleife übrig bleiben, löschen oder einfach auch übermalen. Dies können wir mit diesen Befehlen machen:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // Abhängigkeit zurücksetzten

Nun kann es mit dem Zeichnen losgehen. Die obere linke Ecke des Fensters entspricht den Koordinaten -1, -1. Die obere rechte Ecke 1, -1. Die untere linke Ecke -1, 1. Die untere rechte Ecke 1, 1. Und die Mitte des Fensters ist dann 0, 0. Ist doch logisch. Ich nehme jetzt an, dass du es bis hierhin kapiert hast. Nun nehmen wir die z Achse dazu. Nehmen wir mal an, dass ihr Wert gerade 10 beträgt. Dies hat zu folgen, dass sie nicht mehr angezeigt wird, weil sie dann aus den Bildschirm in deine Richtung bei positiven Werten geht. Wenn ihr Wert -10 beträgt, dann wird sie im Bildschirm angezeigt. Nehmen wir mal an, dass du das ganze Fenster mit einen Viereck ausgefüllt hast und dessen z Wert 0 beträgt. Wenn wir diesen Wert auf z.B. -15 setzten, dann wird das Viereck kleiner, da es sich von dir entfernt. Ok, das solltest du schon verstanden haben. Da immer angenommen wird, dass dein einziger Polygon -1, -1 bis 1, 1 groß ist, kann man diesen wunderbar irgendwo setzten. Dies geschieht so:

glTranslatef(1.5f,0.0f,-6.0f);

Mit diesen Befehl habe ich jetzt den darauf folgenden Polygon um 1.5 Felder nach links und 6 Felder nach Hinten positioniert. Jetzt zeichnen wir ein Dreieck. Dies muss mit folgendem Befehl eingeleitet werden:

glBegin(GL_TRIANGLES);

Nun können wir hintereinanderweg drei Vertex Befehle eintippen, da ein Dreieck aus drei verschiedenen Punkten besteht. Diese werden nacheinander miteinander verbunden. Aber vorher fügen wir noch Farbe hinzu. Dies geschieht mit diesem Befehl:

glColor3f(1.0f,0.0f,0.0f);

Ich habe die Farbe auf rot gesetzt. Das erste Argument bestmmt den Rot-Anteil, das zweite den Grün-Anteil und das dritte den Blau-Anteil. Wir können vor jedem Vertex (siehe den darauffolgenden Befehl) die Farbe neu setzten, damit ein Vermischungseffekt entsteht. Dies kann man jedoch nur einmal setzten oder auch gar nicht, damit wir einfaches Weiß erhalten. Nun zu den Vertex Befehl. Wie gesagt brauchen wir davon 3, da ein Dreieck aus drei Punkten, die miteinander verbunden werden, besteht. Es basiert auf den Koordinatensystem, das ich zuvor erklärt habe:

glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);

Dies waren die Befehle, die man für ein ordentliches Dreieck anwenden sollte. Zwischen denen kannst du den Befehl für eine neue Farbe einsetzten. Dadurch erhälst du ein tollen Vermischungseffekt. Da wir jetzt mit den Dreick fertig sind, müssen wir den Codeblock abschließen und den Backbuffer anzeigen:

glEnd();
SwapBuffers(hDC);

Du kannst die Anweisungen von glBegin() bis glEnd sooft wiederholen, wie du willst. Das Ergebnis sind dann mehrere Dreiecke. Zum Schluss fasse ich das ganze zusammen. Diesmal jedoch musst du nur von der letzten Zusammenfassung in Kapitel 1 die Funktion void DrawGLScene() mit dieser ersetzten:

void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Den Bildschirm säubern
glLoadIdentity(); // Abhängigkeit zurücksetzten

glTranslatef(1.5f,0.0f,-6.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
SwapBuffers(hDC);
}

Kapitel 3:
Rotierender 3D Würfel Nun kommen wir langsam auf das Ende des Workshops zu. In diesen Kapitel, wie die Überschrift schon alles sagt, werden wir einen rotierenden 3D Würfel ausgeben. Erst brauchen wir noch eine globale Variable oben. Diese soll den rotatins Winkel speichern. Wir deklarieren sie so:

float alpha=0.0f;

Nach diesem Schritt wenden wir uns der gewohnten Funktion void DrawGLScene(). Hier machen wir dasselbe wie letztes Mal. Also erst den Bildschirm leeren, die Abhängigkeit zurücksetzten usw. Wir halten bei den Translate Befehl an. Hier werden wir gleich den Würfel drehen im Winkel von float alpha Grad. Dazu gibt es ein einfachen Befehl:

glRotatef(alpha,1.0f,1.0f,1.0f);

Das erste Argument ist der Winkel, in dem sich der Würfel drehen soll, das Zweite um die X, das Dritte um die Y und das viert Argument um die Z Achse. Du kannst mit diesen Befehl selber mal herumexperimentieren. Nun können wir den Würfel zeichnen:

glBegin(GL_QUADS);

glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);

glColor3f(0.0f,1.0f,0.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);

glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);

glColor3f(1.0f,1.0f,0.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);

glColor3f(1.0f,0.0f,1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);

glColor3f(0.0f,1.0f,1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);

glEnd();

Dieser Code gibt ein perfekten Würfel aus. Natürlich kannst du ihn etwas verändern. Da sich der Rotationswinkel irgendwann verändern oder auch erhöhen muss, addieren wir zu alpha einen Wert so zwischen 1 und 2 hinzu. Es soll ja nicht zu schnell und auch nicht zu langsam sein:

alpha+=1.0f;

So, jetzt fasse ich nur die Funktion void DrawGLScenes zusammen. Du kannst sie direkt in dein Quelltext übernehmen. Denke daran, dass du vorher die Variable float alpha definiert hast.

void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Den Bildschirm säubern
glLoadIdentity(); // Abhängigkeit zurücksetzten

glTranslatef(1.5f,0.0f,-6.0f);
glRotatef(alpha,1.0f,1.0f,1.0f);
glBegin(GL_QUADS);

glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);

glColor3f(0.0f,1.0f,0.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);

glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);

glColor3f(1.0f,1.0f,0.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);

glColor3f(1.0f,0.0f,1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);

glColor3f(0.0f,1.0f,1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);

glEnd();
alpha+=1.0f;
SwapBuffers(hDC);
}

Ende:
Ich habe mich bemüht den ganzen Beispiel Code auszukommentieren. Alle Beispiele habe ich erfolgreich mit den Borland BCC 5.5 getestet. In meinen nähsten Workshop werde ich euch zeigen, wie man Texturen einbindet. Bis dahin noch viel Spass und Erfolg!

PS: Hier ist mal die Sprache von Workshop, d.h. Tutorial

Bewertung Anzahl
6
81,8 %
9 Bewertungen
3
9,1 %
1 Bewertungen
1
9,1 %
1 Bewertungen