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

H5::

Treue Seele

Beiträge: 368

Wohnort: Kiel

  • Private Nachricht senden

31

16.03.2013, 18:42

In der msdn heißt es: VOID* pointer to a memory buffer containing the returned vertex data

Was versuchst du denn mit dem Aufruf eigentlich zu erreichen? Bzw. wie hast du die Methode denn verstanden? Eventuell kann man dir dann ein bisschen besser helfen.
:love: := Go;

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

32

17.03.2013, 11:12

Ich glaube hier herrscht ein Fehler beim Verstaendnis, was genau ein Pointer ist und wie er im Zusammenhang mit Lock verwendet wird.

Erstmal ist ein void* oder int* oder auch irgend ein classBla* einfach nur eine Zahl. Zum Beispiel die Zahl 73824. Der Pointer sagt aus, das an der Speicherstelle mit der Nummer 73824 ein Objekt von ein bestimmtem Typ oder eben auch eines unbestimmten Typs (void*) liegt. Wenn die Zahl eine 0 ist, hat man einen Nullpointer. Wenn nun die Zahl 73824 abgespeichert wird, so steht auch diese irgendwo im Speicher. Sie koennte zum Beispiel in der Speicherstelle mit der Nummer 90008 stehen. Betrachten wir 73824 als Datum vom Typ int, dann ist 90008 also ein int*, naemlich die Speicherstelle eines ints. Betrachten wir 73824 aber wie hier als als void*, so ist 90008 also ein (void*)* kurz void**. 90008 ist nun also ein Pointer auf einen Pointer, also ein void**, die Speicherstelle an der eine weiter Speicherstelle abgelegt ist. Und genau das brauch ich beim Lock, ich gebe dem die 90008 und er aendert dann die 73824, die dort gespeichert ist, auf eine andere Speicherstelle, sagen wir 1000000. Die 73824 geht dabei verloren. Wenn ich dann meine Zahl nehme, die bei 90008 gespeichert ist (das ist der Pointer vom Anfang) und damit Speicher adressiere, lese/ schreibe ich dann also im Speicher an der Stelle 1000000. Was genau dort ist und wieviel Speicher dort lesbar/ schreibbar ist, haengt vom dem Lock ab. Im Normalfall, tut man nur Daten in die Grafikkarte schreiben, d.h. dort ist dann Speicher, in dem "nichts" steht (d.h. in den Speicherstellen steht einfach irgendwas, was frueher mal hingeschrieben wurde) und dort soll ich nun meine Daten reinschreiben, die zur Grafikkarte sollen.

Man kann dem Lock daher nicht einfach irgendeine Speicherstelle geben, die zu einem std::vector gehoert. Der Lock schreibt dann irgendwo irgendwas in den std::vector, wenn der Vector sich z.b. mit der 73824 die Anzahl seiner Elemente abgelegt hat, so ist diese Information dann verloren. Damit kommt dieser im Normalfall nicht zurecht (was man in einen Vektor schreibt soll ja immer ueber dessen Funktionen gehen) und das endet im besten Fall in einem Absturz oder schlimmer in irgendwelchen nicht zuordenbaren Folgefehlern.

Zum Lesen von obj Dateien muss ich noch sagen, das dort eigentlich nicht direkt Vertices drin stehen. Ein Vertex besteht ja normalerweise aus Informationen wie Position, Normale, Farbe etc. Im obj ist aber nur eine Liste von Positionen. Dann eine Liste von Normalen. etc. Je nach dem was man exportiert hat. Bei der Definition der Flaechen werden dann erst richtige Vertices aus den Listen. Daher macht ein Ansatz mit einem Zwischenbuffer schon Sinn, ich wuesste auch nicht wie man das einfacher machen soll. Da sowas bei grossen Modellen mit Millionen Dreiecken langsam ist, hab ich mir in meinem obj Reader fuer sowas auch ein Cache gebaut, der die sortierten Vertexes haelt.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

33

17.03.2013, 11:16

Für das Problem mit den Vertices verwend ich persönlich immer eine Hashtable (std::unordered_map).

lfp

Frischling

  • »lfp« ist der Autor dieses Themas
  • Private Nachricht senden

34

17.03.2013, 12:09

Man kann dem Lock daher nicht einfach irgendeine Speicherstelle geben, die zu einem std::vector gehoert. Der Lock schreibt dann irgendwo irgendwas in den std::vector, wenn der Vector sich z.b. mit der 73824 die Anzahl seiner Elemente abgelegt hat, so ist diese Information dann verloren. Damit kommt dieser im Normalfall nicht zurecht (was man in einen Vektor schreibt soll ja immer ueber dessen Funktionen gehen) und das endet im besten Fall in einem Absturz oder schlimmer in irgendwelchen nicht zuordenbaren Folgefehlern.

ok, das hab ich verstanden. Die vector-class verwaltet sich selbst, und dann sage ich DirectX es darf sich am speicher der vector-class bedienen. Das macht also die Fehler.

Aber zu wissen wie es nicht geht bringt mich leider nicht zur Lösung des Problems, sondern führt mich nur zu neuen Fragen:

Wie weise ich dem VertexBuffer die Werte aus dem vector zu, ohne die vector class selbst zu "beschädigen"?
Macht es dann überhaupt noch Sinn die vector-class zum Füllen eines VertexBuffers zu verwenden?

H5::

Treue Seele

Beiträge: 368

Wohnort: Kiel

  • Private Nachricht senden

35

17.03.2013, 12:50

Man kann dem Lock daher nicht einfach irgendeine Speicherstelle geben, die zu einem std::vector gehoert. Der Lock schreibt dann irgendwo irgendwas in den std::vector, wenn der Vector sich z.b. mit der 73824 die Anzahl seiner Elemente abgelegt hat, so ist diese Information dann verloren. Damit kommt dieser im Normalfall nicht zurecht (was man in einen Vektor schreibt soll ja immer ueber dessen Funktionen gehen) und das endet im besten Fall in einem Absturz oder schlimmer in irgendwelchen nicht zuordenbaren Folgefehlern.
Auf die Gefahr hin dich miss verstanden zu haben, ich glaube aber es ist nicht ganz richtig was du geschrieben hast. Der Zeiger den man durch die data( ) Methode erhalten hat ist ein valides Array in das man schreiben und von dem man lesen kann. Im Aufruf der Lock( ) Methode hat es dennoch nicht viel verloren, zumal in dem Beispiel der std::vector noch eine Größe von 0 hat und es wahrscheinlich daher zum Fehler kommt. Die data( ) Methode bezieht sich aber auf C++11, und wird nicht überall unterstützt.
Dass man die Methoden benutzen sollte ist richtig, aber besonders die data( ) Methode ist eine gute Hilfe die C Arrays komplett aus seinem Code zu verbannen.

Zum Thema Vector:
Die Daten bekommst du in den std::vector mit der push_back( ) Methode wenn du die Daten aus der Datei liest. Oder wenn dein std::vector die passende Größe hat und du in sein Array schreiben willst mit dem Zeiger den die data( ) Methode dir liefert.

(Die Lock( ) Methode will dir aber im 3. Parameter selbst etwas zurückgeben. Deswegen das [out] in der Synopsis. Sie verändert den Wert des ihr übergebenen Zeigers. Deswegen der Zeiger auf einen Zeiger.)

std::vector::data

Ich möchte aber anmerken, dass ich noch nie mit DirectX9 gearbeitet habe. Ich kann mich nur auf die MSDN und C++ allgemein stützen. Also muss nicht alles richtig sein was ich so schnell daraus gelesen haben.

Edit: Auf deinen Code bezogen.
Du musst da noch gar kein Lock und Unlock aufrufen. Wie gesagt mit DirectX 9 habe ich noch nie gearbeitet. Aber wenn ich das richtig verstanden habe dienen die methoden nur zum verändern eines vorhandenen Buffers (Der sich schon z.B. im GPU Speicher befindet). Um einen Vertex Buffer zu erzeugen benötigst du:
IDirect3DDevice9::CreateVertexBuffer
Vertex Buffers (Direct3D 9)

Edit2:
Wenn du den std::vector befüllt hast, erst dann must du Lock aufrufen (wie im Link beschrieben) und die Daten vom Vector in den von dir erstellten Buffer (Zeiger ist pVertices im Beispiel) kopieren.
Accessing the Contents of a Vertex Buffer (Direct3D 9)
:love: := Go;

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »H5::« (17.03.2013, 13:20)


lfp

Frischling

  • »lfp« ist der Autor dieses Themas
  • Private Nachricht senden

36

17.03.2013, 13:35

hmmm... ok... nur mag mein Compiler den im Beispiel verwendeten Cast nicht.
error C2664: 'IDirect3DVertexBuffer9::Lock': Konvertierung des Parameters 3 von 'BYTE **' in 'void **' nicht möglich

Ohne Cast wird mal wieder nichts gezeichnet...


Also bei mir sieht das jetzt so aus:

C-/C++-Quelltext

1
2
3
4
5
VOID* pVertices;

VertexBuffer->Lock(0, sizeof(Vertices_sortiert_VECTOR), (VOID**)&pVertices, 0 );
memcpy(pVertices, &Vertices_sortiert_VECTOR, sizeof(Vertices_sortiert_VECTOR));
VertexBuffer->Unlock();


oder mit vector::data() :

C-/C++-Quelltext

1
2
3
4
5
VOID* pVertices;

VertexBuffer->Lock(0, sizeof(Vertices_sortiert_VECTOR.data()), (VOID**)&pVertices, 0 );
memcpy(pVertices, Vertices_sortiert_VECTOR.data(), sizeof(Vertices_sortiert_VECTOR.data()));
VertexBuffer->Unlock();


Bringt aber beides nichts...

Ich hab übrigens schon überprüft, dass Vertices_sortiert_VECTOR alle 36 Punkte für den zu zeichnenden Würfel enthält und dass die Methoden zum Zeichnen funktionieren, wenn ich ihnen in dem VertexBuffer statt dem vector einen C-Array gebe

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »lfp« (17.03.2013, 13:48)


H5::

Treue Seele

Beiträge: 368

Wohnort: Kiel

  • Private Nachricht senden

37

17.03.2013, 13:46

Ich habe den Code jetzt blind erstellt, ob er so richtig ist weiß ich nicht. Aber eventuell hilft er ja.

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
void letstestsomevectorclass(LPDIRECT3DDEVICE9 D3DDevice){
    // Vertices laden
    std::vector <VERTEX> testvector;
    VERTEX testvertex;

    testvertex.x = 5;
    testvertex.y = 5;
    testvertex.z = 1;
    testvertex.Color = RGB(100, 100, 100);
    testvector.push_back(testvertex);

    testvertex.x = 0;
    testvertex.y = 0;
    testvertex.z = 1;
    testvertex.Color = RGB(100, 100, 100);
    testvector.push_back(testvertex);

    testvertex.x = 10;
    testvertex.y = 0;
    testvertex.z = 1;
    testvertex.Color = RGB(100, 100, 100);
    testvector.push_back(testvertex);

    // VertexBuffer erstellen.
    LPDIRECT3DVERTEXBUFFER9 testVertexBuffer;
    auto MyFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
    D3DDevice->CreateVertexBuffer(testvector.size( )*sizeof(VERTEX), 0, MyFVF, D3DPOOL_MANAGED, &testVertexBuffer, nullptr);

    BYTE* buffer;
    testVertexBuffer->Lock(0, testvector.size( )*sizeof(VERTEX), reinterpret_cast<void**>(&buffer), D3DLOCK_NOSYSLOCK);
    std::copy( testvector.begin( ), testvector.end( ), buffer );
    testVertexBuffer->Unlock();
}
:love: := Go;

Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von »H5::« (17.03.2013, 14:02)


lfp

Frischling

  • »lfp« ist der Autor dieses Themas
  • Private Nachricht senden

38

17.03.2013, 14:04

Hilft leider nicht viel...
Warum schreibst du mit std::copy direkt in den VertexBuffer?

Die Methode VertexBuffer->Unlock() schreibt doch schon in den VertexBuffer...oder? Mein Compiler gibt auf jeden Fall einige Fehler bei dem Code aus...

Du benutzt wohl ne andere Version von DirectX?


Trotztdem danke...

Ich bin mir ziemlich sicher dass David das Problem leicht lösen könnte...
Das ist ja vielleicht schon etwas in Vergessenheit geraten, aber eigentlich brauch ich die vector class nicht. Ich möchte nur einen VertexBuffer mit einem Haufen vertices füllen.
Wie ich das mache ist mir dabei eigentlich vorerst egal.

H5::

Treue Seele

Beiträge: 368

Wohnort: Kiel

  • Private Nachricht senden

39

17.03.2013, 14:14

Warum schreibst du mit std::copy direkt in den VertexBuffer?
Ja, da hatte ich mich vertan, aber hatte ich schon geändert.

Die Methode VertexBuffer->Unlock() schreibt doch schon in den VertexBuffer...
Unlock schreibt den VertexBuffer glaube ich in den Videospeicher.

Du benutzt wohl ne andere Version von DirectX?
Ja, Direct3D 11. Vorher hatte ich mich mit dem Thema Visualisierung nicht befasst.
:love: := Go;

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

40

17.03.2013, 16:46

Auf die Gefahr hin dich miss verstanden zu haben, ich glaube aber es ist nicht ganz richtig was du geschrieben hast. Der Zeiger den man durch die data( ) Methode erhalten hat ist ein valides Array in das man schreiben und von dem man lesen kann.
Ich habe mich nicht speziell auf die data Methode bezogen. Aber es gibt nur 3 Moeglichkeiten, wie ich data() und lock benutzen koennte. Entweder ich uebergebe den Pointer, den Data liefert an lock. Dann wird die Adresse, an der Lock die Daten des Buffers erwartet an den Anfang geschrieben und loescht die Daten dort (oder das Array kann nicht soviel Daten halten, und es passiert schlimmeres). Das waere schonmal schlecht. Oder ich uebergebe Lock die Adresse, an der ein vector seinen data() Pointer speichert, so das vec.data() nun diese Adresse liefert. Das waere extrem schlecht. Oder ich kopiere den Rueckgabewert von vec.data() erst in eine Variable und geben dann die Adresse dieser Variable an lock. Lock ueberschreibt dann diese Adresse mit einer anderen. Das waere jetzt nicht schlecht, aber die Variable haette jetzt mit dem Vector auch nichts mehr zu tun und man muesste sich fragen, was der Sinn dieser Aktion sein soll.

Ich persoenlich caste den die Adresse die Lock mir in die Variable schreibt immer zum Typ meiner Vertices und kann die dann dort bequem reinschreiben, etwa so:

C-/C++-Quelltext

1
2
SVertex* pData= (SVertex*)Buffer;
pData[0].m_x= 3.0f;


Hier sollte muss man aber teilweise aufpassen, das man nicht querbeet im Speicher rumschreibt. Je nachdem wie der Buffer gemapped ist, kann das lahm sein.

Werbeanzeige