Totgeglaubte leben länger, oder so ähnlich heißt es - und tatsächlich hat der BaseLevelBaker nach über einem halben Jahr präsentierbare Formen angenommen.
http://www.basegraph.com/bg/blb/blb.zip.
Die Funktionsweise wurde ja schon in den bisherigen Posts erklärt, sodass ich hier eher auf die Oberfläche eingehen werde:
Load File lädt eine Datei, wobei es sich zur Zeit um ein VAD (Vertex Attribute Data, wird weiter unten erklärt) oder eine BaseGraph Datei, wie sie von Carad erzeugt wird handeln kann. Später werden noch BaseGraph Pascal Datendateien und 3DS hinzukommen, andere Formate können ja über Carad importiert, oder in eigenen Programmen als VAD exportiert werden.
Beim Laden einer Datei werden sämtliche Objekte darin automatisch in ein großes TriMesh (= Set aus Dreieckslisten, die verschiedenen Zusammenstellungen von Shadern zugeordnet sind) konvertiert, aus dieser "Dreieckssuppe" wird fürderhin der Octree generiert werden. Die Erstellung des selben wird über folgende Parameter gesteuert:
Threshold: maximale Anzahl von Dreiecken in einem Blatt
MinDepth: minimale Rekursionstiefe
MaxDepth: maximale Rekursionstiefe
Tolerance: Toleranzwert beim Zerschneiden der Polygone.
Über Threshold und MinDepth kann gesteuert werden, ob man sich rein auf die Anzahl der Polygon konzentrieren möchte, oder aber ob es wichtiger ist, dass alle Nodes eher gleich groß sind, was insbesondere dann wichtig ist, wenn der Octree nicht nur sich selbst, sondern auch andere Objekte darstellen soll, oder auch z.B. für Kollisionserkennung und Physik herangezogen wird.
Ich wollte, dass die Octreeklasse allgemeingültig ist, d.h. es sollte egal sein, ob die zugrundeliegende Polygonsuppe aus großen, kleinen, vielen oder wenigen Polygonen besteht. Was in jedem Fall vermieden werden sollte, war auch das mehrfache Rendern einzelner Polygone, aus diesem Grund werden Polygone an den Rändern eines Blattes zerschnitten, wobei aber sämtliche Vertexattribute an der Schnittstelle ebenfalls mitberechnet werden.
Das Zerschneiden einer Fläche hat aber den Nachteil, dass neue Schnittpunkte und Polygone entstehen - aus diesem Grund gibt es den Toleranz-Parameter, mit dem man einstellen kann, dass, wenn ein Polygon nur "ein wenig" über die Grenze eines Blattes ragt, das Blatt wächst, anstatt, dass das Polygon zerschnitten wird. Es ist in jedem Fall garantiert, dass ein Polygon nur in einem einzigen Blatt aufscheint, und dass die Box eines Nodes die Boxen sämtlicher untergeordneter Nodes inkludiert.
Ein zu kleiner Toleranzwert hat zur Folge, dass im schlechtesten Fall an den Rändern von Blättern viele sehr kleine Polygone entstehen (ungut), ein zu großer Toleranzwert lässt die Nodes unverhältnismäßig stark wachsen, was auch nicht im Sinne des Erfinders ist - sinnvolle Werte liegen zwischen 0.5 und 0.01.
Nach der Erstellung eines Octrees ist eingestellt, dass jeder Node von jedem anderen Node aus sichtbar ist - sogar jetzt kann er aber schneller gerendert werden (zumindest, wenn sich der Betrachter "darin" befindet), da Frustum Culling automatisch auf die Nodes angewandt wird. Ein Octree rendert auch eine sehr große Anzahl von Nodes performant, da Kindnodes automatisch verworfen werden, sobald ein Elternnode nicht gerendert werden muss.
Die Erstellung der PVS Informationen kann über folgende Parameter gesteuert werden:
GS Order: "GeoSphere Order", die Anzahl der Richtungen, in die von verschiedenen Punkten eines Blattes aus gerendert wird - bei 0 sind es 20, je höher die Ordnung, desto exakter die PVS Informationen, desto langsamer aber auch die Berechnung der PVS Informationen. Null reicht für das voreingestellte field of view von 60° aus, wenn man ein geringeres Field of View verwenden möchte, sollte eine GS Order von 1 verwendet werden - 2 oder mehr bringen nur bei sehr geringem FoV etwas.
Quick Query: Es wird nur von der Mitte eines Blattes aus gerendert - das beschleunigt die Sache erheblich, sollte aber nur bei kleinen Blättern (MinDepth relativ groß) verwendet werden. Zum Testen praktisch, da ansonsten die Berechnung der PVS Informationen besonders für komplexere Szenen recht lange dauert.
Samples: Maximale Anzahl von Pixeln, ab denen ein Node als "sichtbar" betrachtet wird, wenn er von einem anderen Node aus gesehen wird. Es macht eventuell keinen Sinn, Nodes zu rendern, wenn nur sehr wenige Pixel davon sichtbar sind, insbesondere als für die Sichtbarkeitsberechnung eines Nodes dessen Bounding Box und nicht dessen Inhalt herangezogen wird.
Wie gerade erwähnt, könnte ich für die Occlusion Queries theoretisch auch den Inhalt des Octrees heranziehen, anstatt die Bounding Boxes der einzelnen Nodes zu rendern - dies würde dann ein etwas exakteres (sprich weniger Nodes wären sichtbar) Ergebnis liefern. Ein statischer Octree alleine ist aber recht langweilig, und damit die PVS Informationen aber auch für externe Objekte herangezogen werden können, sobald festgestellt wurde, in welchen Blättern diese sich befinden, ist wichtig, von welchen Nodes aus die BoundingBox eines bestimmten Blattes sichtbar ist oder nicht.
Sonstige Einstellungen sind noch:
Draw Tree: Der Octree selbst wird mitgezeichnet, zusammen mit einigen weiteren statistischen Informationen
Display Lists: Die Dreiecksinformationen der einzelnen Blätter werden in Display Lists anstelle von Vertex Arrays gespeichert. Das bringt einen erheblichen Geschwindigkeitsschub, da der Octree ohnehin statisch ist, sehe ich auch keinen Vorteil darin, statische VBOs zu verwenden - und Display Lists laufen auch auf älteren OpenGL Implementationen (in der Tat benötigt nur die Octree Builder Klasse Occlusion Queries, die Octree Klasse selbst funzt bereits mit OpenGL 1.1). Wenn Display Lists vor dem berechnen der PVS Informationen eingeschaltet werden, wird die Berechnung derselben ebenfalls etwas beschleunigt.
Wireframe Rendering: Wie der Name sagt, die Darstellung des Meshes spiegelt aber ebenfalls den aktiven Node sowie die Sichtbarkeit vom aktiven Node aus wieder.
Viewer Node: anstatt über den Rollbalken wird der aktive Node über die Position des Betrachters gesetzt
Light From Viewer: Die OpenGL Lichtquelle 0 wird auf die aktuelle Position des Betrachters gesetzt (und verbleibt dort, auch wenn der Betrachter bewegt wird)
In der Klasse vorhanden, aber noch nicht ins Programm eingebaut sind:
* das Entfernen von Nodes ohne Dreiecke - hauptsächlich für die Darstellung interessant, bei der Einordnung externer Objekte ist eine größere Anzahl von Blättern hingegen eher günstig.
* das Freigeben von SPeicher nach der Erstellung von Displaylisten - für Applikationen wichtig, der Octree Builder verzichtet hingegen darauf, vor allem weil ich jederzeit Zugriff darauf haben möchte, wieviele Dreiecke eigentlich darin gespeichert sind.
* das Speichern von fertigen Octrees, weil ich noch nicht weiß, wie ich halbwegs elegant und ohne Einschränkungen Shader hineinbekomme, wenn ich nicht auf das Carad (*.bg) oder BaseGraph Pascal Exportformat (*.bgp) zurückgreifen kann - wahrscheinlich wird mir nichts anderes übrig bleiben, als halt Namen abzuspeichern, die ein Benutzer dann nach dem Laden selbst auswerten muss.
Zum Testen ist eine .bg Datei mit dabei, eigene Programme können hingegen VAD Dateien exportieren, die sehr einfach aufgebaut sind:
Die erste Zeile stellt die Vertexkomponenten dar, die im folgenden gespeichert werden. VAD ist sehr flexibel und kennt folgende Attribute:
V3 (Vector XYZ)
N3 (Normal XYZ)
C3 (Color RGB)
C4 (Color RGBA)
S3 (Secondary Color RGB)
F1 (Fog Coordinate)
T1 (Texture S)
T2 (Texture ST)
T3 (Texture STR)
T4 (Texture STRQ)
A1 (Attribute X)
A2 (Attribute XY)
A3 (Attribute XYZ)
A4 (Attribute XYZW)
Texturkoordinaten und Attribute können auch mehrfach angegeben werden, für Multitexturing macht etwa folgendes Sinn:
V3/T2/T3/
Bedeutet erst kommt eine Position, Textureinheit #1 bekommt ST, Textureinheit 2 bekommt STR Werte, die Reihenfolge, in der die Vertexkomponenten angegeben werden ist egal, nach dem Laden könnten den einzelnen Texturkoordinatensets beliebige Textureinheiten zugeordnet werden.
Nach den Vertexkomponenten folgt eine Leerzeile, danach kommen die Vertexdaten selbst, wobei die gespeicherten Floats der Reihenfolge in den Vertexkomponenten entsprechen müssen, zwischen den einzelnen Vertexkomponenten steht ein / nach jedem vollständig definierten Vertex kommt ein Zeilenumbruch.
Wenn mehrere Objekte in einer Datei gespeichert werden, genügt es, zwischen den einzelnen Objekten Leerzeilen zu lassen - nach dem Laden könnten diesen Objekten dann wieder Shader zugeordnet werden.
Prinzipiell weiß das VAD Format nichts von dem Polygon Primitive für das Daten gespeichert wurden (Dreiecke, Vierecke, u.s.w.), BLB geht aber davon aus, dass sämtliche Objekte aus Dreiecken bestehen, die jeweils als drei Punkte gespeichert werden.
Ein VAD für einen Würfel mit 2D Texturkoordinaten und Normalvektoren sieht etwa folgendermaßen aus:
Code: V3/N3/T2/ -0.5 -0.5 -0.5/0 0 -1/0 0/ -0.5 0.5 -0.5/0 0 -1/1 0/ 0.5 0.5 -0.5/0 0 -1/1 1/ -0.5 -0.5 -0.5/0 0 -1/0 1/ 0.5 0.5 -0.5/0 0 -1/0 0/ 0.5 -0.5 -0.5/0 0 -1/0 0/ 0.5 -0.5 0.5/0 0 1/0 0/ 0.5 0.5 0.5/0 0 1/0 0/ -0.5 0.5 0.5/0 0 1/0 0/ 0.5 -0.5 0.5/0 0 1/0 0/ -0.5 0.5 0.5/0 0 1/0 0/ -0.5 -0.5 0.5/0 0 1/0 0/ -0.5 -0.5 0.5/-1 0 0/0 0/ -0.5 0.5 0.5/-1 0 0/0 0/ -0.5 0.5 -0.5/-1 0 0/0 0/ -0.5 -0.5 0.5/-1 0 0/0 0/ -0.5 0.5 -0.5/-1 0 0/0 0/ -0.5 -0.5 -0.5/-1 0 0/0 0/ 0.5 -0.5 -0.5/1 0 0/0 0/ 0.5 0.5 -0.5/1 0 0/0 0/ 0.5 0.5 0.5/1 0 0/0 0/ 0.5 -0.5 -0.5/1 0 0/0 0/ 0.5 0.5 0.5/1 0 0/0 0/ 0.5 -0.5 0.5/1 0 0/0 0/ -0.5 -0.5 -0.5/0 -1 0/0 0/ 0.5 -0.5 -0.5/0 -1 0/0 0/ 0.5 -0.5 0.5/0 -1 0/0 0/ -0.5 -0.5 -0.5/0 -1 0/0 0/ 0.5 -0.5 0.5/0 -1 0/0 0/ -0.5 -0.5 0.5/0 -1 0/0 0/ -0.5 0.5 0.5/0 1 0/0 0/ 0.5 0.5 0.5/0 1 0/0 0/ 0.5 0.5 -0.5/0 1 0/0 0/ -0.5 0.5 0.5/0 1 0/0 0/ 0.5 0.5 -0.5/0 1 0/0 0/ -0.5 0.5 -0.5/0 1 0/0 0/
|