HLSL Shader Column oder Row Vektoren?



  • Hallo zusammen
    Ich habe ein seltsames Phänomen in meinen HLSL Vertex Shaders und zwar muss ich bei dem mul Befehl zuerst die Matrix und dann den Vektor übergeben. Ich dachte jedoch Direct3D interpretiere Vektoren als Row-, nicht als Columnvektoren? Sollte dann aber nicht zuerst der Vektor und dann die Matrix kommen?

    Mfg Samuel



  • Naja genaugenommen interpretiert D3D deine Matrix gar nicht, das was du beschreibst ist lediglich die unter D3D gängige Konvention. Es hängt also ganz davon ab wie die Matrix aussieht die du an den Shader übergibst...



  • Wenn bei mul der Vektor der 1. Parameter ist, wird er als Zeilenvektor interpretiert, ansonsten als Spaltenvektor. Wenn du die Reihenfolge vertauschen willst, musst du also die Matrix transponieren, sprich ändere dein mul(M,v) in mul(v,transpose(M))



  • Ja das ist mir schon alles klar, die Frage ist, ist es normal, dass ich die Matrix zuerst angeben muss, weil ich in sämtlichen Samples sehe, dass der Vektor als erster Parameter übergeben wird. Ich habe mir bereits überlegt, ob ich die Matrizenwerte falsch interpretiert habe? Aber m._24 bedeutet doch schon 2.Zeile, 4. Spalte oder nicht?

    Was mich auch verwundert ist, dass die Matrix Funktionen der Direct3D Extension Libraries einwandfrei funktionieren, die sollten doch dann auch keine vernünftigen Resultate liefen, wenn ich meine Matrix Klasse falsch aufgebaut hätte?



  • Ishildur schrieb:

    Aber m._24 bedeutet doch schon 2.Zeile, 4. Spalte oder nicht?

    Ja, zumindest im Fall der D3DXMATRIX Klasse. Schreibst du selber Werte direkt in die Matrix? Wenn ja was für welche und wohin?

    Ishildur schrieb:

    Was mich auch verwundert ist, dass die Matrix Funktionen der Direct3D Extension Libraries einwandfrei funktionieren, die sollten doch dann auch keine vernünftigen Resultate liefen, wenn ich meine Matrix Klasse falsch aufgebaut hätte?

    Versteh ich das richtig, du hast eine eigene Matrixklasse? Wie sieht die aus?



  • // ************************************** struct "Matrix" *************************************
    // This structure represents a 4x4 row major matrix.
    // Author: Samuel Lörtscher
    // ********************************************************************************************
    struct Matrix{
     // ---------------------------------- public static members ----------------------------------
     static Matrix Identity;
     // -------------------------------------------------------------------------------------------
    
     // ---------------------------------- public dynamic members ---------------------------------
     float32 _11,_12,_13,_14; // first row
     float32 _21,_22,_23,_24; // second row
     float32 _31,_32,_33,_34; // third row
     float32 _41,_42,_43,_44; // fourth row
     // -------------------------------------------------------------------------------------------
    
     // ---------------------------------------- operators ----------------------------------------
     bool    operator==(Matrix &Matrix)   const;
     Matrix  operator*(const Matrix &M)   const;
     Vector3 operator*(const Vector3 &V)  const;
     Matrix  operator*=(float32 Scalar);
     Matrix  operator*=(const Matrix &M);
     // -------------------------------------------------------------------------------------------
    
     // ---------------------------------- public static methods ----------------------------------
     static Matrix LookAt(Vector3 &Eye,Vector3 &LookAt,Vector3 &At);
     static Matrix ProjectionFOV(float32 Fov,float32 Aspect,float32 Near,float32 Far);
     static Matrix Translation(float32 X,float32 Y,float32 Z);
     static Matrix Scaling(float32 X,float32 Y,float32 Z);
     static Matrix RotationX(float32 X);
     static Matrix RotationY(float32 Y);
     static Matrix RotationZ(float32 Z);
     static Matrix RotationAxis(Vector3 &Axis,float32 Angle);
     // -------------------------------------------------------------------------------------------
    
     // ---------------------------------- public dynamic methods ---------------------------------
     Vector3 GetFront(void) const;
     Vector3 GetRight(void) const;
     Vector3 GetUp(void)    const;
     // -------------------------------------------------------------------------------------------
    };
    // ********************************************************************************************
    

    Ist natürlich alles andere als vollständig, aber ich erweitere sie, wann immer ich eine zusätzliche Funktionalität benötige 😉



  • Ok, also die Werte stehen ja richtigerweise in row-major Form im Speicher.
    Dann dürften vermutlich deine Matrixfunktionen falsch arbeiten. Du hast die Formeln für RotationX etc. nicht zufällig aus der Wikipedia? (Die Matritzen dort sind nämlich für M * v und nicht v * M)



  • @dot

    Du hast die Formeln für RotationX etc. nicht zufällig aus der Wikipedia?

    Hehe, also ich schreibe grundsätzlich keine Formeln einfach ab, sondern erarbeite diese selbst und vergleiche sie schliesslich mit verfügbaren Referenzformeln, also NEIN :p

    Dann dürften vermutlich deine Matrixfunktionen falsch arbeiten.

    Ja das hatte ich natürlich zunächst auch vermutet, daher habe ich auch die Funktionen der Direct3D Extension Library D3DXMatrix... auf meine Matrix Klasse losgelassen, welche allerdings exakt dieselben Matrizen produzierten...

    Hier ist sonst mal der Code zweier dieser Funktionen:

    // --------------------------------- static method "RotationX" --------------------------------
    // This static method computes and returns a matrix representing the rotation with the angle
    // A around the basis vector X.
    // Author: Samuel Lörtscher
    // --------------------------------------------------------------------------------------------
    Matrix Matrix::RotationX(float32 X){
     // declare and init local variables
     float32 s = sinf(X);
     float32 c = cosf(X);
    
     // setup and return an y rotation matrix as required
     Matrix m = Matrix::Identity;
     m._22 =  c;
     m._23 =  s;
     m._32 = -s;
     m._33 =  c;
     return m;
    }
    // --------------------------------------------------------------------------------------------
    
    // ------------------------------- static method "RotationAxis" -------------------------------
    // This static method computes and returns a matrix representing the rotation with the angle
    // A around an axis represented by the vector V. In debug mode an exception is thrown if the
    // parametric Vector is a null Vector (magnitude of 0.0f).
    // Author: Samuel Lörtscher
    // --------------------------------------------------------------------------------------------
    Matrix Matrix::RotationAxis(Vector3 &V,float32 A){
     // assert that the parametric Vector isn't a null vector
     Assert(V != Vector3::Zero,ArgumentException,"V darf kein 0-Vektor sein");
    
     // declare and init local variables
     Vector3 v  = Vector3::Normalize(V);
     float32 s  = sinf(A), c  = cosf(A), ic = 1.0f-c;
     float32 x  = V.X, y  = V.Y, z  = V.Z;
    
     // setup and return an axis rotation matrix as required
     Matrix  m;
     m._11 = x*x*ic+c;     m._12 = x*y*ic+z*s;   m._13 = x*z*ic-y*s;   m._14 = 0.0f;
     m._21 = x*y*ic-z*s;   m._22 = y*y*ic+c;     m._23 = y*z*ic+x*s;   m._24 = 0.0f;
     m._31 = x*z*ic+y*s;   m._32 = y*z*ic-x*s;   m._33 = z*z*ic+c;     m._34 = 0.0f;
     m._41 = 0.0f;         m._42 = 0.0f;         m._43 = 0.0f;         m._44 = 1.0f;
     return m; 
    }
    // --------------------------------------------------------------------------------------------
    

    Siehst du darin einen Fehler?



  • Ishildur schrieb:

    Ja das hatte ich natürlich zunächst auch vermutet, daher habe ich auch die Funktionen der Direct3D Extension Library D3DXMatrix... auf meine Matrix Klasse losgelassen, welche allerdings exakt dieselben Matrizen produzierten...

    Hm, Ok... Dann die nächste Frage, wie übergibst du die Matrix an den Shader und wie kompilierst du den Shader (es gibt nämlich ein Compilerflag dass zwischen row-major und column-major umschaltet).

    Ishildur schrieb:

    Hier ist sonst mal der Code zweier dieser Funktionen:
    [...]
    Siehst du darin einen Fehler?

    Die erste schaut zumindest mal gut aus, die zweite spar ich mir jetzt da du ja sagst dass die D3DX Funktionen identische Resultate liefern...



  • // setup the vertex shader
     Device->SetVertexShader(this->vsMsh->GetShader());
     Device->SetVertexShaderConstantF(0,reinterpret_cast<float32*>(&mxWvp),4);
     Device->SetVertexShaderConstantF(4,reinterpret_cast<float32*>(&this->mxLcs),4);
    

    Die Shaders kompiliere ich automatisch mit einer zusätzlichen Build Rule:

    "$(DXSDK_DIR)Utilities\bin\x86\fxc.exe" /T vs_3_0 /nologo /Fo$(InputDir)Resources\Shaders\$(InputName).vso [inputs]
    


  • Ah ok, wenn du SetVertexShaderConstant*() verwendest musst du die Matrix vorher transponieren da die in den Constant Registern in column-major Form liegen muss (vector * Matrix wird in 4 Punktprodukte mit c0, c1, c2, c3 umgesetzt...)
    Das erklärt natürlich alles.



  • Ok alles kla, danke vielmals 🙂



  • Noch etwas. Kann ich auch einfach alles so lassen? Dann spare ich mir ja die zahllosen Matrizentransponierungen in jedem Frame. Ist ja nicht weiter schlimm, die Matrizen als ersten Parameter anstatt als zweiten zu übergeben (solange ich weiss, warum das so ist), oder könnten da irgendwann Probleme mit auftreten?



  • Nein das sollte kein Probleme geben wenn du beim zusammenbauen deiner Matritzen dran denkst (Multiplikationsreihenfolge umdrehen etc.)


Anmelden zum Antworten