Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

26.11.2014, 19:06

[DX9] Vertexdeclaration um flexibel zu bleiben

Hallo zusammen,

wie immer und jedes Jahr um diese Jahreszeit sitze ich mal wieder länger am PC.

Ich versuche gerade das FVF durch Vertexdeclaration zu ersetzen, aber so richtig habe ich das noch nicht verstanden. Was ich Momentan verstehe das ich ja mehrere Streams dazu nutzen kann ein 3D Modell zu färben oder texturieren usw...

Was ich aber nicht verstehe. Wie kann mir (oder geht das überhaupt nicht) die Vertexdeklaration helfen flexibler zu sein als mit FVF?

Ich habe mit das so vorgestellt:

Das ist der erste Code:

C-/C++-Quelltext

1
2
3
    g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer,   0, sizeof(Vertex) );
    g_pd3dDevice->SetStreamSource( 1, g_pColorBuffer,    0, sizeof(Color) );
    g_pd3dDevice->SetStreamSource( 2, g_pTexCoordBuffer, 0, sizeof(TexCoord) );


Ich habe mir gedacht, ich blende einfach den Stream mit den Texturen aus und habe nur noch die Vertexfarbe. In etwa so:

C-/C++-Quelltext

1
2
3
    g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer,   0, sizeof(Vertex) );
    g_pd3dDevice->SetStreamSource( 1, g_pColorBuffer,    0, sizeof(Color) );
    //g_pd3dDevice->SetStreamSource( 2, g_pTexCoordBuffer, 0, sizeof(TexCoord) );


Aber das geht natürlich nicht, weil das Programm abschmiert.

Was ich haben will ist eine wirklich flexible Möglichkeit Vertexbuffer mit den "nötigen" Eigenschaften zu erstellen. Ich bin mir auch nicht sicher ob das geht. Vielleicht gibt es hier den einen oder anderen der einen Weg gefunden hat und sein Wissen teilen möchte. :)

[EDIT] Oder die Frage so gestellt. Wie kann ich Elemente aus dem Inputstream weglassen?

Gruß Gombolo

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »gombolo« (26.11.2014, 19:28)


2

26.11.2014, 21:00

Das geht, Du musst sie halt auch in der VertexDeclaration weglassen. Für jede neue Kombination von streams (oder auch schon nur, wenn Du die Reihenfolge änderst) brauchst Du eine andere VertexDeclaration.

Kannst Du Englisch ? Gothic III hat sowas benutzt: Optimizing Resource Management with Multistreaming. Der Artikel zeigt ziemlich ausführlich, was Du im Sinn hast.

Edit: Übrigens gibts für den Umstieg von FVF die hilfreiche Funktion D3DXDeclaratorFromFVF

3

26.11.2014, 21:16

Hallo,

danke für die Antwort. Den Artikel habe ich schon gelesen. Mein englisch ist nicht sehr gut, ich denke ich habe nicht mal die Hälfte richtig verstanden, aber in etwa worum es geht.

Mein Ziel ist aber ein anderer. Ich möchte DirectX so kapselt das die Benutzung so einfach wie möglich wird. :golly: Der Nutzer soll sich nicht mit dem ganzen Kram von Vertexdeklaration uns so herumschlagen. :zombie: Ich habe auch schon eine Idee. Ich versuche morgen mehr zu schreiben. Vielleicht hat der eine oder andere eine viel bessere Idee.

Gruß Gombolo

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

4

28.11.2014, 10:43

Was ich haben will ist eine wirklich flexible Möglichkeit Vertexbuffer mit den "nötigen" Eigenschaften zu erstellen. Ich bin mir auch nicht sicher ob das geht. Vielleicht gibt es hier den einen oder anderen der einen Weg gefunden hat und sein Wissen teilen möchte.


Du könntest deine Vertexdaten z.B. so gruppieren, dass die die Möglichkeit hast Streams zu deaktivieren, falls nicht gebraucht (z.B. Normal/Tangent für Shadowmapping o.Ä.). Beispielsweise könntest du Position und Texcoord0 in einen Vertexpuffer packen. Zusätzliche Streams wären dann z.B. Texturkoordinaten, Skinningdaten, Tangentframe etc... Die Vertexdeklaration (bzw FVF) ist dann abhängig davon welche Attribute/Streams du für einen Pass benötigst. Die Auswahl könntest du automatisieren, wenn dir die Informationen vorliegen wie das Inputlayout von deinem Vertexshader aussieht. Dann kannst du ggf auch fehlende Vertexattribute dazupatchen oder was auch immer notwendig ist.

Hier ggf als Gedankenstütze wie ich das in meinem kleinen Testframework gelöst habe:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct VertexStream
{
  VertexBuffer* vertexBuffer;
  uint32 stride;
};

struct VertexElement
{
  VertexElement(uint32 streamIndex, const String& semantic, uint32 index, eVertexElementType type)
    : streamIndex(streamIndex)
    , semantic(semantic)
    , index(index)
    , type(type)
  {
  }

  uint32 streamIndex;
  String semantic;
  uint32 index;
  eVertexElementType type;
};


VertexElement beschreibt genau ein Attribute und VertexStream hält alle Daten vor die notwendig für einen Drawcall sind.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
class VertexDeclaration
{
public:
  static VertexDeclaration* create(const std::vector<VertexElement>& elementList);
  const std::vector<D3D11_INPUT_ELEMENT_DESC>& getElements() const { return m_VertexElements; }

  // [...]

private:
  std::vector<D3D11_INPUT_ELEMENT_DESC> m_VertexElements;
};


VertexDeclaration ist die Beschreibung von den Vertexdaten. Also in diesem Fall nur ein sehr dünner Layer über der Schnittstelle die DX11 anbietet. Das könnte natürlich auch entsprechend abstrahiert werden um andere APIs zu unterstützen. VertexAccess ist eine dünne Schicht die verwendet wird um Vertexstreams zusammen zu bauen und an den Renderkontext zu geben. Vertexdaten haben i.A. die üblichen Vertexpuffer/Indexpuffer und ein VertexAccess Objekt das den Vertexzugriff innerhalb der Puffer beschreibt.

Verwendet wird das so:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void MeshChunk::initialize(const struct RawMesh& mesh, uint32 startIndex, uint32 indexCount)
{
  const bool hasNormals = mesh.Normals.size() > 0;
  const bool hasTangents = mesh.Tangents.size() > 0;
  const bool hasTexoord[4] = 
  {
    mesh.Texcoords0.size() > 0,
    mesh.Texcoords1.size() > 0,
    mesh.Texcoords2.size() > 0,
    mesh.Texcoords3.size() > 0
  };

  uint32 vertexStride = sizeof(float) * 3;

  if (hasNormals)
    vertexStride += sizeof(float) * 3;
  if (hasTangents)
    vertexStride += sizeof(float) * 4;
  for (uint32 i = 0; i < 4; ++i)
  {
    if (hasTexoord[i])
      vertexStride += sizeof(float) * 2;
  }

  // create vertex accessor
  std::vector<VertexElement> vertexElements;
  vertexElements.push_back(m_RenderData->m_VertexAccess.addVertexElement(&m_RenderData->m_VertexBuffer, vertexStride, VET_FLOAT3, "POSITION", 0));

  if (hasNormals)
  {
    vertexElements.push_back(m_RenderData->m_VertexAccess.addVertexElement(&m_RenderData->m_VertexBuffer, vertexStride, VET_FLOAT3, "NORMAL", 0));
  }

  if (hasTangents)
  {
    vertexElements.push_back(m_RenderData->m_VertexAccess.addVertexElement(&m_RenderData->m_VertexBuffer, vertexStride, VET_FLOAT4, "TANGENT", 0));
  }

  for (uint32 i = 0; i < 4; ++i)
  {
    if (hasTexoord[i])
    {
      vertexElements.push_back(m_RenderData->m_VertexAccess.addVertexElement(&m_RenderData->m_VertexBuffer, vertexStride, VET_FLOAT2, "TEXCOORD", i));
    }
  }

  m_RenderData->m_VertexAccess.initDeclaration(vertexElements);

  // [erzeugen der vertex-/indexpuffer]
}


Hoffe du kannst dem ein paar Informationen entnehmen. :)
@D13_Dreinig

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

5

28.11.2014, 11:10

Eigentlich solltest Du als Programmierer verdammt genau wissen, wie Deine Vertexdaten aussehen. Wenn Du ein paar Kanäle nicht brauchst, kannst Du eine Vertex Declaration ohne sie erzeugen und fertig. Die Daten nur wegen diffuser Vorstellungen von "Flexibilität" auf x getrennte Buffer aufzuteilen ist eine Verschwendung von Rechenzeit.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

6

29.11.2014, 10:44

@David
danke für den Vorschlag. Ich bin gerade dabei so etwas in diese Richtung zu implementieren, aber ich werde mich nicht zurückhalten und mich auch an deinem Code etwas bedienen ;)

@Sch
Sicher hast du recht, aber mein Ziel ist Momentan nicht die Geschwindigkeit. Das Ziel ist es die Verwendung von DirectX so einfach wie möglich zu gestalten. :) Ist halt ein Hobby. Macht Spaß am Abend nach einem harten Tag sich noch ein paar Gedanken über Programmcode und Algorithmen zu machen.

Werbeanzeige