[Directx] Eigenes 3D Format



  • Hallo ich möchte für maximale Flexibilität gerne mal ein eigenes 3D Format schreiben (nur zum rumspielen soll nie Produktiv werden).

    So nun hab ich son bisschen rumgeguckt. Gefunden habe ich dann die Directx Meshs das fand ich ist ein guter einstieg (oder?). Im ersten schritt sollen einfach die Vertex koordinaten in einer Datei stehen diese sollen gelesen und in so einen Mesh geschrieben werden.

    So beim schreiben in diesen Mesh haperts jetzt.
    Es gibt ja diese Funktion:
    http://msdn.microsoft.com/en-us/library/bb172780(VS.85).aspx
    Die ist vom Namen her doch sehr ansprechend nur leider scheint sie doch nicht zutun was ich wollte?

    So meine Frage ist jetzt ob meine herangehensweise die richtige ist oder ob es üblicher ist mit Vertexbuffern zu arbeiten. Oder noch ganz anders. Wenn meine herangehensweise korrekt ist wüsste ich gerne welche Funktionen ich bei den Meshs übersehen habe.

    mfg nils


  • Mod

    wieso brauchst du noch das directx mesh, wenn du ein eigenes format hast, kannst du entsprechend auch deine meshklasse haben.



  • Das erschien mir einfacher. Aber gut evtl hast du wirklich recht.

    Zeichnen tue ich die meshs dann auf diese art und Weise oder gibt es da noch eine elegantere Lösung?

    Schonmal danke.

    mfg nils



  • Zeichnen tue ich die meshs dann auf diese art und Weise

    Es ist sicher sinnvoll, Vertexdaten in Vertexbuffern abzulegen.

    Du solltest etwas differenzierter betrachten, was ueberhaupt ein "Mesh" ist.
    Auf der Seite der Modelling-Software handelt es sich dabei um die allgemeine Repraesentation der Geometrie, gewoehnlich eine Ansammlung von Eckpunkten sowie einer Oberflaechendefinition und damit zusammenhaengender zusaetzlicher Attribute wie Normalen, Texturkoordinaten und Materialeigenschaften.
    Auf Seite des Renderers muessen diese Daten in deutlich speziellerer Form vorliegen, je nachdem wie die konkreten Renderdurchgaenge vorgehen sollen.
    Abhaengig vom Matieral muessen zusaetzliche Daten wie Kanten oder Tangentenraeume vorliegen (und damit unterschiedliche Vertexstrukturen) und die Datenstroeme in ein hardwarefreundliches Format gebracht werden.
    Du muesstest Dir also zunaechst ueberlegen, welche Daten (und in welcher Form) ueberhaupt in Deinem "Format" gespeichert werden sollen, wie diese Daten im Weiteren verarbeitet werden und welchen Zweck Dein Format ganz allgemein ueberhaupt erfuellen soll.



  • Hmm ich hab damit jetzt mal ein wenig rumgespielt und geübt. Ich weiß nur nicht wie ich die "Faces" berücksichtigen soll wenn ich nur nen Buffer habe.
    Ich könnte natürlich für jedes "Face" nen eigenen buffer haben.....

    Oder wie wird sowas gemacht?

    mfg nils



  • Du moechtest einen Indexbuffer anlegen.



  • Hi schonmal einen riesen dank hab mir jetzt die msdn seite durchgelesen und ein wenig gegoogelt bin mir aber garnicht sicher ob ich auf dem Richtigen Weg bin.

    Also ich habe folgenden Code geschrieben:

    Ich habe eine Klasse Objects die Listen von Objekten verwaltet.

    void Objects::AddTriangel(unsigned int x, unsigned int y, unsigned int Width, unsigned int Height) {
    		LPDIRECT3DINDEXBUFFER9 m_ib;
    		MyDirectx->Device->CreateIndexBuffer(4 * sizeof(Vertex), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_ib, NULL);
    		WORD *indices = NULL;
    		m_ib->Lock( 0, 0, (void**)&indices, 0 );
    		indices[0]=0;
    		indices[1]=1;
    		indices[2]=3;
    		m_ib->Unlock();
    		Vertex tmp[] =
    		{
    			{ x, y, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
    			{ x + Width, y + Height, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), },
    			{ x - Width, y + Height, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
    		};
    		MapObjects.push_back(Object(tmp, sizeof(tmp), 3, 1, m_ib));
    	}
    

    Ich lege dann woanders ein Dreieck an:

    Objects.AddTriangel(320, 50, 200, 350);
    

    So die klasse Object reicht immoment nur durch (Das wird sich ändern..)

    Object::Object(struct Vertex *Vertices, unsigned int Size, unsigned int NumVertices, unsigned int Triangles, LPDIRECT3DINDEXBUFFER9 Indices) : Mesh(Vertices, Size, NumVertices, Triangles, Indices) {
    	}
    

    So die klasse Mesh hat jetzt 2 Wichtige funktionen einmal den Konstruktor und dann die Funktion zum Rendern:

    Mesh::Mesh(struct Vertex *Vertices, unsigned int Size, unsigned int NumVertices, unsigned int Triangles, LPDIRECT3DINDEXBUFFER9 Indices) {
    		Buffer = NULL;
    		MyDirectx->Device->CreateVertexBuffer(3 * sizeof(Vertex), 0, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, D3DPOOL_MANAGED, &Buffer, NULL);
    		void *pVoid;
    		Buffer->Lock(0, 0, (void**)&pVoid, 0);
    		memcpy(pVoid, Vertices, Size);
    		Buffer->Unlock();
    		this->NumVertices = NumVertices;
    		this->Triangles = Triangles;
    		this->Indices = Indices;
    	}
    	void Mesh::Render3DSolid() {
    		MyDirectx->Device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
    		MyDirectx->Device->SetStreamSource(0, Buffer, 0, sizeof(Vertex));
    		MyDirectx->Device->SetIndices(Indices);
    		//MyDirectx->Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
    		MyDirectx->Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, NumVertices, 0, Triangles);  
    	}
    

    Wenn ich das so wie es immoment ist Starte seh ich leider garnichts... Wenn ich die immoment auskommentierte funktion ohne Indices nutze dann wird das Dreieck gezeichnet aber ich möchte ja nun zur Variante mit Indices kommen. Was mache ich falsch?



  • Du legst jetzt fuer jede "Triangel" einen neuen Indexbuffer an.
    Die Grundidee eines Buffers liegt aber darin, mehr als ein Element zu beinhalten.

    CreateIndexBuffer(4 * sizeof(Vertex), ...

    Wieviele Indices passen da jetzt rein?

    CreateVertexBuffer(3 * sizeof(Vertex), ...

    Und wenn Du mal mehr als ein Dreieck hast?

    indices[0]=0;
    indices[1]=1;
    indices[2]=3;

    Vertex #2 interessiert Dich nich so?



  • hellihjb schrieb:

    Du legst jetzt fuer jede "Triangel" einen neuen Indexbuffer an.
    Die Grundidee eines Buffers liegt aber darin, mehr als ein Element zu beinhalten.

    Ja das ist mir schon klar aber das dient ja grade alles übungszwecken. Ich komme halt mehr aus dem Linux und OpenGL bereich => taste mich grade Stückchen für Stückchen mit eurer Hilfe vorran.

    hellihjb schrieb:

    CreateIndexBuffer(4 * sizeof(Vertex), ...

    Wieviele Indices passen da jetzt rein?

    Viermal die größe meiner Vertex struktur wieso? Drei reichen auch oder was willst du mir sagen?

    hellihjb schrieb:

    CreateVertexBuffer(3 * sizeof(Vertex), ...

    Und wenn Du mal mehr als ein Dreieck hast?

    Dann lege ich 2 VertexBuffer an? Oder sollte man das nicht?

    hellihjb schrieb:

    indices[0]=0;
    indices[1]=1;
    indices[2]=3;

    Vertex #2 interessiert Dich nich so?

    [/quote]

    Danke wo war ich da gestern nur mit meinen gedanken. Das klappt jetzt.

    Jetzt hab ich mal gleich den Code für ein Viereck geschrieben:

    void Objects::AddQuad(unsigned int x, unsigned int y, unsigned int Width, unsigned int Height) {
    		LPDIRECT3DINDEXBUFFER9 m_ib;
    		MyDirectx->Device->CreateIndexBuffer(8 * sizeof(Vertex), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_ib, NULL);
    		WORD *indices = NULL;
    		m_ib->Lock( 0, 0, (void**)&indices, 0 );
    		indices[0] = 0;
    		indices[1] = 1;
    		indices[2] = 3;
    		indices[3] = 3;
    		indices[4] = 1;
    		indices[5] = 2;
    		m_ib->Unlock();
    		Vertex tmp[] =
    		{
    			{ x, y, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
    			{ x + Width, y, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), },
    			{ x, y - Height, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
    			{ x + Width, y - Height, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
    		};
    		MapObjects.push_back(Object(tmp, sizeof(tmp), 4, 2, m_ib));
    	}
    

    Dabei entsteht dann malwieder garnichts...

    mfg nils



  • Wieviele Indices passen da jetzt rein?

    Viermal die größe meiner Vertex struktur wieso?

    Du willst aber keine Vertices im Indexbuffer speichern 🙂
    Ausserdem willst Du fuer jedes Objekt *einen* Vertex- und *einen* Indexbuffer anlegen um die Grafikkarte mit moeglichst geringem Aufwand moeglichst lange zu beschaeftigen.
    Die GPU ist eine Streamarchitektur und Bufferwechsel entsprechend teuer. Jedes Polygon in einem eigenen Buffer zu halten ist nicht umsetzbar.



  • Sry doppelpost is keine absicht



  • Kann ich denn Sachen zu aus einem Buffer wieder in ein Array zurück wandeln? Bzw kann ich die einzelenen sachen aus dem Buffer verändern? z.b. für Bewegung?



  • Du kannst den Buffer locken und mit neuen Daten ueberschreiben oder die dafuer notwendigen Berechnungen im Vertex-Shader ausfuehren.
    Aus einem Vertexbuffer zu lesen kann um ein Vielfaches langsamer sein.



  • Naja es geht grad nur um den Editor den ich mir zurechtschreibe um das ganze ein Wenig zu testen.
    Ich wöde den Buffer dann immer wenn was hinzugefügt wird größer machen wollen und müsste dazu die alten Daten erstmal in den Neuen kopiern geht sowas? (Performant muss das an der stelle nicht sein).

    Bei Bewegungen wödest du dann den ganzen Buffer neu schreiben oder kann man nur bestimmte stellen des Buffers überschreiben?

    mfg nils


  • Mod

    bei einem editor waere es nicht schlimm wenn du die daten auch local im speicher haettest, du kommst frueher oder spaeter auf die idee damit noch was anderes anzustellen (z.b. picking) und dann musst du oefter drauf zugreifen, was nicht smart waere bei nem vertexbuffer von d3d 😉

    zudem, wenn es nur ein 'editor' ist, kannst du dir eventuell immer noch ein wenig 'puffer' hintern dran allokieren, sodass, falls noch ein paar mehr vertices dazu kommen, du keinen neuen buffer allokieren musst. ab und zu musst du das dann vielleicht wieder, aber das sollte bei einem editor absolut kein performance problem darstellen. (niemand wird sich beschweren wenn es einen ruckler geben sollte 😉 )



  • rapso schrieb:

    (niemand wird sich beschweren wenn es einen ruckler geben sollte 😉 )

    Stimm da das wie gesagt alles dem Spaß dient werde wahrscheinlich nur ich das ganze einsetzen und das auch nur zum testen 😃

    Ich finde grade keine Funktion um die Vertex und Index Buffer wieder zu "löschen", gibt es da keine Funktion? Und ich erstell den neuen einfach "Über" dem alten?

    mfg nils


  • Mod

    ->Release(), wie bei allen resourcen.
    und nein, du erstellst keinen drueber, danaben oder daruntern, du hast nur CreateVertexbuffer und der treiber sucht sich aus ws er damit macht.



  • Jau danke dann werd ich da heut Abend mal weiter dran rumspielen muss ja jetzt doch nen bisschen was umnstellen. Melde mich wieder wenns noch Probleme/Fragen gibt.

    Erstmal ein riesen danke an die wunderbare hilfe die ihr mir gegeben habt.

    mfg nils 🙂



  • Es hat sich da jetzt doch gleich eine neue Frage aufgedrängt. Und zwar immoment haben meine Gegenstände ja alle nur Farben wie mach ich das denn dann das die verschiedene Texturen haben können?

    Bekommt die Vertex Struktur dann anstatt D3DCOLOR_XRGB ein enstprechendes Textur Objekt?

    Und es ist dann auch richtig das ich den Buffer jedesmal neu erstellen muss wenn sich ein Objekt bewegt oder?

    mfg nils



  • Bekommt die Vertex Struktur dann ein Textur Objekt?

    Das wuerde keinen Sinn machen weil ja sonst fuer die jeweiligen Eckpunkte eines Polygons unterschiedliche Texturen definiert sein koennten.
    Stattdessen weisst man jedem Polygon eine Material-ID (das Material beinhaltet neben anderen Parametern auch die Textur(en)).
    Um nicht jedes Polygon einzelnd zeichnen und staendig Renderstates aendern zu muessen kannst Du fuer das Mesh zb eine Liste von verwendeten Materialien halten und fuer jedes Material eine Liste von Polygonen (oder dessen Indices) die es verwenden.



  • Hmm aber wie funktioniert das Rendern denn dann?
    Mal angenommen ich möchte für meinen Test Editor erstmal nur die ansicht mit Farben und dann irgendwann eine mit Texturen dann soll man da aber trozdem noch umschalten können.

    Ist sowas möglich wie teile ich Direct x dann mit wie er rendern soll?

    mfg nils


Anmelden zum Antworten