行列:効率の良い合成

「行列:効率の良い合成」の編集履歴(バックアップ)一覧はこちら

行列:効率の良い合成」(2014/04/16 (水) 18:54:31) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

<p><strong>行列同士は行列の積を行うと合成する事ができます。<br /> しかし、4×4行列の積は16回も計算しなければなりません。<br /> 平行移動成分と回転成分、拡大縮小成分を合成するのに<br /> 32回も計算するのでしょうか?</strong></p> <p><strong>平行移動成分は回転成分と拡大縮小成分に影響しないので3回の代入で<br /> 済ます事ができます。<br /> 回転成分と拡大縮小成分は互いに行列の要素位置がダブっているので<br /> ただ単に代入する事はできません。<br /> 平行移動成分と同様にして回転成分と拡大縮小成分に関しても計算回数を<br /> 減らす事はできないでしょうか?</strong></p> <p><strong>ここで一つの実験をしてみます。<br /> それは、1行列(全要素が1の4×4行列)に glScalef を実行してみる<br /> という物です。</strong></p> <p><img alt="" src="http://www21.atwiki.jp/opengl?cmd=upload&amp;act=open&amp;pageid=141&amp;file=1.png" /></p> <table width="600" border="1" cellspacing="1" cellpadding="1"><tbody><tr><td> <p>//#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br /> #include &lt;GL/freeglut/freeglut.h&gt;<br /> #include &lt;math.h&gt;<br /> #include &lt;stdio.h&gt;<br /> #define PI 3.1415926</p> <p>#define WIDTH 320<br /> #define HEIGHT 240</p> <p>GLfloat modelview[16];</p> <p>//1行列<br /> GLfloat iti[]={<br />  1,1,1,1,<br />  1,1,1,1,<br />  1,1,1,1,<br />  1,1,1,1<br /> };</p> <p><br /> void matrix_print(char* text)<br /> {<br />  printf(text);<br />  glGetFloatv(GL_MODELVIEW_MATRIX,modelview);<br />  printf("\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n",<br />   modelview[0],modelview[4],modelview[8],modelview[12],<br />   modelview[1],modelview[5],modelview[9],modelview[13],<br />   modelview[2],modelview[6],modelview[10],modelview[14],<br />   modelview[3],modelview[7],modelview[11],modelview[15]);<br /> }<br /> void display(void)<br /> {</p> <p> glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />  glViewport(0, 0, WIDTH, HEIGHT);<br />  glMatrixMode(GL_PROJECTION);<br />  glLoadIdentity();</p> <p> //視野角,アスペクト比(ウィンドウの幅/高さ),描画する範囲(最も近い距離,最も遠い距離)<br />  gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);<br />  glMatrixMode(GL_MODELVIEW);</p> <p> glLoadMatrixf(iti);</p> <p> matrix_print("1行列");</p> <p> glScalef(5.0,3.0,9.0);<br />  matrix_print("拡大縮小");</p> <p> getchar();</p> <p> glutSwapBuffers();<br /> }<br /> void idle(void)<br /> {<br />  glutPostRedisplay();<br /> }<br /> void Init(){<br />  glClearColor(0.3f, 0.3f, 0.3f, 1.0f);<br /> }<br /> int main(int argc, char *argv[])<br /> {<br />  glutInitWindowPosition(100, 100);<br />  glutInitWindowSize(WIDTH, HEIGHT);<br />  glutInit(&amp;argc, argv);<br />  glutCreateWindow("実験");<br />  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />  glutDisplayFunc(display);<br />  glutIdleFunc(idle);<br />  Init();<br />  glutMainLoop();<br />  return 0;<br /> }</p> </td> </tr></tbody></table><p><img alt="" src="http://www21.atwiki.jp/opengl?cmd=upload&amp;act=open&amp;pageid=141&amp;file=iti.png" /></p> <p><strong>すると、このようになったと思います。<br /> 何か、気付いたのではないでしょうか?<br /> これは列方向にX、Y、Zの各軸の拡大縮小を掛けたように見えます。<br /> glScalef の動作がわかりましたね?<br /></strong></p> <p><strong>以上の事から次のように計算回数を減らす事が可能です。</strong></p> <table width="600" border="1" cellspacing="1" cellpadding="1"><tbody><tr><td> <p><strong>pos_x,y,z…平行移動<br /> rotate_x,y,z…回転<br /> scale_x,y,z…拡大縮小</strong></p> <p><strong>SX = sin(2*π*rotate_x/360)<br /> SY = sin(2*π*rotate_y/360)<br /> SZ = sin(2*π*rotate_z/360)</strong></p> <p><strong>CX = cos(2*π*rotate_x/360)<br /> CY = cos(2*π*rotate_y/360)<br /> CZ = cos(2*π*rotate_z/360)</strong></p> <p><strong>として、</strong></p> <p><strong>mat_11=(CY*CZ)*scale_x<br /> mat_12=(CY*SZ)*scale_x<br /> mat_13=-SY*scale_x<br /> mat_14=0<br /> mat_21=((SX*SY*CZ)-(CX*SZ))*scale_y<br /> mat_22=((SX*SY*SZ)+(CX*CZ))*scale_y<br /> mat_23=(SX*CY)*scale_y<br /> mat_24=0<br /> mat_31=((CX*SY*CZ)+(SX*SZ))*scale_z<br /> mat_32=((CX*SY*SZ)-(SX*CZ))*scale_z<br /> mat_33=(CX*CY)*scale_z<br /> mat_34=0<br /> mat_41=pos_x<br /> mat_42=pos_y<br /> mat_43=pos_z<br /> mat_44=1</strong></p> </td> </tr></tbody></table><p><strong>9回の計算と7回の代入まで減らす事ができます。<br /> ただし、回転する順番はXYZの順のみです。(OpenGLの場合は逆方向)<br /> 更に、行列を掛け合わせる順番も拡大縮小、回転、<br /> 平行移動の順のみです。(OpenGLの場合は逆方向)</strong></p> <table width="600" border="1" cellspacing="1" cellpadding="1"><tbody><tr><td> <p><span style="font-size:small;">//#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br />  #include &lt;GL/freeglut/freeglut.h&gt;<br />  #include &lt;math.h&gt;<br />  #include &lt;stdio.h&gt;<br />  #define PI 3.1415926<br />  <br />  #define WIDTH 320<br />  #define HEIGHT 240</span></p> <p><span style="font-size:small;">#define SX sin(2*PI*rotate_x/360.0f)<br /> #define SY sin(2*PI*rotate_y/360.0f)<br /> #define SZ sin(2*PI*rotate_z/360.0f)</span></p> <p><span style="font-size:small;">#define CX cos(2*PI*rotate_x/360.0f)<br /> #define CY cos(2*PI*rotate_y/360.0f)<br /> #define CZ cos(2*PI*rotate_z/360.0f)<br />  <br /> //マトリクス構造体<br />  struct MATRIX {<br />      union {<br />          struct {<br />              float _11, _12, _13, _14;<br />              float _21, _22, _23, _24;<br />              float _31, _32, _33, _34;<br />              float _41, _42, _43, _44;<br />          };<br />          float mat_4x4[4][4];<br />          float mat_16[16];<br />      };<br />   MATRIX(){//単位行列に初期化<br />    INIT();<br />   }<br />   void INIT(){<br />  for(int i=0;i&lt;16;i++){<br />     this-&gt;mat_16[i]=0;<br />    }<br />    this-&gt;_11=this-&gt;_22=this-&gt;_33=this-&gt;_44=1;<br />   }<br />   void PRINT(char* text){<br />    printf("%s\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n\n",<br />     text,<br />     this-&gt;_11,this-&gt;_21,this-&gt;_31,this-&gt;_41,<br />     this-&gt;_12,this-&gt;_22,this-&gt;_32,this-&gt;_42,<br />     this-&gt;_13,this-&gt;_23,this-&gt;_33,this-&gt;_43,<br />     this-&gt;_14,this-&gt;_24,this-&gt;_34,this-&gt;_44);<br />   }<br />   void Efficient_Synthesize(float pos_x,float pos_y,float pos_z,float rotate_x,float rotate_y,float rotate_z,float scale_x,float scale_y,float scale_z){<br />    this-&gt;_11=(CY*CZ)*scale_x;<br />    this-&gt;_12=(CY*SZ)*scale_x;<br />    this-&gt;_13=-SY*scale_x;<br />    this-&gt;_14=0;<br />    this-&gt;_21=((SX*SY*CZ)-(CX*SZ))*scale_y;<br />    this-&gt;_22=((SX*SY*SZ)+(CX*CZ))*scale_y;<br />    this-&gt;_23=(SX*CY)*scale_y;<br />    this-&gt;_24=0;<br />    this-&gt;_31=((CX*SY*CZ)+(SX*SZ))*scale_z;<br />    this-&gt;_32=((CX*SY*SZ)-(SX*CZ))*scale_z;<br />    this-&gt;_33=(CX*CY)*scale_z;<br />    this-&gt;_34=0;<br />    this-&gt;_41=pos_x;<br />    this-&gt;_42=pos_y;<br />    this-&gt;_43=pos_z;<br />    this-&gt;_44=1;<br />   }<br />  };</span></p> <p><span style="font-size:small;">MATRIX mat;</span></p> <p><span style="font-size:small;"> void display(void)<br />  {<br />  <br />  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />   glViewport(0, 0, WIDTH, HEIGHT);<br />   glMatrixMode(GL_PROJECTION);<br />   glLoadIdentity();<br />  <br />  //視野角,アスペクト比(ウィンドウの幅/高さ),描画する範囲(最も近い距離,最も遠い距離)<br />   gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);<br />   glMatrixMode(GL_MODELVIEW);</span></p> <p><span style="font-size:small;"> glLoadIdentity();</span></p> <p><span style="font-size:small;"> glTranslatef(12.0f,55.0f,-90.0f);<br />  glRotatef(50.0f,0.0f,0.0f,1.0f);<br />  glRotatef(50.0f,0.0f,1.0f,0.0f);<br />  glRotatef(50.0f,1.0f,0.0f,0.0f);<br />  glScalef(5.0f,3.0f,9.0f);<br />  glGetFloatv(GL_MODELVIEW_MATRIX,&amp;mat.mat_16[0]);<br />  mat.PRINT("各種アフィン変換で合成行列作成");<br />  glLoadIdentity();</span></p> <p><span style="font-size:small;"> mat.INIT();<br />  mat.Efficient_Synthesize(12.0f,55.0f,-90.0f,50.0f,50.0f,50.0f,5.0f,3.0f,9.0f);<br />  mat.PRINT("効率のよい合成で同じ結果になるか?");<br />  <br />  getchar();<br />  <br />  glutSwapBuffers();<br />  }<br />  void idle(void)<br />  {<br />   glutPostRedisplay();<br />  }<br />  void Init(){<br />   glClearColor(0.3f, 0.3f, 0.3f, 1.0f);<br />  }<br />  int main(int argc, char *argv[])<br />  {<br />   glutInitWindowPosition(100, 100);<br />   glutInitWindowSize(10, 10);<br />   glutInit(&amp;argc, argv);<br />   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />   glutCreateWindow("効率の良い合成");<br />   glutDisplayFunc(display);<br />   glutIdleFunc(idle);<br />   Init();<br />   glutMainLoop();<br />   return 0;<br />  }</span></p> </td> </tr></tbody></table><p> </p> <p> </p> <p> </p> <p> </p>
<p><strong>行列同士は行列の積を行うと合成する事ができます。<br /> しかし、4×4行列の積は16回も計算しなければなりません。<br /> 平行移動成分と回転成分、拡大縮小成分を合成するのに<br /> 32回も計算するのでしょうか?</strong></p> <p><strong>平行移動成分は回転成分と拡大縮小成分に影響しないので3回の代入で<br /> 済ます事ができます。<br /> 回転成分と拡大縮小成分は互いに行列の要素位置がダブっているので<br /> ただ単に代入する事はできません。<br /> 平行移動成分と同様にして回転成分と拡大縮小成分に関しても計算回数を<br /> 減らす事はできないでしょうか?</strong></p> <p><strong>ここで一つの実験をしてみます。<br /> それは、1行列(全要素が1の4×4行列)に glScalef を実行してみる<br /> という物です。</strong></p> <p><img alt="" src="http://cdn21.atwikiimg.com/opengl?cmd=upload&amp;act=open&amp;pageid=141&amp;file=1.png" /></p> <table border="1" cellpadding="1" cellspacing="1" width="600"><tbody><tr><td> <p>//#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br /> #include &lt;GL/freeglut/freeglut.h&gt;<br /> #include &lt;math.h&gt;<br /> #include &lt;stdio.h&gt;<br /> #define PI 3.1415926</p> <p>#define WIDTH 320<br /> #define HEIGHT 240</p> <p>GLfloat modelview[16];</p> <p>//1行列<br /> GLfloat iti[]={<br />  1,1,1,1,<br />  1,1,1,1,<br />  1,1,1,1,<br />  1,1,1,1<br /> };</p> <p><br /> void matrix_print(char* text)<br /> {<br />  printf(text);<br />  glGetFloatv(GL_MODELVIEW_MATRIX,modelview);<br />  printf("\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n",<br />   modelview[0],modelview[4],modelview[8],modelview[12],<br />   modelview[1],modelview[5],modelview[9],modelview[13],<br />   modelview[2],modelview[6],modelview[10],modelview[14],<br />   modelview[3],modelview[7],modelview[11],modelview[15]);<br /> }<br /> void display(void)<br /> {</p> <p> glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />  glViewport(0, 0, WIDTH, HEIGHT);<br />  glMatrixMode(GL_PROJECTION);<br />  glLoadIdentity();</p> <p> //視野角,アスペクト比(ウィンドウの幅/高さ),描画する範囲(最も近い距離,最も遠い距離)<br />  gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);<br />  glMatrixMode(GL_MODELVIEW);</p> <p> glLoadMatrixf(iti);</p> <p> matrix_print("1行列");</p> <p> glScalef(5.0,3.0,9.0);<br />  matrix_print("拡大縮小");</p> <p> getchar();</p> <p> glutSwapBuffers();<br /> }<br /> void idle(void)<br /> {<br />  glutPostRedisplay();<br /> }<br /> void Init(){<br />  glClearColor(0.3f, 0.3f, 0.3f, 1.0f);<br /> }<br /> int main(int argc, char *argv[])<br /> {<br />  glutInitWindowPosition(100, 100);<br />  glutInitWindowSize(WIDTH, HEIGHT);<br />  glutInit(&amp;argc, argv);<br />  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />  glutCreateWindow("実験");<br />  glutDisplayFunc(display);<br />  glutIdleFunc(idle);<br />  Init();<br />  glutMainLoop();<br />  return 0;<br /> }</p> </td> </tr></tbody></table><p><img alt="" src="http://cdn21.atwikiimg.com/opengl?cmd=upload&amp;act=open&amp;pageid=141&amp;file=iti.png" /></p> <p><strong>すると、このようになったと思います。<br /> 何か、気付いたのではないでしょうか?<br /> これは列方向にX、Y、Zの各軸の拡大縮小を掛けたように見えます。<br /> glScalef の動作がわかりましたね?</strong></p> <p><strong>以上の事から次のように計算回数を減らす事が可能です。</strong></p> <table border="1" cellpadding="1" cellspacing="1" width="600"><tbody><tr><td> <p><strong>pos_x,y,z…平行移動<br /> rotate_x,y,z…回転<br /> scale_x,y,z…拡大縮小</strong></p> <p><strong>SX = sin(2*π*rotate_x/360)<br /> SY = sin(2*π*rotate_y/360)<br /> SZ = sin(2*π*rotate_z/360)</strong></p> <p><strong>CX = cos(2*π*rotate_x/360)<br /> CY = cos(2*π*rotate_y/360)<br /> CZ = cos(2*π*rotate_z/360)</strong></p> <p><strong>として、</strong></p> <p><strong>mat_11=(CY*CZ)*scale_x<br /> mat_12=(CY*SZ)*scale_x<br /> mat_13=-SY*scale_x<br /> mat_14=0<br /> mat_21=((SX*SY*CZ)-(CX*SZ))*scale_y<br /> mat_22=((SX*SY*SZ)+(CX*CZ))*scale_y<br /> mat_23=(SX*CY)*scale_y<br /> mat_24=0<br /> mat_31=((CX*SY*CZ)+(SX*SZ))*scale_z<br /> mat_32=((CX*SY*SZ)-(SX*CZ))*scale_z<br /> mat_33=(CX*CY)*scale_z<br /> mat_34=0<br /> mat_41=pos_x<br /> mat_42=pos_y<br /> mat_43=pos_z<br /> mat_44=1</strong></p> </td> </tr></tbody></table><p><strong>9回の計算と7回の代入まで減らす事ができます。<br /> ただし、回転する順番はXYZの順のみです。(OpenGLの場合は逆方向)<br /> 更に、行列を掛け合わせる順番も拡大縮小、回転、<br /> 平行移動の順のみです。(OpenGLの場合は逆方向)</strong></p> <table border="1" cellpadding="1" cellspacing="1" width="600"><tbody><tr><td> <p>//#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br /> #include &lt;GL/freeglut/freeglut.h&gt;<br /> #include &lt;math.h&gt;<br /> #include &lt;stdio.h&gt;<span style="font-size:small;"><br />  #define PI 3.1415926<br />  <br />  #define WIDTH 320<br />  #define HEIGHT 240</span></p> <p><span style="font-size:small;">#define SX sin(2*PI*rotate_x/360.0f)<br /> #define SY sin(2*PI*rotate_y/360.0f)<br /> #define SZ sin(2*PI*rotate_z/360.0f)</span></p> <p><span style="font-size:small;">#define CX cos(2*PI*rotate_x/360.0f)<br /> #define CY cos(2*PI*rotate_y/360.0f)<br /> #define CZ cos(2*PI*rotate_z/360.0f)<br />  <br /> //マトリクス構造体<br />  struct MATRIX {<br />      union {<br />          struct {<br />              float _11, _12, _13, _14;<br />              float _21, _22, _23, _24;<br />              float _31, _32, _33, _34;<br />              float _41, _42, _43, _44;<br />          };<br />          float mat_4x4[4][4];<br />          float mat_16[16];<br />      };<br />   MATRIX(){//単位行列に初期化<br />    INIT();<br />   }<br />   void INIT(){<br />  for(int i=0;i&lt;16;i++){<br />     this-&gt;mat_16[i]=0;<br />    }<br />    this-&gt;_11=this-&gt;_22=this-&gt;_33=this-&gt;_44=1;<br />   }<br />   void PRINT(char* text){<br />    printf("%s\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n\n",<br />     text,<br />     this-&gt;_11,this-&gt;_21,this-&gt;_31,this-&gt;_41,<br />     this-&gt;_12,this-&gt;_22,this-&gt;_32,this-&gt;_42,<br />     this-&gt;_13,this-&gt;_23,this-&gt;_33,this-&gt;_43,<br />     this-&gt;_14,this-&gt;_24,this-&gt;_34,this-&gt;_44);<br />   }<br />   void Efficient_Synthesize(float pos_x,float pos_y,float pos_z,float rotate_x,float rotate_y,float rotate_z,float scale_x,float scale_y,float scale_z){<br />    this-&gt;_11=(CY*CZ)*scale_x;<br />    this-&gt;_12=(CY*SZ)*scale_x;<br />    this-&gt;_13=-SY*scale_x;<br />    this-&gt;_14=0;<br />    this-&gt;_21=((SX*SY*CZ)-(CX*SZ))*scale_y;<br />    this-&gt;_22=((SX*SY*SZ)+(CX*CZ))*scale_y;<br />    this-&gt;_23=(SX*CY)*scale_y;<br />    this-&gt;_24=0;<br />    this-&gt;_31=((CX*SY*CZ)+(SX*SZ))*scale_z;<br />    this-&gt;_32=((CX*SY*SZ)-(SX*CZ))*scale_z;<br />    this-&gt;_33=(CX*CY)*scale_z;<br />    this-&gt;_34=0;<br />    this-&gt;_41=pos_x;<br />    this-&gt;_42=pos_y;<br />    this-&gt;_43=pos_z;<br />    this-&gt;_44=1;<br />   }<br />  };</span></p> <p><span style="font-size:small;">MATRIX mat;</span></p> <p><span style="font-size:small;"> void display(void)<br />  {<br />  <br />  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />   glViewport(0, 0, WIDTH, HEIGHT);<br />   glMatrixMode(GL_PROJECTION);<br />   glLoadIdentity();<br />  <br />  //視野角,アスペクト比(ウィンドウの幅/高さ),描画する範囲(最も近い距離,最も遠い距離)<br />   gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);<br />   glMatrixMode(GL_MODELVIEW);</span></p> <p><span style="font-size:small;"> glLoadIdentity();</span></p> <p><span style="font-size:small;"> glTranslatef(12.0f,55.0f,-90.0f);<br />  glRotatef(50.0f,0.0f,0.0f,1.0f);<br />  glRotatef(50.0f,0.0f,1.0f,0.0f);<br />  glRotatef(50.0f,1.0f,0.0f,0.0f);<br />  glScalef(5.0f,3.0f,9.0f);<br />  glGetFloatv(GL_MODELVIEW_MATRIX,&amp;mat.mat_16[0]);<br />  mat.PRINT("各種アフィン変換で合成行列作成");<br />  glLoadIdentity();</span></p> <p><span style="font-size:small;"> mat.INIT();<br />  mat.Efficient_Synthesize(12.0f,55.0f,-90.0f,50.0f,50.0f,50.0f,5.0f,3.0f,9.0f);<br />  mat.PRINT("効率のよい合成で同じ結果になるか?");<br />  <br />  getchar();<br />  <br />  glutSwapBuffers();<br />  }<br />  void idle(void)<br />  {<br />   glutPostRedisplay();<br />  }<br />  void Init(){<br />   glClearColor(0.3f, 0.3f, 0.3f, 1.0f);<br />  }<br />  int main(int argc, char *argv[])<br />  {<br />   glutInitWindowPosition(100, 100);<br />   glutInitWindowSize(10, 10);<br />   glutInit(&amp;argc, argv);<br />   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />   glutCreateWindow("効率の良い合成");<br />   glutDisplayFunc(display);<br />   glutIdleFunc(idle);<br />   Init();<br />   glutMainLoop();<br />   return 0;<br />  }</span></p> </td> </tr></tbody></table><p> </p> <p> </p> <p> </p> <p> </p>

表示オプション

横に並べて表示:
変化行の前後のみ表示: