«ゴム網シミュレータ 最新 日本のCGプロダクション»

床井研究室

※このブログは遅くとも 2027 年 3 月に管理者の定年退職により閉鎖します (移転先は管理者本人共々模索中)

■ 2004年04月30日 [授業] ゲームグラフィックス特論

2012年03月05日 13:32更新

球面線形補間

4月に入ってなんだか妙に忙しいと思っているうちに,今日はもう30日!なのに,今月は全然ブログ書いとらん…いかん,何か書かねばと思ってもネタがない.仕方がないからゲームグラフィックス特論(なんちゅう講義名だ)の宿題のヒントを.

まず,2つのクォータニオンの補間の実装は,例えばこんな具合になります.

#include <math.h>
#include <float.h>
 
/*
** 球面線形補間 p ← q と r を t で補間したクォータニオン
*/
void slerp(double p[], const double q[], const double r[],
           const double t)
{
  double qr = q[0] * r[0] + q[1] * r[1] + q[2] * r[2] + q[3] * r[3];
  double ss = 1.0 - qr * qr, sp;
  
  if (ss <= 0.0 || (sp = sqrt(ss)) == 0.0) {
    p[0] = q[0];
    p[1] = q[1];
    p[2] = q[2];
    p[3] = q[3];
  }
  else {
    double ph = acos(qr);
    double pt = ph * t;
    double t1 = sin(pt) / sp;
    double t0 = sin(ph - pt) / sp;
    
    p[0] = q[0] * t0 + r[0] * t1;
    p[1] = q[1] * t0 + r[1] * t1;
    p[2] = q[2] * t0 + r[2] * t1;
    p[3] = q[3] * t0 + r[3] * t1;
  }
}

宿題のプログラムを完成させるのに必要なのは,時間軸上に配置された複数のクォータニオンを補間して,ある時刻における姿勢を求める手続きです.すなわち,時刻 ti における姿勢 qi が与えられているとき,それらから時刻 t における姿勢 q(t) を求める関数を作ります.

飛行経路

このために,まず t を含む区間 [ti,ti+i) を探します.これには飛行経路を求めるのに使っているスプライン補間同様,二分探索を用いることができます.そして,その区間 i の両端のクォータニオン qiqi+1 を線形補間して,q(t) を求めます.書いてみると簡単でしょ>某氏.

/*
** 複数のクォータニオン間の球面線形補間(折れ線)
**   p ← t[i] におけるクォータニオン q[i], 0 <= i < n に対する
**        u における補間値
**        
*/
void mslerp(double p[],
            const double t[], const double q[][4], const int n,
	    const double u)
{
  int i = 0, j = n - 1;
  
  /* u を含む t の区間 [t[i], t[i+1]) を二分法で求める */
  while (i < j) {
    int k = (i + j) / 2;
    if (t[k] < u)
      i = k + 1;
    else
      j = k;
  }
  if (i > 0) --i;
  
  slerp(p, q[i], q[i + 1], (u - t[i]) / (t[i + 1] - t[i]));
}

それで,たとえばこういう絵を作ってみてください.

飛行物体

(しかし線形補間だとやっぱりぎこちない)

コメント(2) [コメントを投稿する]
5mingame2 2012年02月28日 23:09

こんにちは!<br><br>細かい事で申し訳ないのですが…(汗)<br><br>slerp()で <br><br>if ((ss == 0.0) {...} else {...}<br><br>と処理を分けている箇所、ss が0より大きくて、すごく小さい値の場合などで、sqrt(ss) でエラーになったりする可能性がありますね…(というか、なりました)<br><br>以上、ご報告まで。

とこ 2012年03月05日 13:17

ご指摘ありがとうございます!ss が負でなかったら,小さくても sqrt(ss) がエラーになることは無いと思うんですが…<br>あ,ss が計算機イプシロンに近くて sqrt(ss) が 0 になってしまったために,sp での割り算でエラーになるということはありそうです.<br>そうならないようにするには sqrt(ss) を計算してから 0.0 との比較をしないといけないですね.


編集 «ゴム網シミュレータ 最新 日本のCGプロダクション»