2016-03-25 11 views
2

So habe ich meine eigene Physik-Engine aus und wieder für eine Weile geschrieben und ich habe vor kurzem begonnen, DirectX-Rendering anstelle von Hardcoding in meinem Rendering mit OpenGL. Jetzt, am Ende, bin ich auf ein sehr seltsames Verhalten gestoßen, das ich nicht verstehen kann.Casting benutzerdefinierte Matrix zu float *

Um Matrices zu einem Shader passieren Dinge zu zeichnen, rufen Sie eine Funktion, die ein const float* und die typische Art und Weise geschieht dies zu tun, ist in einem D3DXMATRIX cast float* passieren. D3DXMATRIX und die gegossenen Operatoren sind als deklariert:

typedef struct _D3DMATRIX { 
    union { 
     struct { 
      float __11, _12, _13, _14; 
      float __21, _22, _23, _24; 
      float __31, _32, _33, _34; 
      float __41, _42, _43, _44; 
     }; 
     float m[4][4]; 
    }; 
} D3DMATRIX; 

Die beiden Umwandlungsoperatoren definiert werden in einer anderen Datei (D3DX10math.inl) als:

D3DX10INLINE 
D3DXMATRIX::operator FLOAT*() 
{ 
    return (FLOAT *) &_11; 
} 

D3DX10INLINE 
D3DXMATRIX::operator CONST FLOAT*() const 
{ 
    return (CONST FLOAT *) &_11; 
} 

typedef struct D3DXMATRIX : public D3DMATRIX 
{ 
    ... 
    operator FLOAT*(); 
    operator CONST FLOAT*() const; 
    .... 
} D3DXMATRIX, *LPD3DMATRIX; 

und D3DMATRIX als erklärt

Die Schlüsselwörter CONST und FLOAT sind in minwindef.h unddefiniert 210 ist in D3DX10.h wie folgt definiert:

#ifndef CONST 
#define CONST const 
#endif 
.... 
typedef float FLOAT; 
.... 
#define D3DX10INLINE __forceline 

Der Aufruf die Funktion I beschrieben ist einfach:

D3DXMATRIX m; 
foo->SetMatrix((float*)&m); 

Während mein gesamte Motor Ich habe meine eigene Matrix Klasse benutzen, und wenn ich versuche, übergeben Sie es in die obige Funktion anstelle einer D3DXMATRIX, sendet es falsche Daten. Meine Matrix Klasse ist (scheinbar) in der gleichen Weise wie D3DXMATRIX definiert, weigert sich jedoch, auf die gleiche Weise zu funktionieren. Hier meine Matrix-Klasse (oder die relevanten Teile):

class Matrix { 
    public: 
     .... 
     operator float*(); 
     operator const float*() const; 
     .... 
    private: 
     union { 
      struct { 
       float _00, _01, _02, _03; 
       float _10, _11, _12, _13; 
       float _20, _21, _22, _23; 
       float _30, _31, _32, _33; 
      }; 
      float m[4][4]; 
     } 
}; 

und die Funktionen definieren als:

__forceinline 
Matrix::operator float*() 
{ 
    return (float *) &_00; 
} 

__forceinline 
Matrix::operator const float*() const 
{ 
    return (const float *) &_00; 
} 

Ich habe versucht, die Definition der Operatoren in der CPP-Datei, in der Header-Datei, in der Klassendefinition, alle mit und ohne inline und __forceinline, aber nichts wird jemals funktionieren. Ich nehme an, ich könnte alle Daten in jeder meiner Matrizen zu einer D3DXMATRIX kopieren, aber das verschwendet eine Menge Zeit/Operationen und sollte irrelevant sein. Das größte Problem ist, dass ich für das Leben meiner Figur nicht herausfinden kann, warum sich alles so verhält. Ich kann unmöglich sehen warum.

sicher der Daten Um in die Funktion DirectX geleitet wird, habe ich so eine Testfunktion bis ich es debuggen können und sehen, was die genauen Werte in weitergegeben werden:

void Test(const float *a, const float *b) 
{ 
    bool result[16] = {false}; 
    float aa[16], bb[16]; 

    for(unsigned int i = 0; i < 16; ++i) 
    { 
     result[i] = a[i] == b[i]; 
     aa[i] = a[i]; 
     bb[i] = b[i]; 
    } 
} 

Zum Beispiel, wenn ich Pass in einem D3DXMATRIX mit den Werten 1-16 für jeden der 16 Schwimmer als ersten Parameter eine meiner Matrizen mit den gleichen Werten wie b dann aa1-16 ganz gut mit den Werten gefüllt werden, aber bb wird = {0.0, 1.875, 0.0, 2.0, 0.0, 2.125, 0.0, 2.5, 0.0, 2.315, 0.0, 2.375, 0.0, 2.4375, 0.0, 2.5}

Also ... hat jemand irgendwelche Ideen, warum sich dieser Code so verhält?

+0

Haben Sie andere Membervariablen in 'Matrix'? –

+0

@AntonSavin Nein, das ist es. – ArcRaizen

Antwort

1

Sie verwenden tatsächlich operator float* falsch.

D3DXMATRIX m; 
foo->SetMatrix((float*)&m); 

Hier konvertieren Sie die Adresse von m-float*. Dies ruft operator float nicht auf, es ist nur reinterpret_cast (und Compiler sollte eine Warnung darüber geben). Aber zum Glück für Sie D3DMATRIX enthält keine anderen Mitglieder und keine Polsterung am Anfang, so dass alles funktioniert.

Wenn Matrix andere Datenelemente vor dem _00 enthält oder nicht standard-layout ist, kann eine solche Konvertierung zu unbestimmten Ergebnissen führen.

So ist die Grundlinie ist, sollten Sie tun

foo->SetMatrix((float*)m); 

oder nur

foo->SetMatrix(m); 
+0

Es gibt keine anderen Datenelemente in meiner Matrix-Klasse und es gibt absolut keinen funktionalen Unterschied zwischen foo-> SetMatrix ((float *) & m), foo-> SetMatrix ((float *) m) und foo-> SetMatrix (m) überhaupt. – ArcRaizen

+0

@ArcRaizen Können Sie versuchen, 'static_sert > :: value'? –

+0

kommt wieder als wahr – ArcRaizen