PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ein paar Fragen zu OpenGL!


Ganon
2003-07-19, 16:14:46
Hi,

es folge der Standard-Satz:

"Ich bin noch ein Anfänger"

:D

Naja! Ich will mich jetzt näher mit OpenGL in Verbindung mit C++ beschäftigen. Daher habe ich mir ein bisschen was zusammenkopiert und ein bisschen erweitert und versucht es zu verstehen.

Naja! Fenstersteuerung übernimmt GLUT.

Ich habe einen farbigen Würfel mit einer Pyramide drauf (bzw. ein kleines Haus) das ich mit der Maus drehen kann (bzw. die Teekanne von glut / ist auswählbar).

Alles noch sehr simpel. Normales Licht an und ausschaltbar usw.

Nun ein paar Fragen:

1. Wie kann ich FSAA mit OpenGL erzwingen? Unter OSX kann man FSAA nämlich nicht über den Treiber einschalten! ATi arbeitet noch dran. Wenn kompliziert sein sollte, dann lassen wir das erst mal! :)

2. Wenn ich das Objekt auf der Z-Achse nach hinten verschiebe, dann verschwindet es im schwarzen Hintergrund! Ich denke mal es liegt dran das ich noch keinerlei Code für die Sicht habe! Das Objekt wird ja auch nicht kleiner!
Wie definiere ich den Sichtpunkt usw.? Oder kennt ihr ein gutes Tutorial das sich damit auseinandersetzt (Kamera usw.)?

Die Methode recalcModelPos sieht auch noch ziehmlich winzig aus!


void recalcModelPos(void)
{
glLoadIdentity();
glTranslatef(posx, posy, posz);
glRotatef(xangle, 1.0, 0.0, 0.0);
glRotatef(yangle, 0.0, 1.0, 0.0);
}


3. Wo ist eigendlich der Unterschied zwischen glVertex3f und glVertex3d usw.?

So das wäre es erst mal!

Schonmal danke!

MeLLe
2003-07-19, 16:38:56
Hmm, also ich möchte da mal ein paar Dinge beantworten:

zu 2)
Dein Model verschwindet beim Nach-hinten-schieben, weil es die definierte Far Clipping Plane erreicht bzw. kreuzt. Dies ist eine der sechs Ebenen, die das View Frustrum - also den Sichtbereich - definieren. Die Near Clipping Plane liegt in unmittelbarer Nähe zum Betrachterstandpunkt, alles was näher als diese Ebene am Betrachter liegt, wird geclippt und nicht dargestellt. Die Far Clipping Plane stellt das gegenüberliegende Ende des View Frustrums dar - alles, was weiter als diese Ebene vom Betrachter entfernt ist, wird auch geclippt und nicht gerendert. Mit gluPerspective(field_of_view, window_width / window_height, near_clipping_plane, FAr_clipping_plane);legst Du das View Frustrum für Deine Anwendung auf einfache Weise fest.

Exzellente Tutorials für OpenGL findet Du bei NeHe (http://nehe.gamedev.net).


zu 3)
Es gibt unter OpenGL viele Funktionen, die fast gleichen Namen haben und sich nur marginal unterscheiden. Das ist ganz einfach zu erklären, z.B. an Hand Deiner beiden Funktionen:
void glVertex3d(GLdouble x, GLdouble y, GLdouble z);
void glVertex3f(GLfloat x, GLfloat y, GLfloat z);Wie Du siehst, unterscheiden sich beide Funktionen nur darin, dass sie unterschiedliche Parametertypen aufnehmen - und dieser Unterschied ist auch im Namen der Funktion festgehalten.
Ansonsten dienen beide Funtionen dem Zweck, je einen Vertex durch 3 Parameter zu definieren - glVertex3d() erwartet dazu drei GLdouble-Werte, glVertex3f() drei GLfloat-Parameter.

Xmas
2003-07-19, 17:21:22
Original geschrieben von Ganon
1. Wie kann ich FSAA mit OpenGL erzwingen? Unter OSX kann man FSAA nämlich nicht über den Treiber einschalten! ATi arbeitet noch dran. Wenn kompliziert sein sollte, dann lassen wir das erst mal! :)
Unter Windows gibt es eine WGL-Extension (WGL_ARB_pixel_format + ARB_multisample) die das anfordern von Multisampling erlaubt. Leiter erzwingt sie kein AA.
Ob es entsprechende Funktionalität auch für OSX gibt weiß ich nicht.

Ansonsten hat MeLLe eigentlich schon alles erklärt. Hinzuzufügen wäre noch, dass nach Anzahl der Parameter (2, 3, oder 4) und Typ (d, f, i, b, ...) noch ein v folgen kann, das für Vektor steht. Hier gibt man die Parameter nicht einzeln an, sondern als ein Pointer auf ein Array.

Ganon
2003-07-19, 18:09:16
Hi,

danke schonmal für die Erklärung!

Nur leider verschwindet das Objekt immernoch!

Ich habe jetzt in der Methode recalcModelPos diese Zeile eingefügt (unten rangehängt):

gluPerspective(45,width/height,0,2000);

Xmas
2003-07-19, 18:22:38
Original geschrieben von Ganon
gluPerspective(45,width/height,0,2000);
Das funktioniert nicht. znear muss > 0 sein.

Ganon
2003-07-19, 18:28:38
OK! Jetzt ändert sich was!

Ich sehe mein Objekt nicht mehr! Ich sehe nur schwarze Fläche! Wie finde ich das Ding? Oder muss durch diesen Befehl etwas geändert werden?

Xmas
2003-07-19, 18:36:31
Original geschrieben von Ganon
Ich habe jetzt in der Methode recalcModelPos diese Zeile eingefügt (unten rangehängt):

Falsche Matrix, falsche Stelle im Programm.

Die Perspektivprojektion musst du üblicherweise ja nur einmal einstellen. Also musst du in deinen Initialisierungscode folgende Sequenz einfügen.


glMatrixMode(GL_PERSPECTIVE);
glLoadIdentity();
gluProjection(...);
glMatrixMode(GL_MODELVIEW);

Ganon
2003-07-19, 18:52:21
glMatrixMode(GL_PERSPECTIVE) erkennt er nicht.

Und was ist glProjection?

Kant
2003-07-19, 18:57:45
Hi,

Xmas meinte wohl GL_PROJECTION. (anstelle GL_PERSPECTIVE)

Ich habe es in der Art....

glMatrixMode(GL_PROJECTION);
glLoadIdentity(); gluPerspective(60.0f,(GLfloat)width/(GLfloat)height,0.1f,30000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

Ganon
2003-07-19, 19:15:41
Hi Kant,

ich habe jetzt deinen Code als erstes von recalcModelPos gesetzt! Auch wenn es da unpassend ist!

Funzt Supi!

Jetzt versuche ich mal ne Textur drauf zu packen! Falls ich dabei Probleme bekomme melde ich mich nochmal!:D

DANKE!

Xmas
2003-07-19, 20:07:36
Original geschrieben von Kant
Xmas meinte wohl GL_PROJECTION. (anstelle GL_PERSPECTIVE)
:| Sah auch irgendwie komisch aus :bonk:;)

Ganon
2003-07-19, 20:24:58
Hi,

OK ist nicht ganz Texturierung, aber ich wollte mal versuchen auf Tastendruck das "Dach" (die Pyramide auf dem Würfel) aufzuklappen!

Geht soweit auch nur viel zu schnell! Ich will das das Dach langsam aufgeht! Ich habe eine Variable die ich entweder hoch oder runterzähle (zwischen 0.0 und 0.5)! Das mache ich mit einer "for" Schleife!

Wie bremse ich jetzt das ganze?

Kant
2003-07-19, 22:49:27
Ich glaube, ich verstehe dein Problem noch nicht ganz..
Die Geschw. bzw Anzahl der Durchläufe kannst du ja mit dem step in der Schleife festlegen ?
Oder hast du das Problem bei der Interpolation der Vertices ?

Ganon
2003-07-19, 23:38:37
Hi,

wenn ich auf eine Taste drücke will ich das sich die Pyramide aufklappt! Habe jetzt eine While-Schleife die von 0.0 bis 0.5 in 0.01 Schritten geht, bzw. anders herum!

Nur leider geht das zu fix, man merkt nicht das es Schrittweise geht!

Ich dachte jetzt an einen Timer damit der Schleifenbefehl nur alle 250ms, oder so aufgerufen wird!

Nur lieder weiß ich nicht wie man einen Timer in C++ startet bzw. nutzt!

Kant
2003-07-19, 23:57:02
Unter Windows sollte es mit GetTickCount() gehen.

float startTime = GetTickCount() * 0.001f;
und in der schleife
{
float jetzt=(GetTickCount() * 0.001f)-startTime;
}

Dann hast du in "jetzt" die Sekunden seit dem definieren von startTime.
Gibt da aber sicher bessere Methoden, habe den Timer bisher nur zur fps anzeige genutzt.

Ganon
2003-07-20, 00:03:49
Naja! Ich machs ja unter OSX!

Wenn ich deines benutze sagt gcc mir:

`GetTickCount' was not declared in this scope

zeckensack
2003-07-20, 08:30:30
Original geschrieben von Kant
Hi,

Xmas meinte wohl GL_PROJECTION. (anstelle GL_PERSPECTIVE)

Ich habe es in der Art....

glMatrixMode(GL_PROJECTION);
glLoadIdentity(); gluPerspective(60.0f,(GLfloat)width/(GLfloat)height,0.1f,30000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); Ist nicht zu empfehlen. Gerade der Abstand der near plane hat großen Einfluß auf die nutzbare Z-Auflösung. Das Problem ist schwer in knappe Worte zu fassen, aber um unnötigen Ärger zu vermeiden, sollte man die near plane wenn möglich bei mindestens 0.5f, besser 1.0f ansetzen.

zeckensack
2003-07-20, 08:34:05
Original geschrieben von Ganon
2. Wenn ich das Objekt auf der Z-Achse nach hinten verschiebe, dann verschwindet es im schwarzen Hintergrund! Ich denke mal es liegt dran das ich noch keinerlei Code für die Sicht habe! Das Objekt wird ja auch nicht kleiner!
Wie definiere ich den Sichtpunkt usw.? Oder kennt ihr ein gutes Tutorial das sich damit auseinandersetzt (Kamera usw.)?Die Default-Einstellung für die Projektions ist eine identity-matrix. Dadurch ist der 'clip space' (in dem Objekte gezeichnet werden können) der Einheitskubus (Würfel von -1 bis 1 in x,y,z). Nur der Vollständigkeit halber :)

Ganon
2003-07-20, 12:15:36
Hi,

kann sein das ich jetzt falsch denke, aber wie erreicht man eine Bewegung in OpenGL?

Ich will von der Pyramide die oberen Punkte verschieben. Das aber langsam so das das öffnen der Pyramide ungefähr 3 Sekunden brauch,. aber das Programm dabei nicht stoppt.

Es soll weiterhin dreh und zoombar sein.

Wie stelle ich denn sowas an?

zeckensack
2003-07-20, 12:34:13
Original geschrieben von Ganon
Hi,

kann sein das ich jetzt falsch denke, aber wie erreicht man eine Bewegung in OpenGL?

Ich will von der Pyramide die oberen Punkte verschieben. Das aber langsam so das das öffnen der Pyramide ungefähr 3 Sekunden brauch,. aber das Programm dabei nicht stoppt.

Es soll weiterhin dreh und zoombar sein.

Wie stelle ich denn sowas an? Grundidee:

bool animate_door=false;
float door_animation_state=0.0f;
float door_animation_delta=0.0f;

void
process_input()
{
if (user_requests_open_door())
{
animate_door=true;
door_animation_delta=1.0f;
}
if (user_requests_close_door())
{
animate_door=true;
door_animation_delta=-1.0f;
}
}

void
animate_world()
{
float delta_t=time_since_last_frame();
if (animate_door)
{
door_animation_state+=delta_t*door_animation_delta;
//clamp to maximum
if (door_animation_state>=1.0f)
{
door_animation_state=1.0f;
//stop animation
door_animation_delta=0.0f;
animate_door=false;
}
else
if (door_animation_state<=0.0f)
{
door_animation_state=0.0f;
//stop animation
door_animation_delta=0.0f;
animate_door=false;
}
}
}


void
main_loop()
{
while (still_running)
{
process_input();
animate_world();
render();
}
}
door_animation_state kann nun in render() eingesetzt werden, um eine Rotation oä zu kontrollieren. Man kann auch eine Übertragungsfunktion implementieren, die aus der linearen Bewegungen etwas 'rundes' macht (quadrieren, Sinus, was auch immer).

Drei Sachen sind hier wichtig:
Die Applikation kreist weiter in ihrer Hauptschleife. Interaktion ist weiterhin möglich.

Für die Animation wird ein delta_t benutzt (ist bei mir immer ein float, 1.0f entspricht einer Sekunde). Auf die Weise laufen Animationen immer gleich schnell, unabhängig von der Framerate.

Die 'states', die den Fortschritt einer Animation steuern, werden pro Frame nur mit linearen Funktionen (Addition, Subtraktion) bearbeitet. Der Grund ist der gleiche wie für den zweiten Punkt. Nicht-lineare Funktionen (zB Multiplikation) lassen sich nur schwer geschwindigkeitsunabhängig machen. Es ist viel leichter, einfach eine lineare Funktion später zu verbiegen, als direkt mit einer nicht-linearen zu arbeiten. Dafür braucht man nämlich Logarithmen, Integrale, und ganz allgemein furchtbar gute Mathe-Kenntnisse :)

Ganon
2003-07-20, 14:40:54
Hi,

erst mal vielen Dank zeckensack! Soweit ist schonmal die Theorie klar! Habe es auch gleich versucht!

Es geht soweit nur gibt es ein (oder 2) kleines Problem.

Erst mal wie ich es jetzt gemacht habe!

Auf der Tastenabfrage:


if (PState == 0.0f)
{
Ani = true;
cout << "Machen wir das Dach auf" << endl;
PDelta=0.5f;
}
else
{
Ani = true;
cout << "Machen wir das Dacht zu" << endl;
PDelta=-0.5f;
};


Die Methode für die Animation! Hier gleich noch eine Frage! Wie bekomme ich deinen Wert "time_since_last_frame" raus? Ich habe jetzt erst mal 0.01 genommen, damit es wenigsten läuft.


void Anima()
{
if (Ani == true)
{
PState+=0.01*PDelta;
if (PState>=0.5f)
{
PState=0.5f;
PDelta=0.0f;
Ani = false;
}
else
{
if (PState<=0.0f)
{
PState=0.0f;
PDelta=0.0f;
Ani = false;
};
};
};
}


Die Methode "Anima" wird in der Methode DrawScene, nach recalcModelPos aufgerufen! DrawScene ist die Methode wo die Objekte erstellt werden.

Die Main-Funktion sieht so aus:


int main(int argc, char *argv[])
{
//GLUT initialisieren, Fenster setzen
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (width, height);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);

// eigene Initialisierungen (Licht, Z-Buffer usw.)
myinit();

//Callbacks setzen: Reaktion auf Mausklicks und -bewegungen, Tastaturaktivitäten
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutKeyboardFunc(keyb);

//Callback zum Zeichnen der GL-Funktion
glutDisplayFunc(DrawScene);

glutMainLoop();

return EXIT_SUCCESS;


Mein Problem ist jetzt das sich die Pyramiden-Teile sich nur bewegen wenn ich das Objekt drehe, zomme usw.!
Würde es aber gerne so haben, dass sich nach dem Tastendruck das ganze Dach auf, bzw. zuklappt ohne weiteres zutun!

Danke schonmal!

Xmas
2003-07-20, 16:56:35
Original geschrieben von Ganon
Mein Problem ist jetzt das sich die Pyramiden-Teile sich nur bewegen wenn ich das Objekt drehe, zomme usw.!
Würde es aber gerne so haben, dass sich nach dem Tastendruck das ganze Dach auf, bzw. zuklappt ohne weiteres zutun!

Danke schonmal!
Du brauchst auch noch eine glutIdleFunc. In deinem Fall kannst du DrawScene als IdleFunc nehmen.

Zum Zeitproblem, da ist mir leider kein portabler Millisekunden-genauer Timing-Mechanismus bekannt.

Ganon
2003-07-20, 17:24:00
COOL! VIELEN DANK! ES KLAPPT! *freu*

Ganon
2003-07-20, 22:23:33
Hi,

ich habe mir jetzt vom unten aufgeführten Link den Code gezogen (GLUT-Variante), wie man Texturen holt! Nur leider bricht er mit folgenden Meldungen ab:

---
Width of NeHe.bmp: 65536
Height of NeHe.bmp: 65536
Planes from NeHe.bmp is not 1: 256
---

Ich verwende das Bitmap das dabei war!

Woran liegt das und könnte man das auch anders lösen?


http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06

Xmas
2003-07-20, 23:20:17
Original geschrieben von Ganon
Hi,

ich habe mir jetzt vom unten aufgeführten Link den Code gezogen (GLUT-Variante), wie man Texturen holt! Nur leider bricht er mit folgenden Meldungen ab:

---
Width of NeHe.bmp: 65536
Height of NeHe.bmp: 65536
Planes from NeHe.bmp is not 1: 256
---

Ich verwende das Bitmap das dabei war!

Woran liegt das und könnte man das auch anders lösen?


http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06
???
Bei der GLUT-Variante ist doch gar keine NeHe.bmp dabei, sondern eine TGA?

Anhand der Zahlen kann ich dir aber mit ziemlicher Sicherheit sagen, dass es sich um ein Little Endian->Big Endian Problem handelt. BMP ist ein Windows-Format, und da Windows nun mal üblicherweise auf x86-Architektur läuft, werden Zahlen im Little Endian Format gespeichert. Beim Mac wird aber traditionell Big Endian verwendet.
Deswegen wird aus 1 (0x0001) auch 256 (0x0100)

Ganon
2003-07-21, 17:44:05
Hi,


uups! Sorry! Habe ja die Linux-Variante genommen! Bei der GLUT-Variante habe ich nicht durchgesehen!

Kann man das Bitmap denn ändern, oder muss der Code angepasst werden? Weil sonst lasse ich das erst mal!

Xmas
2003-07-21, 18:58:24
Original geschrieben von Ganon
Kann man das Bitmap denn ändern, oder muss der Code angepasst werden? Weil sonst lasse ich das erst mal!
Beides ist möglich, aber den Code anzupassen ist sinnvoller.


char *revert, swap;

// read the width
if ((i = fread(&(image->sizeX), 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
revert = (char *) &(image->sizeX);
swap = revert[0]; revert[0] = revert[3]; revert[3] = swap;
swap = revert[1]; revert[1] = revert[2]; revert[2] = swap;
printf("Width of %s: %lu\n", filename, image->sizeX);

// read the height
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
revert = (char *) &(image->sizeY);
swap = revert[0]; revert[0] = revert[3]; revert[3] = swap;
swap = revert[1]; revert[1] = revert[2]; revert[2] = swap;
printf("Height of %s: %lu\n", filename, image->sizeY);

// calculate the size (assuming 24 bits or 3 bytes per pixel).
size = image->sizeX * image->sizeY * 3;

// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
revert = (char *) &planes;
swap = revert[0]; revert[0] = revert[1]; revert[1] = swap;
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}

// read the bpp
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
revert = (char *) &bpp;
swap = revert[0]; revert[0] = revert[1]; revert[1] = swap;
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}

Xmas
2003-07-21, 19:22:37
Da du als Mac-User durchaus öfter auf solche Probleme stoßen könntest, hier mal ein C++ Template zum Byte umkehren:


template <class T>
inline T& swapbytes(T& t) // Parameter wird sowohl verändert als auch zurückgegeben
{
char c;
for(i = 0; i < (sizeof(t) / 2); ++i)
{
c = ((char *)&t)[i];
((char *)&t)[i] = ((char *)&t)[sizeof(t) - i - 1];
((char *)&t)[sizeof(t) - i - 1] = c;
}
return t;
}


Das sollte für alle Integer- und Float-Typen funktionieren.

Ganon
2003-07-21, 19:26:07
Hi,

Supi! Läuft!

Was machst du da jetzt genau? Verschiebst du jetzt die ausgelesenen Werte, damit sie vom MAC richtig erkannt werden?

edit:

Achja! Warum sieht das Bild auf dem Polygon anders aus, als wenn ich das Bitmap so öffne?

Xmas
2003-07-21, 20:03:05
Original geschrieben von Ganon
Was machst du da jetzt genau? Verschiebst du jetzt die ausgelesenen Werte, damit sie vom MAC richtig erkannt werden?
Umwandlung von Little Endian nach Big Endian und andersrum.
Bei Little Endian wird das niedrigste Byte einer Zahl im Speicher auf die niedrigste Adresse gelegt, bei Big Endian auf die höchste. Das ist Prozessor(-Architektur)-spezifisch.

Xmas
2003-07-21, 20:04:34
Original geschrieben von Ganon
Achja! Warum sieht das Bild auf dem Polygon anders aus, als wenn ich das Bitmap so öffne?
Wie sieht es denn aus? Andere Farben oder gespiegelt?

Ganon
2003-07-21, 20:14:59
Andere (weniger) Farben!

edit:

Hat sich erledigt! Das QUAD dahinter hatte noch ne Farbe drauf (Blau)! OpenGL scheint das zu mixen! Muss natürlich Schwarz sein!

Nasenbaer
2003-07-22, 18:08:31
Ich weiß zwar nicht ob es bereits erwähnt wurde oder ob die die Quelle schon kennst aber auf http://nehe.gamedev.net/ findet man DAS Tutorial zu OpenGL. Dort wird dann auch alles zur richtigen Initialisierung erklärt damit das Objekt nicht einfach so im Nichts verschwindet. :)

Mfg Nasenbaer

Xmas
2003-07-22, 19:18:06
Original geschrieben von Nasenbaer
Ich weiß zwar nicht ob es bereits erwähnt wurde oder ob die die Quelle schon kennst aber auf http://nehe.gamedev.net/ findet man DAS Tutorial zu OpenGL. Dort wird dann auch alles zur richtigen Initialisierung erklärt damit das Objekt nicht einfach so im Nichts verschwindet. :)

Mfg Nasenbaer
Hättest du dir ein ganz klein wenig mühe gegeben den Thread zu überblicken, wäre dir aufgefallen dass die letzten zehn Postings um ein NeHe-Tutorial gingen... ;)

Wenn der Thread 15 Seiten lang wäre würde ich es ja verstehen, aber so...

Nasenbaer
2003-07-22, 21:11:51
Original geschrieben von Xmas
Hättest du dir ein ganz klein wenig mühe gegeben den Thread zu überblicken, wäre dir aufgefallen dass die letzten zehn Postings um ein NeHe-Tutorial gingen... ;)

Wenn der Thread 15 Seiten lang wäre würde ich es ja verstehen, aber so...
:heuldoch:
Hab' die komplette erste Seite durchgelesen, weils mich teilweise auch interessiert hat. Danach wurds für mich langweilig da ich ersma Dx lerne. :-)

Mfg Nasenbaer

Melle@work
2003-07-23, 12:59:27
Original geschrieben von Nasenbaer
:heuldoch:
Hab' die komplette erste Seite durchgelesen, weils mich teilweise auch interessiert hat. Danach wurds für mich langweilig da ich ersma Dx lerne. :-)

Mfg Nasenbaer
Und genau da, auf Seite 1, ziemlich weit oben am Beginn, steht der Link zu NeHe ...

Nasenbaer
2003-07-23, 14:35:25
Original geschrieben von Melle@work
Und genau da, auf Seite 1, ziemlich weit oben am Beginn, steht der Link zu NeHe ...
Das hab ich dann übersehen. Ich bitte vielmals um Entschuldigung. :massa:

Mfg Nasenbaer