Alexa、Cohen-Or、および Levin による2000 年の論文As-rigid-as-possible shape interpolationで説明されているように、クォータニオンを使用して 2 つの三角形間の形状補間を実装しようとしています。
三角形 1 に点 A、B、C があり、三角形 2 に点 M、N、O があるとします。対応する 2 つの行列 (それぞれ T1 と T2) は次のとおりです。
T1 = {A.x, B.x, C.x},
{A.y, B.y, C.y},
{1, 1, 1 }
T2 = {M.x, N.x, N.x},
{M.y, N.y, N.y},
{1, 1, 1 }
次に、T1 の逆数を取り、それを T2 で乗算して特異値分解を実行し、行列 SVD を取得して、回転行列とスケーリング行列を見つけます。
Eigen::Matrix3f A = T1.inverse().eval() * T2;
Eigen::JacobiSVD<MatrixXf> SVD;
SVD.compute(A, ComputeFullU | ComputeFullV);
Eigen::MatrixXf D = SVD.singularValues().asDiagonal().toDenseMatrix();
Eigen::Matrix3f rotationMatrix = SVD.MatrixU() * SVD.MatrixV();
Eigen::Matrix3f sMatrix = SVD.MatrixV() * D * SVD.MatrixV().transpose();
Eigen::Quaternionf quat = rotationMatrix;
次に、このクォータニオンと sMatrix を補間に使用します。注: タイマーは 0.0f で開始し、1.0f に達するまで 0.0001f (いくつかの小さな定数) ずつ増加します。変換をアニメーション化します。
Eigen::MatrixXf Rtime = (Quaternionf::Identity().slerp(timer, quat)).toRotationMatrix();
MatrixXf Stime = MatrixXf::Identity(3, 3) * (1 - timer) + sMatrix * timer;
Eigen::MatrixXf A = Rtime * ((1 - timer) * MatrixXf::Identity(3, 3) + timer * Stime);
次に、元の三角形の各点 P を独自の 3x1 ベクトルに変換し、それを A で乗算します。
Eigen::Vector3f v;
v(0) = P.x;
v(1) = P.y;
v(2) = 1;
v = At * v;
最後に、新しい v(0) と v(1) に点を描き、三角形の他の 2 つの頂点について繰り返します。
タイマーが非常に小さい (0 に近い) 場合、元の三角形 (T1) の位置に新しい三角形を取得しますが、タイマーが増加すると、新しい三角形はスケーリングされ、T1 から離れて移動しますが、最後の三角形に向かって移動しません。 (T2)。
T1.inverse() を取得して T2 を掛けて計算した行列を使用するだけで、線形補間が機能するようです。したがって、私の問題は slerp の実装または SVD にあると思いますが、よくわかりません。
どこが間違っていたのかを判断するのに役立つ、他に含める必要があるものはありますか?
編集: Stime 行列を追加し、V 行列で転置の呼び出しを切り替えました。