討論區快速選單
知識庫快速選單
網路投保旅行平安險 網路投保旅行平安險
[ 回上頁 ] [ 討論區發言規則 ]
glut 教學 - 平衡環鎖(Gimbal Lock)
更改我的閱讀文章字型大小
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/4/11 下午 03:56:56
關於 三維空間旋轉 的問題, 總是重複的在各討論區出現, 重複的解答同一個問題, 好像不太符合成本效益, 就讓我在這一個教學, 一次過把它解決掉吧.

三維空間的旋轉 有 三個自由度 (degree of freedom), 要記錄三維空間的旋轉, 就算是沒啥數學概念的人, 也會想到使用三個 由 三條座標軸 量度出來的 角度 去記錄. 這種可說是最原始的 三維旋轉 代表方法, 也就是大家說的 Euler Angle.

以 Euler Angle 去代表旋轉, 當成是簡單的記錄是沒問題的, 但是, 使用 Euler Angle 去實作旋轉介面時, 就會發生某旋轉方向失效的情況, 這是因為三個獨立處理的旋轉角, 它們其中之一 使兩條座標軸重疊了. 這個情況, 我們都叫作 Gimbal Lock.

為了避免 Gimbal Lock 的出現, 人們就發展出 Axis Angle 的旋轉定義, 就是說, 旋轉 都是以 自轉軸 和 自轉角 去代表的, 使用 Axis Angle 去實作旋轉介面方法, 就是先訂出兩支 unit vector (v0, v1), 然後以 Axis Angle 找出它們的最少旋轉, 即
axis = normalize( cross(v0, v1) )
angle = acosf( v0,v1)
如此, Gimbal Lock 的問題就解決了.

雖然 Axis Angle 定義, 可以解決 Gimbal Lock 的問題, 但是, 如果我們想要在兩個 Axis Angle 旋轉 之間 插值 去做出它們之間的平滑變化, 你並不可以作單純的線性插值, 你會需要一番額外的運算, 才可以達到 插值 的功能. 又說, 如果你親手做過 Axis Angle 功能的話, 你就會發現當中常用的運算, 都包含很多類同的程序, 把它們 歸納 優化 之後, 就差不多跟我們常用的 四元數(Quaternion) 同一樣了. 你可以把 四元數 想像成 優化版 的 Axis Angle 定義. 但是, 我要強調一點, 實質的程序, 兩者沒多大差別的, 最大的分別, 大概就只是 四元數 的名號讓人看來遠不可及吧.

當然, 直接使用 Axis Angle 或 Quaternion 去實作旋轉介面 是最理想的做法, 但是, 初學者們一般也會覺得它們太複雜, 因而 望而卻步. 或是說, 如果純粹只是要避免 Gimbal Lock 的問題, 其實並不是必須使用 Axis Angle 或 Quaternion 的, 關鍵是在於避免使用三個獨立控制的旋轉而已, 以下一個範例只使用最基本的東西去避免 Gimbal Lock, 大概, 應該不會再嚇怕初學者的了.




作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/4/11 下午 03:57:58
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <GL/glut.h>

float mo[16];

void init_mo();
void update_mo( float angle, float x, float y, float z );

void display();
void keyboard( unsigned char key, int x, int y );

void main( int argc, char **argv )
{

  glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
  glutInitWindowSize( 512, 512 );

  glutCreateWindow( "gimbal_lock" );
  glutDisplayFunc( display );
  glutKeyboardFunc( keyboard );

  init_mo();

  glutMainLoop();
}

void display()
{
  GLint viewport[4];
    glGetIntegerv( GL_VIEWPORT, viewport );

  glEnable( GL_DEPTH_TEST );
  glEnable( GL_LIGHTING );
  glEnable( GL_LIGHT0 );

  glClearColor( .1, .2, .3, 1 );
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective( 45, double(viewport[2])/viewport[3], 0.1, 10 );
  
  glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt( 0,0,3, 0,0,0, 0,1,0 );
    glMultMatrixf(mo);

    glutSolidTeapot(.7);

  glutSwapBuffers();
}

void init_mo()
{
  memset( mo, 0, sizeof(mo) );
  mo[0]=mo[5]=mo[10]=mo[15]=1;
  glutPostRedisplay();
}

void update_mo( float angle, float x, float y, float z )
{
  glPushMatrix();
    glLoadIdentity();
    glRotatef( angle, x,y,z );
    glMultMatrixf(mo);
    glGetFloatv( GL_MODELVIEW_MATRIX, mo );
  glPopMatrix();

  glutPostRedisplay();
}

void keyboard( unsigned char key, int x, int y )
{
  switch( key )
  {
    case 27:
     init_mo();
     break;
    case '1':
     update_mo( -5, 1,0,0 );
    break;
    case '2':
     update_mo( 5, 1,0,0 );
    break;

    case '3':
     update_mo( -5, 0,1,0 );
    break;
    case '4':
     update_mo( 5, 0,1,0 );
    break;

    case '5':
     update_mo( -5, 0,0,1 );
    break;
    case '6':
     update_mo( 5, 0,0,1 );
    break;
  }
}
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/4/11 下午 04:05:03
這個範例, 只有一個旋轉定義

float mo[16];

就是因為只有一個旋轉定義, 因而不會出現 Gimbal Lock.

而每當我們需要改變旋轉的幅度, 我們都直接更新到 mo 去, 即

void update_mo( float angle, float x, float y, float z )
{
  glPushMatrix();
    glLoadIdentity();
    glRotatef( angle, x,y,z );
    glMultMatrixf(mo);
    glGetFloatv( GL_MODELVIEW_MATRIX, mo );
  glPopMatrix();

  glutPostRedisplay();
}
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/4/11 下午 04:11:30
void display()
{
//...
  glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt( 0,0,3, 0,0,0, 0,1,0 );

    // 所得出的總合旋轉, 在繪圖時引用
    glMultMatrixf(mo);

// ...
}
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/4/11 下午 04:16:59
噢... 差一點忘了交代...

這個程式,
按下 1 鍵 或 2 鍵 時, 就會繞著 X軸 反向 或 正向 的旋轉
按下 3 鍵 或 4 鍵 時, 就會繞著 Y軸 反向 或 正向 的旋轉
按下 5 鍵 或 6 鍵 時, 就會繞著 Z軸 反向 或 正向 的旋轉
按下 Esc 鍵, 就會重置旋轉
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/4/11 下午 04:24:13
也做一點功課吧, 上述的範例, 是一個沒有 Gimbal Lock 問題的旋轉介面, 請你, 利用 Euler Angle 定義, 做出有 Gimbal Lock 問題的旋轉介面, 然後把兩者比較一下呀.

提示:
要寫 Euler Angle 旋轉介面, 你會需要三個角度
float ax, ay, az;

按鍵時 增/減 ax, ay, az,

繪畫時, 呼叫

void display()
{
//...
    glRotatef( ax, 1,0,0 );
   glRotatef( ay, 0,1,0 );
   glRotatef( az, 0,0,1);
//...
}




作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/4/11 下午 04:25:07
最後... 如果你能夠完成這個教學, 請簽個名呀. ^^
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/9 上午 10:19:48
單靠axis-angle轉動想要避免gimbal lock是不可行的. 兩者之間的數學原理根本就不是同樣一件事. gimbal lock中的lock其實是"鎖死"的意思. gimbal是一種平衡的定向裝置(旋轉定義在三個獨立軸向x-y-z). 航太上用來判定機體翻轉時飛行器的定位. Gimbal lock(平衡環鎖死)指的是在特定情況下(例如三軸向其中出現任兩軸平行...)造成平衡環因為失去一個自由軸而無法做平衡修正的現象.

此教學的程式碼, 並沒有論點支持你對axis-angle可以避免gimbal lock的立論. 因為其中的旋轉只有單一軸向(加乘上目前的面向), 這樣沒有機會觸發Gimbal lock. 如果按鍵觸發連續三個軸向的旋轉(就跟你要大家glRotate glRotate glRotate一樣), 就有可能會發生.

3D Programming脫不了一連串的轉動, 如果想要單純的用矩陣乘法來複合這一連串的轉動, Gimbal lock還是有機會發生.

建議可以讀這本書:
http://www.amazon.com/Quaternions-Rotation-Sequences-Applications-Aerospace/dp/0691102988/ref=pd_bbs_sr_1/105-6943845-4041231?ie=UTF8&s=books&qid=1189302683&sr=8-1
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/9 上午 11:03:49
範例程式又不會說謊的, 你為何不先試試看?

要避免 gimbal lock, 關鍵是要避免三個獨立控制的旋轉, axis-angle 並不是必須的, 上文的論述已經蠻簡潔的, 我不再多解釋了.

> 此教學的程式碼, 並沒有論點支持你對axis-angle可以避免gimbal lock的立論.

還有, 上文的範例, 並沒有使用 axis-angle, 沒有關於 axis-angle 的程序也是想當然的.

> 因為其中的旋轉只有單一軸向(加乘上目前的面向), 這樣沒有機會觸發Gimbal lock. 如果按鍵觸發連續三個軸向的旋轉(就跟你要大家glRotate glRotate glRotate一樣), 就有可能會發生.

這個範例, 就算你 "按鍵觸發連續三個軸向的旋轉", 也不會有 gimbal lock 的問題的. 如果, 你能夠在上文的旋轉介面找到 gimbal lock 的話, 就請你指出. 先提提你, 不要想當然的幻想範例程式問題, 實在的試試看再說.


作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 上午 09:47:25
> 3D Programming脫不了一連串的轉動, 如果想要單純的用矩陣乘法來複合這一連串的轉動, Gimbal lock還是有機會發生.

順帶一提, gimbal lock 是 Euler Angle 旋轉定義的先天缺憾而已, 只要你不使用 Euler Angle, 就不會有 gimbal lock 的問題的.
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 上午 10:37:50
範例程式當然是試過也想過 才想提提你滴...
重點是只要你用的glRotate作一連串轉動的結合, 那麼gimbal lock就會存在.

就讓程式來說話吧....(假定編譯器是最普遍的VC)

#include <windows.h>
#include <gl/glut.h> // GLUT

//#pragma comment(lib, "opengl32.lib")
//#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glut32.lib")

float mo[16];
float Yaw = 0.0f;
float Pitch_Roll = 0.0f;
bool bLock = false;

/* 在此任選正交右手系三軸向 */
// Arbitrary orthonormal axes here(right-handed coordinate system)
float const xAxis[3] = {0.8f, 0.6f, 0.0f};
float const yAxis[3] = {-0.6f, 0.8f, 0.0f};
float const zAxis[3] = {0.0f, 0.0f, 1.0f};

/* 按任意鍵切換是否觸發Gimbal Lock */
// Keyboard
void keyboard(unsigned char key, int, int)
{
     bLock = !bLock;
     Yaw = 0.0f;
}

/* 視窗程式嘛, 總免不了改變大小 */
// Called on window resize
void resize(int w, int h)
{
     // Set viewport
     glViewport(0, 0, w, h);

     // Set up projection matrix
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     gluPerspective(45.0f, (GLfloat)w/(GLfloat)h, 1.0f, 100.0f);

     glEnable(GL_DEPTH_TEST);
     glEnable(GL_LIGHTING);
     glEnable(GL_LIGHT0);

     glClearColor(.1f, .2f, .3f, 1.0f);
}

// update for each frame
void frameupdate()
{
     Pitch_Roll += 5.0f;
     Yaw += 3.0f;

     glPushMatrix();
     glLoadIdentity();
     glRotatef(Pitch_Roll, xAxis[0], xAxis[1], xAxis[2]);

     // if Lock, trigger gimbal lock
     if(bLock && Yaw>90.0f)
Yaw = 90.0f;

     glRotatef(Yaw, yAxis[0], yAxis[1], yAxis[2]);
     glRotatef(-Pitch_Roll, zAxis[0], zAxis[1], zAxis[2]);
     glGetFloatv(GL_MODELVIEW_MATRIX, mo);
     glPopMatrix();
}
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 上午 10:40:51
// rendering callback
void display()
{
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(0.0, 0.0, 3.0, // Camera position
     0.0, 0.0, 0.0, // Look At
     0.0, 1.0, 0.0 ); // Up

     // frameupdate
     frameupdate();

     // draw something
     glMultMatrixf(mo);
     glutSolidTeapot(.7f);

     // flush and present
     glFinish();// To Synchronize, block until all GL execution is complete
     glutSwapBuffers();

     // next frame
     glutPostRedisplay();
}

// Main body of program
int main(int argc, char* argv[])
{
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
     glutInitWindowSize(800, 600);
     glutCreateWindow("Gimbal Lock Demo");

     // register glut callbacks
     glutReshapeFunc(resize);
     glutKeyboardFunc(keyboard);
     glutDisplayFunc(display);

     // main loop
     glutMainLoop();

     return 0;
}
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 上午 10:51:41
Gimbal Lock原本就很難出現的, 出現通常都很難解.
誠如之前所說, 原本的範例根本就無法造成Gimbal Lock出現的機會. 可是要就此推斷axis-angle rotation就可防止Gimbal Lock就有點...

維持相同轉動(順序)條件, 在你可以用axis-angle rotation解開此gimbal lock之前. 討論可以就此打住.

Quaternion(四元數), 真的是所有3D Programmers必須做的功課.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 下午 12:13:18
真頭痛... 首先, gimbal lock 只是 Euler Angle 的先天缺憾, 但是, 為什麼我們必須要使用 Euler Angle 呢??? axis-angle 和 quaternion 都沒有 gimbal lock 問題, 只要不使用 Euler Angle, 又何來 gimbal lock 問題給你去解決??? 這個因果關係, 請你先認識清楚.

> ... 可是要就此推斷axis-angle rotation就可防止Gimbal Lock就有點...

上文的範例, 在最開始時, 目的已經講得很清楚, 就是要在 不使用 Axis-angle 和 Quaternion 的前題 (請注意 是 不使用), 再說一遍 在 不使用 Axis-angle 和 Quaternion 的前題下, 做出沒有 gimbal lock 問題的旋轉介面. 為什麼你硬要說我在用 Axis-angle 而且 用錯了???

>誠如之前所說, 原本的範例根本就無法造成Gimbal Lock出現的機會.

你... 是否覺得 gimbal lock 是某種有用的功能?? ( 你不會是這樣想吧... ), gimbal lock 是使用 Euler Angle 設計旋轉介面時必然遇到問題, 我們恨不得要把它根除呀, 既然我寫的範例程式 "無法造成" gimbal lock 問題, 就即是 沒有 gimbal lock 問題了, 為什麼你還要把它說成有問題似的 ????

>維持相同轉動(順序)條件, 在你可以用axis-angle rotation解開此gimbal lock之前. 討論可以就此打住.
>Quaternion(四元數), 真的是所有3D Programmers必須做的功課.

使用 axis-angle 去設計沒 gimbal lock 問題的旋轉介面的方法, 在文章最開始時簡述了一點點, 但是, 這不是文章的重點. 實在, 關於 axis-angle 和 quaternion 的使用方法, 在解答網友提問時我已經重複又重複的向他們介紹和推薦, 只是, 網友們總時覺得 axis-angle 和 quaternion 太難了解 而不願意使用.

最後, 我想再強調一點, gimbal lock 只是 Euler Angle 的先天缺憾, 除了歷史因素之外, 我們是完完全全沒任何理由去使用有先天缺憾的 Euler Angle 去實作旋轉介面的. 也請你面對現實, 放棄 Euler Angle 吧... 如此, 就沒什麼 gimbal lock 需要解決了.

作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 下午 12:33:35
> 範例程式當然是試過也想過 才想提提你滴...
> 重點是只要你用的glRotate作一連串轉動的結合, 那麼gimbal lock就會存在.

glRotate 作一連串轉動的結合 並不代表會出現 gimbal lock 的. gimbal lock 的根源, 是來自 Euler angle 旋轉定義的, 更仔細的說, 就是, 當你祈望 增加個別 Euler angle 參數 來達致旋轉這個行動, 會引致 gimbal lock.

重點應該是只要你用 Euler angle, 那麼gimbal lock就會存在. 犯了使用 Euler angle 這麼大的一個錯誤, 才會需要往後用各式各樣詭異的方法, 左右為難的拼貼補救.
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 下午 02:41:55
聽起來, 這個教學其實是 : 我能用axis-angle把茶壺搞的團團轉而且一點都不卡, 所以axis-angle疊合沒有Gimbal Lock的問題!?

Gimbal Lock跟Euler angles並沒有絕對的關係. 只要您用矩陣來描述轉動, 用矩陣乘法來表示轉動的疊合. 那麼您就無法擺脫Gimbal Lock的威脅. glRotate只是一個方便的例子罷了.

平心靜氣想一想:
R1 : axis = (1,0,0), angle = 5(degree), 是不是一個有效的轉動?
R2 : axis = (0,1,0), angle = 90(degree), 是不是一個有效的轉動?
R3 : axis = (0,0,1), angle = -5.0(degree)), 是不是一個有效的轉動?

那敢問, 您所謂"Axis Angle 定義, 可以解決 Gimbal Lock 的問題", 您的轉動是怎麼描述R1xR2的結果? R1xR2xR3 的結果? 還是您這個"轉動介面"拒絕處理這個問題, 因為這樣的轉動順序太危險?

辦法絕對是有的, 最簡單的還是Quaternion(dual Quaternion). 如果你可以做出來一個"轉動介面", 不管運算方面有沒有比Quaternion來得有效率, 不彷試試去各大期刊投稿, 說不定您這位國際級大師可以跟Jim Blinn, Ken Shoemake齊名. 不過這"轉動介面"可要能轉換成4x4 Matrix格式才行, 這樣目前的3D 顯示硬體就可以用.

很抱歉造成您頭痛老毛病又犯了. 不過看不見並不代表沒有. 父系空間轉動如R1, 子系空間做R2轉動, 孫系空間做R3轉動, 在3D空間可是稀鬆平常的事.

最後, 問題其實出自矩陣的乘法(還有時間太多的我), Euler angles絕對是無辜的. 其他有(不)幸看到這篇的網友們, 請對以上的討論持懷疑的態度. 試著研究以上Gimbal Lock的範例, 並自己去找出問題所在.

就這樣子, 祝一切順利.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 下午 03:34:00
前面的討論, 已經提出過了...

gimbal lock 的根源, 是來自 Euler angle 旋轉定義的, 更仔細的說, 就是, 當你祈望 增加個別 Euler angle 參數 來達致旋轉這個行動, 會引致 gimbal lock.

Euler angle 是代表著 三維空間旋轉, 三維空間旋轉 本身是並不存在 gimbal lock 的問題的, 問題只在增加個別 Euler angle 參數 來達致控制旋轉這個行動. 只要你不這樣做, 是不會出現 gimbal lock 的問題的. 你所列舉的例子, 全都在進行這個行動, 有 gimbal lock 是自然的事.

或者... 我們試試看另一個角度去看看 gimbal lock 的影響, 如果我使用 Euler angle 實作旋轉介面, 在某些 Euler angle 參數下, 某個方向的旋轉控制失效了. 但是, 這絕不是說在這參數下, 三維空間旋轉 只有二個自由度, 反之, 在任何情況下, 我們都應該有三個自由度的控制, 只不過 Euler angle 受制於自己的先天缺憾, 提供不了這個功能而已. 請留心, 這個影響只限於參數條整, 只要旋轉介面本身沒 gimbal lock 問題, 連續的旋轉是不會有問題的.

又說, 我們來談談邏輯, 如果 gimbal lock 是 三維空間旋轉 的問題, 這麼, 又甚可能存在沒 gimbal lock 問題的旋轉介面?? 假設, 如果 gimbal lock 真的是 三維空間旋轉 的問題的話... 是否我拿在手上的電話, 某種旋轉之後, 就會出現某個方向的旋轉不能控制的問題嗎?? ^^" 如果我的手眼協調沒有錯誤的話, 這個假設是不成立的. (除非... 我的手眼協調是有問題??)

來來來, 請問你能在現實世界, 旋轉實物至某個方向不能旋轉, 如果你能找到的話, 應該是物理學界的重大發現了.






作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 下午 03:46:25
還有, 除了最開始的序言之外, 這篇文章並沒有任何使用 Axis angle 的意思, 你為什麼硬要說文章裡沒清楚的講解 Axis angle?? 更徨論什麼什麼 Axis angle 的結論是錯誤的...

也許你覺得 gimbal lock 只能用非常複雜 和 高檔的概念去解決, 但是, 上文的程式, 真的提供了一個沒 gimbal lock 的旋轉介面了, 沒有 axis angle, 沒有 quaternion, 只用了最基本的東西, 就能提供 三個自由度 的 三維空間旋轉.

如果你仍然堅持上文的程式是假的, 就請你解釋一下, 為什麼... "我的範例能提供 三個自由度 的 三維空間旋轉 而且沒 gimbal lock 問題的"? ( 不要跟我說什麼什麼權威, 眼前的範例程式, 就只有這麼幾句而已... )
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 下午 09:44:56
我的錯, 我的範例給的太極端, 讓你誤以為Gimbal Lock一定要鎖死到一動也不動.

不管你用的是什麼樣的系統, 只要你是用單純矩陣的乘法, 你就避不掉Gimbal Lock.
最後一個例子了, 希望大家真的用心想一想, 就像我試著努力了解你想表達的重點一樣.
我只對前一個例子稍作修改...

#include <Mmsystem.h> // timeGetTime
#pragma comment(lib, "Winmm.lib") // timeGetTime

// globals
float mo[16];
float gAppStart = 0;
bool bLock = false;

// Keyboard
void keyboard(unsigned char, int, int)
{
     bLock = !bLock;
     gAppStart = timeGetTime(); // reset timer
}

// update for each frame
void frameupdate()
{
     float time = 0.001f*(timeGetTime() - gAppStart); // in second

     float Pitch = 180.0f*time;
     float Roll = 240.0f*time;
     float Yaw = 18.0f*time; // 5 seconds to reach 90 after any key pressed.

     // if Lock, trigger gimbal lock
     if(bLock && Yaw>90.0f) Yaw = 90.0f;

     glPushMatrix();
     glLoadIdentity();
     glRotatef(Pitch, 1.0f, 0.0f, 0.0f);
     glRotatef(Yaw, 0.0f, 1.0f, 0.0f);
     glRotatef(Roll, 0.0f, 0.0f, 1.0f);
     glGetFloatv(GL_MODELVIEW_MATRIX, mo);
     glPopMatrix();
}

// Main body of program
int main()
{
     照舊...
     glutDisplayFunc(display);

     gAppStart = timeGetTime(); // 插入此行
     // main loop
     glutMainLoop();

     return 0;
}

至於你的例子, 並沒有提供 "三個自由度 的 三維空間旋轉", 同一時間只有繞著一個軸做轉動而已, 也就是如此, 根本還不到Gimbal Lock所形成的條件. 就像我現在斷言台灣以後都不會有地震, 今天沒有並不代表沒有. 至於你所謂的奇怪物理現象, 不是現實有問題, 而是"用矩陣乘法來表示轉動會有問題", 現實是對的, 矩陣有機會出錯. 不管是Euler Angles, Axis-angle, direction cosines, 甚至Quaternion.... 只要你能想到用來求算轉動矩陣的方法, 再運用矩陣的乘法做轉動疊合, 就是會出現你想要排除的結果.

回到上面的例子, 先觀察茶壺的轉動, 觀察壺嘴運動的模式, 八字形的運動著, 擺幅或大或小, 但是可以斷定有二維以上的自由度(對照你的例子只有一個維度), 就算一直放到下次地震之前, 我相信也是會如此. 按任意按鍵之後, 五秒鐘時間, 茶壺左右擺動幅度越來越小, 直到最後就只剩後空翻, 只剩繞著x軸轉動, 一個維度, 可是明明至少有繞著x/z軸旋轉...... 如果這是動畫師調出來給你的結果(他會覺得你很遜), 他想要的轉動應該是茶壺光是後空翻之外, 還要能做逆時針旋轉(+Z軸), 程式設計師往往只管下轉動指令, 通常不去管眼前的轉動是否跟預期的一致.

重點:"矩 陣 乘 法 早 晚 出 錯". 就算單純用Quaternion直接乘法也無法避免Gimble Lock, 必須有一番修正才行, 不過那是大家不關心的事.

就當我是一派胡言, 真正的問題還是自己想過才會有所得. 回地球了.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/10 下午 10:27:45
> 至於你的例子, 並沒有提供 "三個自由度 的 三維空間旋轉", 同一時間只有繞著一個軸做轉動而已,

我相信你必定覺得我是愚昧無知的初學者, 或者 是在侮辱我的知識. 不然, 又甚會說這種不負責任的話. 要知道... 我的範例程式 是可以提供 "三個自由度 的 三維空間旋轉".

你對 gimbal lock 的誤解, 力量之大, 竟然可 扭曲程式功能, 扭曲物理現象 甚至 扭曲數學現象, 我一介凡人, 面對這樣大的一股力量, 只可輕嘆 無能為力 了.

如果有一天, 你終於能了解我在說什麼的話, 我歡迎回來說句謝謝.
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/11 上午 10:08:03
謝謝.

呼.... 好吧.

首先, 你的程式碼真的沒有 提供 "三個自由度 的 三維空間旋轉". 劃一時間軸, 你的程式充其量只是一些"單一維度轉動的片段(而且一段一段不重疊)所構成的組合"而已. 除非終身以劃旋轉茶壺為執志, 這樣的轉動系統, 在實際運用上弱了些, "關節階級動畫", "動畫調合"在3D程式非常普遍. 套用您這個系統""也許""會有問題. 也許您覺得這樣就是所謂"三個自由度 的 三維空間旋轉". 那我無話可說, 不過我所在的業界, 不會有人同意.

沒有人扭曲物理現象, 說過不只一次了, 這是我們(不是您)無腦的想要運用矩陣來詮釋物理剛體旋轉現象其中確實存在的不幸結果. Gimbal-Lock確實存在, apollo 10(沒錯不是13)在1969.05.18在月球軌道上測試時發生的現象, 怪罪物理學嗎? 當然不是, 那是裝置出現問題("The Apollo 10 Gimbal-Lock Incident"). 問題原理跟3D 程式師用矩陣所出現的問題一樣, 也才因此得名. 還有, 旋轉茶壺不過是我們模擬真實物理的結果(不是真的物理), 出現問題是我們(不是您)不好, 不是物理有誤.

扭曲數學? 也許吧? 因為就算我擁有數學碩士學歷, 難保您就不是數學博士, 見笑了.

最後我的重點仍是 : 運用矩陣乘法真的要小心. 舉一段證明Gimbal-Lock無所不在的程式碼, 當作結束. 真理為何就讓各位看官去評論. 我不一定是對的, 自己確實想過才最要緊.

這個範例接受按鍵'+' 跟 '-'(正常在鍵盤右側), 按'+'增加特定軸轉角度, 增加到最大"120度"時觸發Gimbal Lock...

// globals
float mo[16];
float CriticalAngle = 0.0f;

// Keyboard
void keyboard(unsigned char key, int, int)
{
     switch(key)
     {
     case '+': // glut is neutral, not VK_ADD!!!
if(++CriticalAngle>120.0f)
CriticalAngle = 120.0f;
     break;

     case '-':
if(--CriticalAngle<0.0f)
CriticalAngle = 0.0f;
     break;
     }
}

// update for each frame
void frameupdate()
{
     // no worry! GL will normalized this vector.
     static float const Axis[3] = {1.0f, 1.0f, 1.0f};

     float time = 0.001f*timeGetTime(); // in second
     float Pitch = 180.0f*time;
     float Roll = 240.0f*time;

     glPushMatrix();
     glLoadIdentity();
     glRotatef(Pitch, 1.0f, 0.0f, 0.0f);
     glRotatef(CriticalAngle, Axis[0], Axis[1], Axis[2]); // watch this!!!
     glRotatef(Roll, 0.0f, 0.0f, 1.0f);
     glGetFloatv(GL_MODELVIEW_MATRIX, mo);
     glPopMatrix();
}

缺的程式碼請往上頭剪吧.

記住, 我不一定是對的. 也許這又是重度扭曲原程式, 扭曲數學(還有物理)罷了!
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/11 下午 12:04:47
你所指的 "關節階級動畫" 大概就每個部份都有一個自己的旋轉吧, 旋轉 (不管是 現實世界的 或是 以矩陣代表的) 都沒有 gimbal lock 問題的, gimbal lock 只會出現在你嘗試用 Euler angle 控制旋轉的時候.

至於我的範例, 並不只能旋轉一維, 當中用來記錄旋轉的, 是一個 4x4 的旋轉矩陣. 你, 是絕對可以取出這個 4x4 的旋轉矩陣, 應用在 "關節階級動畫" 裡.

Euler angle 之所以會引致 gimbal lock 問題, 是因為它有一些 singular point, 即是, 多個 Euler angle 定義被對應到同一 實際旋轉.

情況就好像用經緯度的來定義球面位置一般, 在一般的情況下, 你是能夠透過增加 經度 來改變位置的, 但是, 在 北極點 和 南極點, 無論你如何增加經度, 你都只是在同一點上, 但是, 這絕不是代表 北極點 和 南極點 跟其他的地區有任何分別, 這個問題, 只是因為 經緯度定義 有兩點 singular point 而已. 實質上, 球面上的任何一點, 本質上都是同一樣的. 只要我們避免透過 增減經緯度 來 改變位置, 就不會發生上述的問題. 好像三維旋轉一般, 除了 經緯度 之外, 我們還有很多沒有 singular point 的球面定位方法, 除了 歷史因素之外, 經緯度 (相比起其他方法) 其實是全沒好處的.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/11 下午 12:25:22
既然你是數學碩士, 這麼我就多列舉一個類同的數學現象, 代表直線的方程式, 我們有好幾種方法, 其中一種是 斜截式

y = mx + c

但是, 以這個方種方法來定義直線, 垂直的線是不能被代表的, 如果我們限制自己使用 斜截式 去代表直線, 就需每次都個別考慮 垂直線. 但是, 這並不是代表 垂直線 跟其他直線本質上有分別, 這只是 斜截式定義 本身的先天缺憾而已. 如果我們用

ax + by + c = d

去代表直線, 就不會出現 垂直線不能被定義的問題了.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/11 下午 01:25:30

>// Keyboard
>void keyboard(unsigned char key, int, int)
>{
> switch(key)
> {
> case ''+'': // glut is neutral, not VK_ADD!!!
> if(++CriticalAngle>120.0f) << 這裡才是 gimbal lock 的問題所在
> CriticalAngle = 120.0f;
> break;
>
> case ''-'':
> if(--CriticalAngle<0.0f) << 這裡才是 gimbal lock 的問題所在
> CriticalAngle = 0.0f;
> break;
> }
>}
>
>// update for each frame
>void frameupdate()
>{
> // no worry! GL will normalized this vector.
> static float const Axis[3] = {1.0f, 1.0f, 1.0f};
>
> float time = 0.001f*timeGetTime(); // in second
> float Pitch = 180.0f*time; << 這裡才是 gimbal lock 的問題所在
> float Roll = 240.0f*time; << 這裡才是 gimbal lock 的問題所在
>
> glPushMatrix();
> glLoadIdentity();
> glRotatef(Pitch, 1.0f, 0.0f, 0.0f); << 這跟 gimbal lock 無關
> glRotatef(CriticalAngle, Axis[0], Axis[1], Axis[2]); << 這跟 gimbal lock 無關> glRotatef(Roll, 0.0f, 0.0f, 1.0f);<< 這跟 gimbal lock 無關
> glGetFloatv(GL_MODELVIEW_MATRIX, mo);
> glPopMatrix();
>}
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/12 上午 09:52:14
是裝傻還是真的那麼難理解啊?

原本看到這位老大您只留一篇, 無關痛癢, 仍舊執迷不悟認為"Euler Angles導致Gimbal-Lock"的回應(我想您要認真想過上一個例子, 調理清晰的人要同意也會有點難.). 我真的倒盡胃口不想再有回應的,算是給你個台階下. 可你扯出點斜式模糊焦點, 再把最後範例胡亂解釋一番, 不是擺明著給自己找難堪?

不用到研究所, 數學本系的學生吃高微,代數當早餐, 點斜什麼式的除非不得已得充當家教糊口, 不會有人無聊到想提. 您還是自己留著用吧(那何不用向量? 斜率不就是微分?). 本版絕大多幾何, 線代的數學問題. 只能當第二節下課點心而已. 當我們跟對方說你先前的立論有問題, 那也只是我們有禮貌性的互相打聲招呼.

最後的例子, 120度繞(未正規化)旋轉軸axis = (1.0, 1.0, 1.0)轉動, 才是整個問題的重點. (難道數學除了點斜式(我開始無聊了)之外, 這兩項因數不能對你有所啟發?)

1) 上例三旋轉軸難道沒有"避免使用三個獨立控制的旋轉"(開篇主要論點一).
2) 難道上個例子是你所謂Euler Angles轉動? (1.0,1.0, 1.0)可不是任何XYZ軸之一.
3) 你知道這產生了Gimbal-Lock. 那就你所堅信你的矩陣什麼的"...不只能旋轉一維, 當中用來記錄旋轉的, 是一個 4x4 的旋轉矩陣. 是絕對可以取出這個 4x4 的旋轉矩陣, 應用在..."看來,是絕對有機會出現這樣旋轉組合的. 現在問題來到你用矩陣要怎麼解? 這篇教學不就是你得提出讓我們信服的解決之道不是嗎?

幾何上的解釋, 120度繞未正規化旋轉軸axis = (1.0, 1.0, 1.0)做轉動沒什麼錯, 是矩陣前後結合造成的問題, 以OpenGL右手座標系來看. X軸繞axis轉動一圈(2pi弳度或是360度)所成軌跡會形成一正圓錐. 你會發現, XYZ軸均勻分布其上. X軸轉120度(注意方向)來到Y軸, 再轉120度來到Z軸, 再120度回到X軸. 我只是設了一個陷阱將Z軸(範例最後一個轉動軸)轉到X軸這時矩陣的運算就無可避免的出現Gimbal-Lock. 我一直講矩陣是問題, 矩陣是問題. 你的系統也是矩陣, 真可以避免的話, 你就應該提出可以挽救上一個例子的確切作法.

要知道, 這樣的"巧合"就是不時的在發生, 甚至您可以任意給我兩個轉動軸, (不?)幸運的只要浮點數誤差能控制在一定的範圍內, 都有機會插入一個轉動造成Gimbal-Lock.

4x4矩陣涵蓋了所有Euler Angle轉動模式, 當我舉到了矩陣的層級出錯時, 那問題癥結點就有可能不是只有Euler Angles轉動而已. 在邏輯上當你論述一件事情是正確的, 只要出現反例, 那論述就是荒誤的. 也就是說, 要推翻那件事情是錯的, 一個反例就夠. 當然你也可以試著推翻這些反例得到大家的認同, 也可以繼續視而不見, 甚至斷章取義倒打, 指控我扭曲什麼樣的科學等等的污衊我都欣然接受, 那只是我今天的下午茶.

還有, 這裡沒有人擁護Euler Angles, 不過這真的很方便用. 我想每個有理想在默默開發3D引擎的人, 程式碼裡的某處也必定存在著Euler angles轉動跟矩陣間的互換計算.

老實說, 我本來就對這討論區"因人廢言"的討論態度失望透頂, 要不是這篇立論會誤導許多人, 而且老大您又一直頑強的轉貼在許多不同地方, 我真的不想有任何回應. 而現在我卻也開始厭煩我的多事.

以上以上, 看完這些要是有任何一個人真能認真想過這個問題, 或有所得, 甚至發現我所犯的誤謬, 那就算有了回報. 與其花費心力去捍衛自己, 我寧願花更多的心力讓自己成長. 任何批評指教可以寄到 hornglin@hotmail.com反正很多垃圾信寄到這裡(開玩笑的啦).

再會了, 記得時時都要努力.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/12 上午 11:49:46
> 1) 上例三旋轉軸難道沒有"避免使用三個獨立控制的旋轉"(開篇主要論點一).

你所列的例子, 沒有 "避免使用三個獨立控制的旋轉", Pitch, CriticalAngle, Roll, 剛好就是三個了.

2) 難道上個例子是你所謂Euler Angles轉動? (1.0,1.0, 1.0)可不是任何XYZ軸之一.

Euler Angles 的定義, 並不必然是 XYZ 軸, 甚至... 常用的 Euler Angles 也不是 XYZ 軸的.
http://en.wikipedia.org/wiki/Euler_angles

3) 你知道這產生了Gimbal-Lock. 那就你所堅信你的矩陣什麼的"...不只能旋轉一維, 當中用來記錄旋轉的, 是一個 4x4 的旋轉矩陣. 是絕對可以取出這個 4x4 的旋轉矩陣, 應用在..."看來,是絕對有機會出現這樣旋轉組合的. 現在問題來到你用矩陣要怎麼解? 這篇教學不就是你得提出讓我們信服的解決之道不是嗎?

Gimbal lock 的影響, 是在某些旋轉下, 只有二維的控制. 這裡包含了一個 祈望, 就是 祈望增加 Euler angles 參數來控旋轉, 有這個 祈望 而達成不了, 才會有所謂的 Gimbal lock. 同樣的旋轉組合是會出現的, 但是, 如果沒有用 Euler angles 參數來控旋轉的祈望, 請問 Gimbal lock 又如何可以發生?? 說理論, 說例子, 說比喻, 這麼久了, 這麼簡單的因果關係也不明白的, 是那過了點吧.

已經太長的討論了, 如果你要繼續這個討論, 請你先找找我, 我的 MSN 是 ma_hty@hotmail.com . 因為這個討論開始有點火藥味, 我按捺著意氣話, 並不代表我軟弱, 只是, 我很討厭筆戰而已.
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/12 下午 04:20:01
下午茶時間, 不過很抱歉不想找你...
(先別動肝火, 要知道先指責別人扭曲現實的人可是你)

如果隨意使用三個軸轉動還不是你所謂的"避免使用三個獨立控制的旋轉", 那你應該給個方向怎麼樣複合三個轉動叫才是"避免使用三個獨立控制的旋轉"?(那我也才有機會給你一個最糟的範例) 還是根本就不允許複合三個以上的轉動?

是的,Euler Angles轉動是沒有確切的定義, 不過所有Euler Angles延伸的運用都不外乎選擇三座標軸-正X軸, 正Y軸, 正Z軸轉動(基本轉動)其中的任三個所組成(請注意有三個, 而且允許重複). 你提供的連結就有說明, 進去看清楚. (1,1,1)明顯不是正X軸或正Y軸或正Z軸(要知道(1,1,1)只是我隨便選的). 這樣隨意解釋Euler Angles rotation, 會陷入更大的危機. 如果真是照你說, 那Euler Angles轉動跟Axis-Angle轉動豈不是根本就一樣? 你又強烈建議大家放棄Euler Angle轉動, 那不是就不要轉了? 隨意貼網址不去看只想嚇人, 會讓人看不起.(上面貼出來的書我當然是看過的, 歡迎你拿內容來考我!)

為何不能有怎樣的期望? 明明有方法可以達成這樣的期望. 那就要去克服, 我們的工作就是克服難題不是? 難道你真這麼甘心作一個這麼受限制的轉動系統? 要是我這樣跟動畫師講:"不行喔, 你這樣的期望會Gimbal-Lock." 我不等著去美術頭頭辦公室夾懶蛋?

往哪個方向呆版的增加參數來旋轉, 當然是簡單範例才會有的寫法. 大多的狀況是隨著時間軸進行去把預先調好的動畫資料("矩陣"也好, "縮放+四元數+位移"也好)根據時間點決定之後, 再總成起來. 萬一用的資料是矩陣(就跟你一樣), 又剛好某個時間點組起來就是那麼糟(湊巧), 我們只能眼睜睜看問題發生?

要我怎樣(包含跟你認錯)都行, 只要你記住闡述事實要有所根據, 別因此誤導別人. 我說真的.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/12 下午 05:34:45
>如果隨意使用三個軸轉動還不是你所謂的'避免使用三個獨立控制的旋轉', 那你應該給個方向怎麼樣複合三個轉動叫才是'避免使用三個獨立控制的旋轉'?(那我也才有機會給你一個最糟的範例) 還是根本就不允許複合三個以上的轉動?
>

文章最開始, 已經給了一個範例.

除了這個範例之外, 你也可以利用滑鼠點選出的兩支 unit vector, 配合 axis angles 的特質找出最少旋轉, 用來當旋轉介面. 亦即是最常見的 arcball 介面.

以上兩個方法, 都避免了使用三個獨立控制的旋轉.

> ... 這樣隨意解釋Euler Angles rotation, 會陷入更大的危機. 如果真是照你說, 那Euler Angles轉動跟Axis-Angle轉動豈不是根本就一樣? ... 隨意貼網址不去看只想嚇人, 會讓人看不起 ...

不是要 "嚇人" (嚇人?), 我只想指出, Euler Angles 座標軸並不必然是 XYZ 而已. 實在, 只要接鄰座標軸不互相平衡, 就足夠當 Euler Angles 的座標軸了. 還有 Euler angles 是複合三個定軸 axis angle 而成的, 為什麼同一樣?

>往哪個方向呆版的增加參數來旋轉, 當然是簡單範例才會有的寫法. 大多的狀況是隨著時間軸進行去把預先調好的動畫資料('矩陣'也好, '縮放+四元數+位移'也好)根據時間點決定之後, 再總成起來. 萬一用的資料是矩陣(就跟你一樣), 又剛好某個時間點組起來就是那麼糟(湊巧), 我們只能眼睜睜看問題發生?
>

你所說的 隨著時間軸進行預先調好的動畫資料, 不會是以 Euler angles 參數定義的軌跡公式吧... 也不會是替 Euler angles 定義的 key rotation 按時間插值吧... 如果這樣做, 就似乎有點不合時宜了.

這些動畫資料, 當中的 key rotation, 應該用 quaternion 代表, 以便利按時間插值. 我的範例以 4x4 矩陣 去代表旋轉, 故然是不適合這個插值應用, 但是, Euler angles 也不適合呢...
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/12 下午 06:55:49
> 首先, 你的程式碼真的沒有 提供 "三個自由度 的 三維空間旋轉". 劃一時間軸, 你的程式充其量只是一些"單一維度轉動的片段(而且一段一段不重疊)所構成的組合"而已.

對了, 按你這個論調, 這個我們常用的 arcball 介面, 在劃一時間軸, 它只能提供單一軸向的自旋呀. 這麼... arcball 介面 是否也沒有提供 "三個自由度 的 三維空間旋轉"?
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/12 下午 10:16:02
球面上一點原本在A位置, 轉動之後到了B位置. 這條軌跡如果是球面上最短路徑, 那這個轉動需要兩個轉動去結合出來嗎?

Arcball拖動茶壺, 壺嘴在11點鐘位置. 鼠標由中心點往四點鐘方向拖去. 那麼壺嘴要是直接往三點鐘方向去(感覺就好). 那你想不是只要以一點鐘方向為軸做單一璇轉就可以了? 如果持續拖的夠長, 壺嘴應該有機會以最短路徑回到最原始11點鐘位置, 行徑軌跡恰可形成一個非常"正"的圓. 不過要是你的眼睛跟不上壺嘴運動, 開始有點飄,不是以最短路徑到達三點鐘位置, 這"一連串運動過程"就不是單純以一個簡單的轉動就能做得出來的.

不用什麼R4, S3空間理論, "最短路徑"在轉動上是個非常重要的觀念, 所有轉動內插方法都非常注重是否能形成"最短路徑"

不介意的話我還想提Euler Angles轉動, 正因為Euler是個非常偉大的數學家, 所以還是尊重他的定義才好. Euler Angles是偉大的概念是分解:"An arbitrary rotation may be described by only three parameters". 跟我們只用來結合,難度等級真的差太多.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/13 上午 12:06:28
甚麼了? 你不是說所有旋轉介面都有 gimbal lock 的問題嗎? arcball 介面也是 旋轉介面, 它以 axis angle 運算, 但是, 按你的理論, 因為 axis angle 和 Euler angle 是能夠互化呀, arcball 介面 都有 gimbal lock 呀.
作者 : andrechen(andre)
[ 貼文 81 | 人氣 5 | 評價 610 | 評價/貼文 7.53 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/13 上午 07:35:56
因為不管目前 Arcball處於麼樣的狀態(或者說方位orientation).鼠標拖動Arcball只要選定一個軸轉動, 也就是說 :"單...純...轉...動...一...次...就...到...位...了"

也許像這樣:
Matrix4 const CalcArcBallRotationMatrix(int mouse_dx, int mouse_dy)
{
     // 這裡找到自轉軸(window space), 也就是和(mouse_dx, mouse_dy)正交的向量。(check:點內積為零, 使用左手座標系的人請注意方向)
     int x = -mouse_dy;
     int y = mouse_dx;

     // 以下y軸方向變號是因為世界座標Y軸跟螢幕Y軸倒反。
     Vector3 vAxis = x * pCamera->GetRight() - y * pCamera->GetUp();
     float angle = ToGetRotationAngle(arcballRadius, x, y);//你猜?
  return Matrix4(vAxis, angle); // 假定Matrix4有一個可從axis-angle轉換的建構子。
}

要勇敢這樣寫也不意外:
     Vector3 vAxisX = pCamera->GetRight();
     Vector3 vAxisY = pCamera->GetUp();
     return Matrix4(vAxisX, kConst*mouse_dy) * Matrix4(vAxisY, kConst*mouse_dx);

我會假定他知道僅僅"兩個"轉動疊合不會產生Gimbal-Lock(而且個別轉動角度都很小),要是動起來跟鼠標拖動方向直覺上有小小的誤差(也許沒有誤差)也沒有關係。

程式風格就不討論了,程式哪邊有錯也不用麻煩寫信告訴我,這段程式碼不會在我的任何檔案裡。今天有點忙,不會有下午茶時間,諸多冒犯,望高抬貴手,大人不記小人過。

後會有期。
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/13 上午 08:19:50
> 我會假定他知道僅僅'兩個'轉動疊合不會產生Gimbal-Lock(而且個別轉動角度都很小),要是動起來跟鼠標拖動方向直覺上有小小的誤差(也許沒有誤差)也沒有關係。

不太懂你的意思... 請問... 你是否認為 arcball 介面也有 gimbal lock 問題呢?

在 arcball 介面, 不管每次自旋的角度多少, 也不會引致 gimbal lock 問題的.

作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2189 | 人氣 89850 | 評價 10120 | 評價/貼文 4.62 | 送出評價 79 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/9/15 上午 05:23:58
> Gimbal Lock跟Euler angles並沒有絕對的關係. 只要您用矩陣來描述轉動, 用矩陣乘法來表示轉動的疊合. 那麼您就無法擺脫Gimbal Lock的威脅. glRotate只是一個方便的例子罷了.

在網上找回來, 關於 Gimbal Lock 和 Euler angles 關係的討論.

> 原本看到這位老大您只留一篇, 無關痛癢, 仍舊執迷不悟認為"Euler Angles導致Gimbal-Lock"的回應(我想您要認真想過上一個例子, 調理清晰的人要同意也會有點難.). 我真的倒盡胃口不想再有回應的,算是給你個台階下. 可你扯出點斜式模糊焦點, 再把最後範例胡亂解釋一番, 不是擺明著給自己找難堪?

國外的討論, 多以 Euler Angles導致Gimbal-Lock 為主, 說不定, 台灣的旋轉是跟外國的不同吧...
 板主 : 白老鼠(Gary)
 > OpenGL - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - OpenGL - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
OpenGL
1 白老鼠(Gary) 2720 
2 CROMAYEN2000 1530 
3 aming 500 
4 東昇 380 
5 PLAYER 120 
6 富伯 110 
7 qq 100 
8 NDark 80 
9 ozzy 60 
10 simula 60 
OpenGL
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.125