Implementation von Vertex-Klassen



  • Hi!

    Wir hatten schon einmal ein ähnliches Topic hier - allerdings sind wir da ein
    bisschen vom Thema abgekommen - also noch einmal, und diesmal gleich präziser!

    Das Problem bei der Implemation einer Vertex-Klasse ist aus meiner Sicht
    folgendes: Da jedes Objekt unterschiedlich viele Textur-Schichten hat, muss
    ein Vertex auch dynamisch viele Textur-Koordinaten bieten (bis zu 8).

    Man kann allerdings ja keine zusätzliche Variable in die Vertex-Klasse auf-
    nehmen, die speichert wie viele Tex-Koordinaten da sind, da man dann keine
    Arrays mehr aus der Vertex-Klasse bilden kann (zum direkten schreiben in
    den Buffer in einem Stück).

    Vererbung geht auch nicht, da dann die vftable hinzukommt.

    Eine andere Idee wäre eine Template-Klasse. Geht allerdings auch nicht, da
    man dann den Vertex nicht mehr allgemein ansprechen kann.

    Meine Frage also: Wie habt ihr das Problem in euren Engines gelöst?
    Seid ihr z.B. generell von 8 Textur-Koordinaten ausgegangen?

    Würde mich über rege Beteiligung freuen 🙂



  • ich habs so gelöst: eine klasse die das vertexformat speichert(also anzahl texturen etc),und einen vector enthält, der die kompletten vertexdaten gespeichert hat.



  • Vererbung geht auch nicht, da dann die vftable hinzukommt.

    Wieso sollte die vftable hinzukommen?



  • Abbadon schrieb:

    Vererbung geht auch nicht, da dann die vftable hinzukommt.

    Wieso sollte die vftable hinzukommen?

    Weil wir virtuelle Methoden brauchen (z.B. um die Koordinaten zu setzen).



  • Braucht ihr wirklich virtuelle Methoden? Es geht bestimmt auch ohne.



  • EnERgYzEr schrieb:

    Hi!
    Das Problem bei der Implemation einer Vertex-Klasse ist aus meiner Sicht
    folgendes: Da jedes Objekt unterschiedlich viele Textur-Schichten hat, muss
    ein Vertex auch dynamisch viele Textur-Koordinaten bieten (bis zu 8).

    Man kann allerdings ja keine zusätzliche Variable in die Vertex-Klasse auf-
    nehmen, die speichert wie viele Tex-Koordinaten da sind, da man dann keine
    Arrays mehr aus der Vertex-Klasse bilden kann (zum direkten schreiben in
    den Buffer in einem Stück).

    Vererbung geht auch nicht, da dann die vftable hinzukommt.

    ...

    Meine Frage also: Wie habt ihr das Problem in euren Engines gelöst?

    Hm ich habe es einfach bei einem struct belassen, aber vor ein paar Wochen mal angefangen eine Klasse zuschreiben.
    - eine Vertexklasse die alle möglichen Elemente (xyz(rhw),normale, farbe, 8 Texturkoodinaten) enthält
    - einen Descriptor der genau angibt welche elemente tatsächliche benutzt werden
    - eine Größenangabe, die die Bytezahl der benutzten Daten angibt (als Vertex.size statt sizeof(Vertex) ), welche aus dem Descriptor errechnet wird
    - einen Konstruktur der gleich dem Vertex seinen Descriptor mitteilt
    - new[] Operator wird überladen, so das er eine verkette liste von Vertexklassen zurückgibt
    - jeder Vertex enthält eine Zeiger auf das nächste Element eines Vertex-Arrays
    - eine Funktion MakeVBuffer(int length) die ein Vertexbuffer aus dieser verketteten Vertex-Liste macht
    - Funktionen zum einfügen/löschen von Vertices aus der liste
    - Funktionen zum setzen der Werte, ermitteln des FVF etc...

    Vorteile:
    - Einfügen und löschen von Elementen geht gut
    - eine Klasse für alle Vertextypen

    Nachteile:
    - unnützer Speicherverbrauch, durch überflüssige Elemente
    - langsamer bei z.B. Erstellung eines VertexBuffers

    Keine Ahnung, ob das überhaupt so toll ist. Was haltet ihr davon?

    Auf meinem Laptop ich diese Klasse schon fast fertig, aber den hab ich heut in der Firma gelassen.



  • illuminator schrieb:

    - new[] Operator wird überladen, so das er eine verkette liste von Vertexklassen zurückgibt

    Das ist eine geniale Idee!

    Bei der Erstellung des VertexBuffers musst du dann aber die Daten per Schleife
    kopieren, oder? Andererseits fällt dieser Prozess nur einmal an.

    Gut finde ich auch die Idee, einen Vertex selbst die Erstellung des Buffers
    übernehmen zu lassen! 👍



  • Warum einfach, wenn's auch kompliziert...

    Allokier doch einfach soviel Byte, wie du brauchst und schreib dann die Daten "von Hand" an die passenden Stellen. Die kann man ja aus dem Format einfach berechnen.

    Bye, TGGC \-/



  • TGGC schrieb:

    Allokier doch einfach soviel Byte, wie du brauchst und schreib dann die Daten "von Hand" an die passenden Stellen. Die kann man ja aus dem Format einfach berechnen.

    Worauf bezieht sich diese Antwort??

    Auf die illuminator-Lösung?



  • hi,

    nützlich ist es schon eine eigene Vertexklasse zu schreiben die angibt welche informationen verwendet werden sollen. in gängingen lösungen (bspw. ogre3d, nebula2) findet man in einer solchen struktur alle benötigten datenelemente (xyz, normal, tangent, binormal, diffuse, blend, specular, tex0..3). nur so viele Kombinationen wird man meist nicht nutzen. da man die daten fast immer parallel im system ram rumliegen hat, würde ich es darauf beziehen. aus den vorhandenen daten dann nen vertexbuffer zu erstellen und zu füllen, der dann nur die elemente aufnimmt die auch wirklich benötigt werden, ist dann auch nicht das problem. mit geringem aufwand lässt sich für den vertexarray ein iterator basteln, mit dem man noch handlicher und effektiver arbeiten kann (oder vertices gleich in einen std::vector packen). den operator new dafür zu überladen, halte ich für unnötigen overkill.

    @illuminator
    deine lösung finde ich teilweise unschön. wieso zeigt zB jeder vertex auf das nächste element?

    gruss,
    Sebastian



  • zebel schrieb:

    deine lösung finde ich teilweise unschön. wieso zeigt zB jeder vertex auf das nächste element?

    Weil ich dann eine verkette Liste hab wo ich einfach mit z.B. Vertex->InsertAfter(new Vertex[10],10) zehn vertices mittendrin einfügen kann.
    fragt sich natürlich wie sinnvoll das ist und ob man das braucht... 😃
    Aber meine Überlegung war halt, dass wenn man eh schon nur eine Klasse für jeden Vertex-Typ hat und deswegen sowieso nicht mit einem memcpy-befehl alles in eine Vertexbuffer schieben kann und jeden Vertex einzeln anfassen muss, auch gleich eine verkette liste Liste draus machen könnte.

    TGGC schrieb:

    Allokier doch einfach soviel Byte, wie du brauchst und schreib dann die Daten "von Hand" an die passenden Stellen. Die kann man ja aus dem Format einfach berechnen.

    Hm, wie meinst du das?

    Soll der Konstruktur der Vertexklasse anhand des FVF genügend Byte allokieren ?
    Dann musst du dir doch aber auch offsets für normale, tex1, farbe etc. merken, damit du die nicht bei jedem Aufruf von z.B. Vertex->SetNormal(nx,ny,nz) neu ermitteln musst.
    womit du dann wieder unnötigen Speicherverbrauch hättest (wenn auch möglichweise weniger) und du trotzdem wieder für jeden Vertex einen memcpy beim erstellen des Vertexbuffer bräuchtest.

    Oder meintest du es anders? 😕



  • @EnERgYzEr:
    Auf deine Frage.

    @Optimizer:
    Und an ein paar Offsets pro VB wirst du nicht sterben. Als Offset reicht ein Byte, ein Eintrag (normal ja float oder DWORD) braucht vier. Ab 25 Vertizen pro VB brauchen die Offsets also nur noch 1%...

    Denk ausserdem mal drüber nach, ob das wirklich unnötig ist. Die Offsets brauchst du bei _jeder_ Methode.

    Was du für'n Problem mit memcpy meinst, weiss ich nicht. Ich seh keines.

    Bye, TGGC \-/



  • TGGC schrieb:

    @Optimizer:

    Du meinst mich nicht Optimizer 😃

    TGGC schrieb:

    Und an ein paar Offsets pro VB wirst du nicht sterben. Als Offset reicht ein Byte, ein Eintrag (normal ja float oder DWORD) braucht vier. Ab 25 Vertizen pro VB brauchen die Offsets also nur noch 1%...

    Du willst dir die Offsets also außerhalb der Vertexklasse merken? Find ich nicht gut.
    Oder willst du sie in der Klasse static machen? Ist doch auch gar nicht gut wenn du veschiedene Vertextypen brauchst, oder?

    TGGC schrieb:

    Denk ausserdem mal drüber nach, ob das wirklich unnötig ist. Die Offsets brauchst du bei _jeder_ Methode.

    Nichts anderes hab ich gesagt. Ich meinte lediglich "unnötig" im dem Sinne, dass man ja eigentlich nur den Speicher für Vertexdaten an einem Stück haben möchte und nicht mittendrin noch die Offsets.



  • Finde das alles ziemlich interessant, und würde gern mal wissen, was von folgender Idee zu halten ist (Einfachheit geht mal vor Effizienz):
    Man übergibt dem Konstruktor der Vertexklasse (ich nenn sie lieber Meshklasse) einen Enum, der den Typ spezifiziert.
    Die Klasse initialisiert damit ihren std::vector<std::vector<>> mit entsprechend vielen Vectoren des entsprechenden Typs, also wenn man POS_NORM_TEX als Typ des Meshes angibt, bekommt der obere std::vector der Klasse 3 std::vectoren, von denen wieder 2 vom Typ vec3 sind und einer vom Typ vec2 ist.

    Fragen sind also: Wäre das eine gute, einfache Möglichkeit? Ist das überhaupt möglich, muss man denn nicht schon in der Klassendefinition den Typ des std::vectors der in dem oberen std::vector enthalten ist, angeben?
    Also z.b. so: std::vector<std::vector<vec3>>
    Das wär aber nicht möglich, weil man ja nicht weiß obs ein vec3, vec4 oder doch nur ein vec2 sein soll, bzw. weil sich das ja dann auch unterscheidet.

    Und noch was:
    Wäre es schlechtes Design, schon dieser Meshklasse API-spezifische Funktionen zu geben?
    Wenn nicht, würde dann (für OGL) eine Funktion "GLuint compileDisplayList()" oder irgendwas mit VertexArrays / VBOs Sinn machen?

    EDIT: "std::" hinzugefügt und andere Unklarheiten beseitigt.



  • das geht nur mit templates, und die habenw ir schon ausgeschlossen.
    in der richtung mit enum gings nur über polymorphie, und ich glaub nich, dass wir 1000 verschiedene vertexklassen wollen^^

    aber nur mal so ne frage am rande: wozu brauch man 8 paar vertexkoordinaten?
    1.schicht relief
    2. schicht standardtextur
    3.schicht detailtextur
    4.schicht lightmap

    vielelicht noch ne 5. schicht für ne weitere textur mit details...
    darüber hinaus wirds doch schon sehr ungewöhnlich oder irr ich mich jetzt?



  • otze schrieb:

    aber nur mal so ne frage am rande: wozu brauch man 8 paar vertexkoordinaten?
    1.schicht relief
    2. schicht standardtextur
    3.schicht detailtextur
    4.schicht lightmap

    z.B. noch Alpha für Detailtextur oder noch weitere Standardtexturen



  • alpha für detail?



  • Also ich meinte mit Detailtextur eine Normalmap (vielleicht bezeichnest du
    das als Relief??). Und die macht durchaus Sinn mit einer Alphamap zu
    kombinieren. Z.B., wenn man will, dass nur die Steine im Terrain Risse haben
    und nicht das Gras 😉



  • relief ist dafür da um einer textur durch grautöne eine plastizität zu geben.
    ansonsten mein ich mit detailmap das, was du auch meinst^^



  • @Opti: Sorry.

    @illumintaor:
    Von ausserhalb oder innerhalb habe ich nichts gesagt, möglich wäre alles. Es könnte z.b. einen OffsetManager geben, der Offset alle bisher nötigen Vertextypen cached...
    Und Die Offsets sind doch nicht mittendrin!

    Bye, TGGC \-/



  • Das Problem bei der Implemation einer Vertex-Klasse ist aus meiner Sicht
    folgendes: Da jedes Objekt unterschiedlich viele Textur-Schichten hat, muss
    ein Vertex auch dynamisch viele Textur-Koordinaten bieten (bis zu 8).

    nach längerem überlegen kam ich auf folgenden gedanken:
    pack in die vertices das, was jedes objekt minimal braucht, und pack das, was objektspeziell ist, in eine andre streamsource und benutz shader.
    (5 unbenutze texturschichts koordinaten pro vertex 😮 ).


Anmelden zum Antworten