C#で行列を一度に回転、拡大縮小、および変換する方法は?
-
10-07-2019 - |
質問
さて、これは単純なマトリックスの質問であるべきですが、マトリックスの私の理解はいくらか制限されています。ここにシナリオがあります:私は1xx 1pxのスプライトをxとyの量(各側で異なる量)でスケーリングしたいのですが、そのスプライトをある角度で回転させたいのですが、全体を正確に配置します(左上または中央から、私には違いはありません)。
これまでのところ私のコードは漠然と近いですが、私が渡す角度に応じてランダムな量だけオフになる傾向があります。
これでうまくいくと思います:
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 );
しかし、正しい位置に配置していると思いますが、回転した線のスケールを小さくする傾向があります。
これも試しました:
Matrix m = Matrix.Transformation2D( new Vector2( center.X, center.Y ), 0f,
new Vector2( width, height ), new Vector2( center.X, center.Y ),
angle, Vector2.Zero );
線は正確に正しいサイズと形状で正確に見えますが、正しく配置できません。上記の呼び出しの最後に移動ベクトルを使用する場合、またはSprite.Drawを使用して位置を設定する場合、どちらも正しく機能しません。
これはすべてSlimDXにあります。私は何を間違えていますか?
解決
XNAを使用して、マトリックス変換の学習に苦労しました。
これら 記事 to be 非常に何が起こるかを理解するのに役立ちます。メソッド呼び出しはXNAでも非常によく似ており、その背後にある理論はすべて、SlimDXを使用しても当てはまります。
コードをちらっと見て、最初から原点に翻訳し、最後に再び最終位置に翻訳する必要があると思いますが、私はまだ初心者ですまあ。
私が行う順序は次のとおりです。
- 原産地への翻訳
- スケール
- 回転
- 目的の場所に翻訳する
最初に原点に変換する理由は、回転が原点に基づいているためです。したがって、特定の点を中心に何かを回転させるには、回転する前にその点を原点に置きます。
他のヒント
さて、これは現在機能しています。他の誰かがそれを必要とする場合のために、これは私の作業コードです:
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 );
これにより、選択した太さに等しい太さで、選択した長さの斜めの線が描画されます(テクスチャが1x1ピクセルの白い画像であると仮定)。ソースの場所は、指定した角度(ラジアン単位)で、線が放射される場所です。したがって、ゼロから開始して2PIに達するまで0.1のように増分し、その後0にリセットすると、時計の針やレーダースイープのように中心の周りを回転する線ができます。これは私が探していたものです-貢献してくれたすべての人に感謝します!
正しい軸を中心に回転していますか?私はマトリックスの初心者ですが、スプライトはx、y空間に存在するため、回転軸はZ軸(つまり、(0,0,1))である必要があります。
する必要があるのは、各変換を一度に1ステップずつ実行することです。最初にスケーリングを行います。あなたが期待する場所ですか?次に、回転をスローし、次に翻訳します。これは、誤った仮定を明らかにするのに役立ちます。
一時的な線を描画して、座標がどこにあるかを把握することもできます。たとえば、ストレッチと回転を行い、終点が0,0になると予想する場合。 1つのエンドポイントが0,0である別の線を描くと、本当にそうなのかを確認するための二重チェックとして機能します。
特定の問題では、回転に問題がある可能性があります。スケーリングして回転した後、線は中心から外れて、翻訳中に問題が発生します。
一般的な解決策は、線を原点に戻し、形状または方向を変更する操作を行うことです。その後、既知の良好な場所にいるため、最終目的地に翻訳できます。
コメントへの返信
変換が問題であり、座標系を変換する場合、古いシステムと新しいシステムの間で変換する変換関数を記述する必要があります。
たとえば、45度回転している場合。回転の前に、0,1だけ平行移動して1インチ上に移動できます。回転後、元の座標系に対して1インチ上に移動するには、おおよそ-.70707、.070707だけ平行移動する必要があります。