Carad Hands on Training: ARB_VP

Hier wird vorgestellt, wie Vertexprogramme in Carad recht einfach selbst erstellt und getestet werden können. Diese Tutorial soll keine allgemeine Einführung in die Arbeitsweise von Carad oder der zugrundeliegenden BaseGraph Bibliothek sein, vielmehr werden wir Schritt für Schritt die Erstellung einer einfachen Animation über Vertexprogramme durchgehen und diese als Delphisource abspeichern, was den Weg zu eigenen Experimenten erleichtern sollte.
Zur Demonstration wird eine an sich glatte Fläche über ein Vertexprogramm in Wellen geworfen, damit es etwas mehr her macht, binden wir dann noch einen TimeSensor an einen Umgebungsparameter und erstellen so ganz einfach und automatisiert eine kleine Animation.
Um die Screenshots nicht zu groß werden zu lassen, werde ich die Auflösung 1024x768 verwenden, ich empfehle aber stark, eine höhere Auflösung zu verwenden, um einen besseren Überblick zu bewahren. Es wird logischerweise eine Grafikkarte mit ARB_vertex_program Unterstützung benötigt.

Bereit? Los geht's.

Nach dem Start von Carad über den Aufruf von "Carad.exe" sollte uns folgender Startbildschirm begrüßen:


(die finale Version von Carad wird wohl erst im Frühjahr 2004 veröffentlicht)

Als Erstes brauchen wir ein Heightfield, das schlussendlich die Wellen darstellen soll, dazu wählen wir erst mal im Primitivefenster das entsprechende Objekt aus, am Schnellsten geht dies, wenn man auf die Reiter

rechts klickt und im Kontextmenü das Heightfield auswählt - dann spart man sich die Herumscrollerei.

Danach geben wir folgende Parameter ein (die gelben Felder können auf den Standardwerten belassen werten) und klicken dann auf neu um das Heightfield mit den gewählten Werten zu erstellen.

Da das Heightfield recht groß ist, schieben wir es etwas zurück, um es im Ganzen betrachten zu können (Heightfield anklicken, rechte Maustaste gedrückt halten und Maus verschieben, um ein Objekt zum Betrachter oder von ihm weg zu schieben). Der Bildschirm sollte nun ungefähr so aussehen:


(ein aktives Objekt kann über die dargestellten Koordinatenachsen rotiert werden)

Nach den Präliminarien geht's jetzt langsam an's Eingemachte und wir erstellen endlich das versprochene Vertexprogramm. Dazu schalten wir die fxPascal IDE ein, indem wir auf Fenster > Programm klicken, oder aber den

Knopf in der Schnellstartleiste verwenden.

Carad versucht automatisch die Fenster an die geänderten Bedingungen anzupassen, die neue Oberfläche sollte nun folgendermaßen aussehen:

Ein neues Vertexprogramm erstellen wir mit einem Druck auf neu unterhalb des Vertexprogrammfenster.

Carad benennt neu erstellte Elemente automatisch, natürlich können diese Namen aber jederzeit geändert werden. Das automatisch in das Sourcefenster eingefügte Programmtemplate schaut folgendermaßen aus, und macht nichts Dramatisches - es berechnet nur die Position eines Schnittpunktes und gibt Textur und Farbe weiter:

Immerhin können wir es schon mal testen und an unser Heightfield binden, um zu sehen, was sich tut. Dazu "ziehen" wir per Drag & Drop das Vertexprogramm aus der Vertexprogrammliste auf das Objekt im 3D-Fenster, an das es gebunden werden soll (also das Heightfield) - und das war's dann schon. Alternativ können Shader auch auf den Objektbaum oder diverse Shaderlisten gezogen werden.

Das Objektfenster sollte nun folgendermaßen aussehen:

Wir sehen also, dass das Vertexprogramm an das Heightfield gebunden ist - ansonsten tut sich aber nicht gerade viel - eigentlich sollte aber die Beleuchtung abgeschaltet werden, da wir im Vertexprogramm keine Lichtquellen berücksichtigen. Was ist also los?

Das Problem ist, dass in den DefaultRenderSettings Vertexprogramme ausgeschaltet sind. Dort einschalten wollen wir sie aber auch nicht, da ansonsten neu generierte Objekte ebenfalls dem Vertexprogramm unterworfen sein würden, eigentlich wollen wir aber nur das Heightfield durch das Vertexprogramm verändern. Also generieren wir neue RenderSettings, aktivieren dort Vertexprogramme und binden die neuen RenderSettings ebenfalls an das Heightfield:


Wir drücken auf neu,


erhalten neue Rendereinstellungen, wählen diese aus, ein Klick auf das blaue "+" öffnet dieselben und...


wir aktivieren Vertexprogramme, indem wir auf das gelbe Häckchen klicken (grün= aktivieren und eventuelle Parameter setzen, gelb= aktivieren, rot= deaktivieren, nichts= unverändert belassen). Nun ziehen wir die neuen Rendereinstellungen auf das Objekt, und es sollte folgendermaßen aussehen:


Das Objekt verwendet nun unser Vertexprogramm, daher die weiße Farbe - und in der Shaderliste des Objektes...


sehen wir dass nun auch die RenderSettings1 an das Objekt gebunden wurden.

Natürlich ist ein weißes Viereck nicht besonders beeindruckend, deshalb geben wir im fxPascal Editor folgendes Programm ein:


($optimize- dient nur zu Testzwecken, um etwas performanteren Code zu erzeugen sollte $optimize+ verwendet werden)

Nach der Eingabe des Programms, muss dieses noch kompiliert werden, entweder mit Kompilieren > VertexProgram1 oder aber mit einem Klick auf die "Zahnräder" neben dem Programmnamen. Danach sollte das Vertexprogramm diesen Effekt generieren:

An dieser Stelle muss wirklich ein Kompliment an Lars Middendorf ausgesprochen werden, da es absolut nicht selbstverständlich ist, in Vertexprogrammen Sinus und Cosinus verwenden zu können. Aber ein guter Programmierer macht manchmal das Unmögliche (bzw in diesem Fall Umständliche) möglich - ihr müsst nur einen Blick auf den generierten ARB_vertex_program Code werfen, um zu sehen, was ihr euch da mit ein paar fxPascal Zeilen erspart habt.
Wenn ich GLSlang Code erst mal selbst testen kann, werde ich auch dafür Unterstützung in Carad einbauen (dann kann man alternativ mit fxPascal/ARB_FP/ARB_VP oder GLSlang programmieren, wenn Lars Middendorf seine GLSlang Version von fxPascal veröffentlicht sogar beides) - ich schätze aber wirklich, dass es nicht viel einfacher werden wird, Shader zu erstellen.

Nun wollen wir die "Wasseroberfläche" auch noch animieren (ok ok, schaut nicht wirklich wie Wasser aus, ihr könnt aber mit den Farben experimentieren oder aber zusätzlich Fragmentprogramme implementieren - das Prinzip sollte eigentlich klar sein).
Dafür binden wir einen TimeSensor an den ersten Umgebungsparameter für Vertexprogramme, der zur Zeit ja ziemlich sinnleer in unserem Source sein Dasein fristet. Carad bietet folgende Möglichkeiten, Programmparameter von außen zu steuern, ohne sie konstant vorzugeben:

  • Matrizen für Vertexprogramme können an Transformationsmatrizen von Objekten gebunden werden
  • Parameter für Vertex- und Fragmentprogramme können an TimeSensoren gebunden werden

Was ihr mit dem erstellten Source macht, steht natürlich euch offen, hier habt ihr natürlich alle Möglichkeiten lokale und globale Programmparameter zu ändern, die ihr euch vorstellen könnt.

Zuerst mal müssen wir überhaupt einen Umgebungsparameter erstellen - dazu klicken wir auf den Reiter Umgebung im Programmfenster und geben z.B. 0 im blauen Feld der ersten (und einzigen) Zeile der VP Umgebungsparameter ein (danach Enter drücken oder in anderes Feld klicken) . Folgendes geschieht:

Wir haben Carad mitgeteilt, dass wir den Umgebungsparameter mit dem Index 0 (also den ersten Umgebungsparameter) für Vertexprogramme definieren wollen. Auf die selbe Weise können wir beliebig viele (ok, bis zu 255) Parameter erstellen, Pi ist der jeweilige Index des Parameters, den wir setzen möchten. Es ist so z.B. möglich nur den 10. und 16. Parameter zu setzen.
Carad fügt automatisch Standardwerte für die Koeffizienten des Parameters ein (in ARB_ Programmen arbeitet man hauptsächlich mit Vierkomponentenvektoren), diese werden alle auf 0 gesetzt.

Der interessante Teil ist nun dieser, wir geben im Feld Timer (t) folgende Formel ein.

Erklärung: t ist die Systemzeit in Sekunden als Fließkommazahl. Da wir den Nachkommateil der halbierten Zeit nehmen und mit 2 PI multiplizieren, läuft der Umgebungsparameter alle zwei Sekunden von 0 bis 2 PI (also eine volle "Rotation" im Bogenmaß). Es ist besser möglichst viele Rechenoperationen hier auszulagern, da sie in Vertex- oder Fragmentprogrammen pro Vertex oder gar Fragment ausgeführt würden, was im Prinzip vergeudete Zeit ist.

Nach der Eingabe (Enter drücken nicht vergessen) sollten wir bereits sehen, dass die Umgebungsparameter automatisch berechnet werden. Nun haben wir noch das Problem, dass Carad aus Performancegründen, den Bildschirm nur automatisch updatet, wenn der Benutzer etwas geändert hat - da Animationen aber vom Benutzer unabhängig sind, sehen wir nur bei irgendwelchen Änderungen, dass sich etwas tut. Um Carad zu zwingen, den Bildschirm automatisch immer wieder neu zu zeichnen, müssen wir noch Animationen einschalten (Ansicht > Animationen), oder wir aktivieren das 3D-Fenster und drücken <STRG><A>, oder wir verwenden den Quickstartbutton

.

Nun sollten wir eine flüssige Wellenbewegung sehen.

Der eigentliche Freude beginnt allerdings erst :^) , denn jetzt speichern wir das Ganze als DelphiSource (wahlweise in Geschmacksrichtung WinAPI oder VCL) ab (Tipp: stellt map in den Projekteigenschaften ab, wenn ihr kein "Bodengitter" haben wollt, außerdem könnt ihr dort auch die Verwendung von fxPascal und dglOpenGL einschalten - "meine eigene" OpenGL Unit stellt nur ausgewählte ARB-Extensions zur Verfügung) und eigenen Experimenten sind Tür und Tor geöffnet.,

Viel Spaß beim Programmieren,