2009-03-11 10 views
8

Okay, das ist etwas, das eine einfache Matrixfrage sein sollte, aber mein Verständnis von Matrizen ist etwas begrenzt. Hier ist das Szenario: Ich habe ein 1px mal 1px Sprite, das ich um einen Betrag x und y skalieren möchte (verschiedene Beträge auf jeder Seite), und dann möchte ich das Sprite um einen Winkel drehen, und dann möchte ich es können positioniere das Ganze genau (von oben links oder von der Mitte aus, macht für mich keinen Unterschied).Wie kann man eine Matrix in C# gleichzeitig drehen, skalieren und übersetzen?

Bisher ist mein Code vage nahe, aber es neigt dazu, durch eine zufällige Menge in Abhängigkeit vom Winkel ab, in dem ich passiere

Ich würde denken, dass dies würde es tun.

 Point center = new Point(50, 50); 
     float width = 60; 
     float height = 100; 
     float angle = 0.5; 
     Vector3 axis = new Vector3(center.X, center.Y, 0); 
     axis.Normalize(); 
     Matrix m = Matrix.Scaling(width, height, 0) * 
      Matrix.RotationAxis(axis, angle) * 
      Matrix.Translation(center.X, center.Y, 0); 

Aber es neigt dazu, den Umfang der gedrehten Linie nach unten zu verkleinern, obwohl ich denke, dass es so richtig positioniert ist.

Ich habe auch schon versucht, diese:

Matrix m = Matrix.Transformation2D(new Vector2(center.X, center.Y), 0f, 
     new Vector2(width, height), new Vector2(center.X, center.Y), 
     angle, Vector2.Zero); 

Die Linie genau richtig aussieht, mit der exakt richtigen Größe und Form, aber ich kann es nicht richtig überhaupt positionieren. Wenn ich den Übersetzungsvektor am Ende des obigen Aufrufs verwende, oder wenn ich eine Position mit Sprite.Draw einstelle, funktioniert beides nicht richtig.

Dies ist alles in SlimDX. Was mache ich falsch?

Antwort

12

Ich ging gerade durch den Schmerz des Lernens Matrix Transformation, aber mit XNA.

fand ich thesearticlestobevery in Verständnis hilfreich, was passiert. Die Methodenaufrufe sind in XNA sehr ähnlich und die Theorie dahinter sollte auch für SlimDX gelten.

Von einem Blick auf Ihren Code, ich denke, Sie sollten am Anfang übersetzen, um den Ursprung, und dann wieder am Ende, auf die endgültige Position zu übersetzen, obwohl ich noch ein bisschen ein Neuling dabei bin auch.

Die Reihenfolge ich es tun würde ist:

  • zu Herkunft Übersetzen
  • Skala
  • Drehen
  • an den gewünschten Ort Übersetzen

Der Grund, auf den Ursprung für die Übersetzung erste ist, dass Umdrehungen vom Ursprung basieren. Um also etwas um einen bestimmten Punkt zu drehen, platzieren Sie diesen Punkt auf den Ursprung, bevor Sie ihn drehen.

+1

Hmm ... das scheint sehr nah zu sein. Das Übersetzen in Ursprung, Skalieren und Drehen funktioniert großartig, aber wenn ich dann versuche, den gewünschten Ort zu übersetzen, wirkt es wirklich seltsam - ich verändere das x-Koordinatensystem und es bewegt sich sowohl in x als auch in y. Ich denke, dass es im gedrehten Raum übersetzt ... – x4000

+0

Eine andere Sache, die mir noch nicht klar ist, ist, wie man zum Ursprung übersetzt. Ich habe zwei Punkte plus ein Drittel, das in der Mitte von ihnen ist. Ich habe das Zentrum in den Ursprung übersetzt, aber sollte ich anders übersetzen? – x4000

+1

Anstatt zurück zu übersetzen, wo Sie wollen, können Sie einfach die Position ändern, wo Sie zeichnen? –

1

Was Sie tun müssen, ist jede Transformation Schritt für Schritt durchzuführen. Zeichnen Sie zuerst die Skalierung. Ist es da, wo du es erwartest? Dann werfen Sie das Drehen und dann das Übersetzen ein. Dies wird helfen, falsche Annahmen aufzudecken.

Sie können auch temporäre Linien zeichnen, um die Koordinaten zu bestimmen. Zum Beispiel, wenn Sie Ihre Dehnung und Rotation machen und erwarten, dass Ihr Endpunkt bei 0,0 liegt. Das Zeichnen einer anderen Linie mit einem Endpunkt bei 0,0 wird als eine doppelte Überprüfung dienen, um zu sehen, ob das wirklich der Fall ist.

Für Ihr spezifisches Problem kann das Problem mit der Rotation sein. Nachdem Sie skaliert und gedreht haben, befindet sich die Linie jetzt in der Mitte, was zu Problemen bei der Übersetzung führt.

Die allgemeine Lösung besteht darin, die Linie zurück zum Ursprung zu bewegen, um die Form oder Ausrichtung zu ändern. Danach, weil Sie an einem bekannten guten Ort sind, können Sie zu Ihrem endgültigen Ziel übersetzen.

Reaktion auf die Kommentare

Wenn Übersetzung ist ein Problem, und Sie verändern die Koordinatensystem dann müssen Sie eine Konvertierungsfunktion schreiben, zwischen dem alten und dem neuen System zu konvertieren.

Zum Beispiel, wenn Sie 45 Grad drehen. Vor der Drehung können Sie um 0,1 um 1 Zoll nach oben verschieben. Nach der Drehung müssen Sie um ca. -70707, .070707 um 1 Zoll relativ zum ursprünglichen Koordinatensystem verschieben.

+0

Ich habe schon versucht, jeden Teil separat zu machen - das hätte ich erwähnen sollen. Skalierung und Übersetzung funktionieren einwandfrei. Aber wie du sagst, wenn ich Rotation hinzufüge, geht es aus. Und ja, ich muss Icons an den Referenzpunkten haben, damit ich sehen kann, wie nah ich bin. Ich werde jetzt den Ausgleich versuchen. – x4000

+0

Rotation versagt, da sie um den Ursprung gedreht wird. –

+0

Ich habe jetzt versucht, zurück zum Ursprung zu gehen und dann wieder dorthin zu übersetzen, wo ich es möchte. Das scheint nah zu sein, aber die Übersetzung ist aus, weil es sich scheinbar innerhalb des gedrehten Koordinatenraums verschiebt. – x4000

1

Drehen Sie sich um die richtige Achse? Ich bin ein Neuling im Matrix-Zeug, aber es scheint mir, dass, da das Sprite im x, y-Raum existiert, die Rotationsachse die Z-Achse sein sollte - d. H. (0,0,1).

+0

Hmm, das ist ein guter Punkt, aber meine Drehung scheint gut zu funktionieren, wenn ich nur die Skalierung mache und es - das Problem kommt, wenn ich dann versuche, es auch zu positionieren. Ich kann zwei von diesen drei Arbeiten machen, aber es gibt etwas, was ich falsch mache, wenn ich alles zusammenfasse! – x4000

+0

Hey, guter Fang mit der Z-Achse - mit meinem ersten Beispiel oben ist das ziemlich relevant. – x4000

3

Okay, das funktioniert jetzt. Hier ist mein Arbeits-Code für diese, falls jemand anderes braucht es:

Point sourceLoc = new Point (50, 50); 
    float length = 60; 
    float thickness = 2; 
    float angle = 0.5; 
    Matrix m = Matrix.Scaling(length, thickness, 0) * 
      Matrix.RotationZ(angle) * 
      Matrix.Translation(sourceLoc.X, sourceLoc.Y, 0); 
    sprite.Transform = m; 

    sprite.Draw(this.tx, Vector3.Zero, Vector3.Zero, Color.Red); 

Dies wird eine abgewinkelte Linie von den gewählten Länge, mit einer Dicke gleich den gewählten Dicke zeichnen (die Textur der Annahme ist ein 1x1-Pixel-Weiß-Bild). Der Quellort ist der Ort, an dem die Linie emittiert, mit dem von Ihnen angegebenen Winkel (im Bogenmaß). Wenn Sie also bei Null beginnen und um etwa 0,1 inkrementieren, bis Sie 2PI drücken und dann auf 0 zurücksetzen, wird sich eine Linie um ein Zentrum drehen, wie bei einer Zeigeruhr oder einem Radar-Sweep. Das habe ich gesucht - Danke an alle, die dazu beigetragen haben!