「球面線形補間」の編集履歴(バックアップ)一覧はこちら
「球面線形補間」(2014/04/16 (水) 19:26:16) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
<p><strong>クォータニオンとクォータニオンを補間するには<br />
『球面線形補間』を使います。</strong></p>
<p><img alt="" src="http://www21.atwiki.jp/opengl?cmd=upload&act=open&pageid=149&file=lin.png" /></p>
<table border="1" cellspacing="1" cellpadding="1" width="600"><tbody><tr><td>
<p>#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br />
#include <GL/freeglut/freeglut.h><br />
#include <stdio.h><br />
#include <math.h></p>
<p>#define WIDTH 320<br />
#define HEIGHT 240</p>
<p>#define PAI 3.14159</p>
<p>//黄色<br />
GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0};</p>
<p>bool flag=true;<br />
float t=0.0f;</p>
<p>struct Vector3f{<br />
float x;<br />
float y;<br />
float z;<br />
}vec3d;</p>
<p>//クォータニオン構造体<br />
struct Quaternion{<br />
float w;<br />
float x;<br />
float y;<br />
float z;<br />
}qua;</p>
<p>//マトリクス構造体<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 />
for(int i=0;i<16;i++){<br />
this->mat_16[i]=0;<br />
}<br />
this->_11=this->_22=this->_33=this->_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->_11,this->_21,this->_31,this->_41,<br />
this->_12,this->_22,this->_32,this->_42,<br />
this->_13,this->_23,this->_33,this->_43,<br />
this->_14,this->_24,this->_34,this->_44);<br />
}<br />
};</p>
<p><br />
//任意軸回転をクォータニオンにする<br />
Quaternion RotateToQuaternion(Vector3f vAxis,float Angle)<br />
{<br />
Quaternion q;<br />
float radian = (float)(Angle * (PAI / 180.0) / 2.0);<br />
float s = sin(radian);<br />
q.w=cos(radian);<br />
q.x=vAxis.x*s;<br />
q.y=vAxis.y*s;<br />
q.z=vAxis.z*s;<br />
return q;<br />
}</p>
<p>//クォータニオンを回転行列にする<br />
MATRIX QuaternionToMatrix(Quaternion q){<br />
MATRIX ret;<br />
float sx = q.x * q.x;<br />
float sy = q.y * q.y;<br />
float sz = q.z * q.z;<br />
float cx = q.y * q.z;<br />
float cy = q.x * q.z;<br />
float cz = q.x * q.y;<br />
float wx = q.w * q.x;<br />
float wy = q.w * q.y;<br />
float wz = q.w * q.z;</p>
<p> ret._11= 1.0f - 2.0f * (sy + sz);<br />
ret._12= 2.0f * (cz + wz);<br />
ret._13= 2.0f * (cy - wy);<br />
ret._21= 2.0f * (cz - wz);<br />
ret._22= 1.0f - 2.0f * (sx + sz);<br />
ret._23= 2.0f * (cx + wx);<br />
ret._31= 2.0f * (cy + wy);<br />
ret._32= 2.0f * (cx - wx);<br />
ret._33= 1.0f - 2.0f * (sx + sy);<br />
ret._41= 0.0f;<br />
ret._42= 0.0f;<br />
ret._43= 0.0f;<br />
return ret;<br />
}</p>
<p>//回転行列をクォータニオンにする<br />
Quaternion MatrixToQuaternion(MATRIX mat){<br />
Quaternion q;</p>
<p> float s;<br />
float tr = mat._11 + mat._22 + mat._33 + 1.0f;<br />
if (tr >= 1.0f) {<br />
s = 0.5f / sqrt(tr);<br />
q.w= 0.25f / s;<br />
q.x= (mat._23 - mat._32) * s;<br />
q.y= (mat._31 - mat._13) * s;<br />
q.z= (mat._12 - mat._21) * s;<br />
return q;<br />
}else{<br />
float max;<br />
if(mat._22 > mat._33){<br />
max = mat._22;<br />
}else{<br />
max = mat._33;<br />
}<br />
<br />
if (max < mat._11) {<br />
s = sqrt(mat._11 - (mat._22 + mat._33) + 1.0f);<br />
float x = s * 0.5f;<br />
s = 0.5f / s;<br />
q.x= x;<br />
q.y= (mat._12 + mat._21) * s;<br />
q.z= (mat._31 + mat._13) * s;<br />
q.w= (mat._23 - mat._32) * s;<br />
return q;<br />
}else if (max == mat._22) {<br />
s = sqrt(mat._22 - (mat._33 + mat._11) + 1.0f);<br />
float y = s * 0.5f;<br />
s = 0.5f / s;<br />
q.x= (mat._12 + mat._21) * s;<br />
q.y= y;<br />
q.z= (mat._23 + mat._32) * s;<br />
q.w= (mat._31 - mat._13) * s;<br />
return q;<br />
}else{<br />
s = sqrt(mat._33 - (mat._11 + mat._22) + 1.0f);<br />
float z = s * 0.5f;<br />
s = 0.5f / s;<br />
q.x= (mat._31 + mat._13) * s;<br />
q.y= (mat._23 + mat._32) * s;<br />
q.z= z;<br />
q.w= (mat._12 - mat._21) * s;<br />
return q;<br />
}<br />
}<br />
}</p>
<p>//球面線形補間<br />
Quaternion Spherical_Linear_Interpolation( Quaternion q1, Quaternion q2, float
t)<br />
{<br />
Quaternion q;<br />
float qr = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;<br />
float ss = 1.0f - qr * qr;<br />
<br />
if (ss == 0.0f) {<br />
q.w = q1.w;<br />
q.x = q1.x;<br />
q.y = q1.y;<br />
q.z = q1.z;<br />
return q;<br />
}<br />
else {<br />
float sp = sqrt(ss);<br />
float ph = acos(qr);<br />
float pt = ph * t;<br />
float t1 = sin(pt) / sp;<br />
float t0 = sin(ph - pt) / sp;<br />
<br />
q.w = q1.w * t0 + q2.w * t1;<br />
q.x = q1.x * t0 + q2.x * t1;<br />
q.y = q1.y * t0 + q2.y * t1;<br />
q.z = q1.z * t0 + q2.z * t1;<br />
return q;<br />
}<br />
}</p>
<p><br />
MATRIX model;</p>
<p>void display(void)<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 />
gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);<br />
glMatrixMode(GL_MODELVIEW);</p>
<p> glLoadIdentity();</p>
<p> glRotatef(36.8f,1.0f,0.0f,0.0f);<br />
glGetFloatv(GL_MODELVIEW_MATRIX,&model.mat_16[0]);<br />
Quaternion q1=MatrixToQuaternion(model);</p>
<p> glLoadIdentity();</p>
<p> glRotatef(240.4f,0.0f,1.0f,0.0f);<br />
glGetFloatv(GL_MODELVIEW_MATRIX,&model.mat_16[0]);<br />
Quaternion q2=MatrixToQuaternion(model);</p>
<p> Quaternion q3=Spherical_Linear_Interpolation(q1,q2,t);<br />
MATRIX mat=QuaternionToMatrix(q3);</p>
<p> glLoadIdentity();<br />
gluLookAt(0.0,500.0,500.0,<br />
0.0,0.0,0.0,<br />
0.0,1.0,0.0);</p>
<p> glMultMatrixf(&mat.mat_16[0]);<br />
glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow);<br />
glutSolidCube(150.0);</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 />
glEnable(GL_DEPTH_TEST);<br />
glEnable(GL_LIGHTING);<br />
glEnable(GL_LIGHT0);<br />
}</p>
<p>void timer(int value) {<br />
if(t>1.0f)flag=false;<br />
if(t<0.0f)flag=true;<br />
if(flag){t+=0.01f;}else{t-=0.01f;}<br />
glutTimerFunc(10 , timer , 0);<br />
}</p>
<p>int main(int argc, char *argv[])<br />
{<br />
glutInitWindowPosition(100, 100);<br />
glutInitWindowSize(WIDTH, HEIGHT);<br />
glutInit(&argc, argv);<br />
glutCreateWindow("球面線形補間");<br />
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />
glutDisplayFunc(display);<br />
glutIdleFunc(idle);<br />
glutTimerFunc(10 , timer , 0);<br />
Init();<br />
glutMainLoop();<br />
return 0;<br />
}</p>
</td>
</tr></tbody></table><p> </p>
<p> </p>
<p> </p>
<p><strong>クォータニオンとクォータニオンを補間するには<br />
『球面線形補間』を使います。</strong></p>
<p><img alt="" src="http://cdn21.atwikiimg.com/opengl?cmd=upload&act=open&pageid=149&file=lin.png" /></p>
<table border="1" cellpadding="1" cellspacing="1" width="600"><tbody><tr><td>
<p>#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br />
#include <GL/freeglut/freeglut.h><br />
#include <stdio.h><br />
#include <math.h></p>
<p>#define WIDTH 320<br />
#define HEIGHT 240</p>
<p>#define PAI 3.14159</p>
<p>//黄色<br />
GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0};</p>
<p>bool flag=true;<br />
float t=0.0f;</p>
<p>struct Vector3f{<br />
float x;<br />
float y;<br />
float z;<br />
}vec3d;</p>
<p>//クォータニオン構造体<br />
struct Quaternion{<br />
float w;<br />
float x;<br />
float y;<br />
float z;<br />
}qua;</p>
<p>//マトリクス構造体<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 />
for(int i=0;i<16;i++){<br />
this->mat_16[i]=0;<br />
}<br />
this->_11=this->_22=this->_33=this->_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->_11,this->_21,this->_31,this->_41,<br />
this->_12,this->_22,this->_32,this->_42,<br />
this->_13,this->_23,this->_33,this->_43,<br />
this->_14,this->_24,this->_34,this->_44);<br />
}<br />
};</p>
<p><br />
//任意軸回転をクォータニオンにする<br />
Quaternion RotateToQuaternion(Vector3f vAxis,float Angle)<br />
{<br />
Quaternion q;<br />
float radian = (float)(Angle * (PAI / 180.0) / 2.0);<br />
float s = sin(radian);<br />
q.w=cos(radian);<br />
q.x=vAxis.x*s;<br />
q.y=vAxis.y*s;<br />
q.z=vAxis.z*s;<br />
return q;<br />
}</p>
<p>//クォータニオンを回転行列にする<br />
MATRIX QuaternionToMatrix(Quaternion q){<br />
MATRIX ret;<br />
float sx = q.x * q.x;<br />
float sy = q.y * q.y;<br />
float sz = q.z * q.z;<br />
float cx = q.y * q.z;<br />
float cy = q.x * q.z;<br />
float cz = q.x * q.y;<br />
float wx = q.w * q.x;<br />
float wy = q.w * q.y;<br />
float wz = q.w * q.z;</p>
<p> ret._11= 1.0f - 2.0f * (sy + sz);<br />
ret._12= 2.0f * (cz + wz);<br />
ret._13= 2.0f * (cy - wy);<br />
ret._21= 2.0f * (cz - wz);<br />
ret._22= 1.0f - 2.0f * (sx + sz);<br />
ret._23= 2.0f * (cx + wx);<br />
ret._31= 2.0f * (cy + wy);<br />
ret._32= 2.0f * (cx - wx);<br />
ret._33= 1.0f - 2.0f * (sx + sy);<br />
ret._41= 0.0f;<br />
ret._42= 0.0f;<br />
ret._43= 0.0f;<br />
return ret;<br />
}</p>
<p>//回転行列をクォータニオンにする<br />
Quaternion MatrixToQuaternion(MATRIX mat){<br />
Quaternion q;</p>
<p> float s;<br />
float tr = mat._11 + mat._22 + mat._33 + 1.0f;<br />
if (tr >= 1.0f) {<br />
s = 0.5f / sqrt(tr);<br />
q.w= 0.25f / s;<br />
q.x= (mat._23 - mat._32) * s;<br />
q.y= (mat._31 - mat._13) * s;<br />
q.z= (mat._12 - mat._21) * s;<br />
return q;<br />
}else{<br />
float max;<br />
if(mat._22 > mat._33){<br />
max = mat._22;<br />
}else{<br />
max = mat._33;<br />
}<br />
<br />
if (max < mat._11) {<br />
s = sqrt(mat._11 - (mat._22 + mat._33) + 1.0f);<br />
float x = s * 0.5f;<br />
s = 0.5f / s;<br />
q.x= x;<br />
q.y= (mat._12 + mat._21) * s;<br />
q.z= (mat._31 + mat._13) * s;<br />
q.w= (mat._23 - mat._32) * s;<br />
return q;<br />
}else if (max == mat._22) {<br />
s = sqrt(mat._22 - (mat._33 + mat._11) + 1.0f);<br />
float y = s * 0.5f;<br />
s = 0.5f / s;<br />
q.x= (mat._12 + mat._21) * s;<br />
q.y= y;<br />
q.z= (mat._23 + mat._32) * s;<br />
q.w= (mat._31 - mat._13) * s;<br />
return q;<br />
}else{<br />
s = sqrt(mat._33 - (mat._11 + mat._22) + 1.0f);<br />
float z = s * 0.5f;<br />
s = 0.5f / s;<br />
q.x= (mat._31 + mat._13) * s;<br />
q.y= (mat._23 + mat._32) * s;<br />
q.z= z;<br />
q.w= (mat._12 - mat._21) * s;<br />
return q;<br />
}<br />
}<br />
}</p>
<p>//球面線形補間<br />
Quaternion Spherical_Linear_Interpolation( Quaternion q1, Quaternion q2, float
t)<br />
{<br />
Quaternion q;<br />
float qr = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;<br />
float ss = 1.0f - qr * qr;<br />
<br />
if (ss == 0.0f) {<br />
q.w = q1.w;<br />
q.x = q1.x;<br />
q.y = q1.y;<br />
q.z = q1.z;<br />
return q;<br />
}<br />
else {<br />
float sp = sqrt(ss);<br />
float ph = acos(qr);<br />
float pt = ph * t;<br />
float t1 = sin(pt) / sp;<br />
float t0 = sin(ph - pt) / sp;<br />
<br />
q.w = q1.w * t0 + q2.w * t1;<br />
q.x = q1.x * t0 + q2.x * t1;<br />
q.y = q1.y * t0 + q2.y * t1;<br />
q.z = q1.z * t0 + q2.z * t1;<br />
return q;<br />
}<br />
}</p>
<p><br />
MATRIX model;</p>
<p>void display(void)<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 />
gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);<br />
glMatrixMode(GL_MODELVIEW);</p>
<p> glLoadIdentity();</p>
<p> glRotatef(36.8f,1.0f,0.0f,0.0f);<br />
glGetFloatv(GL_MODELVIEW_MATRIX,&model.mat_16[0]);<br />
Quaternion q1=MatrixToQuaternion(model);</p>
<p> glLoadIdentity();</p>
<p> glRotatef(240.4f,0.0f,1.0f,0.0f);<br />
glGetFloatv(GL_MODELVIEW_MATRIX,&model.mat_16[0]);<br />
Quaternion q2=MatrixToQuaternion(model);</p>
<p> Quaternion q3=Spherical_Linear_Interpolation(q1,q2,t);<br />
MATRIX mat=QuaternionToMatrix(q3);</p>
<p> glLoadIdentity();<br />
gluLookAt(0.0,500.0,500.0,<br />
0.0,0.0,0.0,<br />
0.0,1.0,0.0);</p>
<p> glMultMatrixf(&mat.mat_16[0]);<br />
glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow);<br />
glutSolidCube(150.0);</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 />
glEnable(GL_DEPTH_TEST);<br />
glEnable(GL_LIGHTING);<br />
glEnable(GL_LIGHT0);<br />
}</p>
<p>void timer(int value) {<br />
if(t>1.0f)flag=false;<br />
if(t<0.0f)flag=true;<br />
if(flag){t+=0.01f;}else{t-=0.01f;}<br />
glutTimerFunc(10 , timer , 0);<br />
}</p>
<p>int main(int argc, char *argv[])<br />
{<br />
glutInitWindowPosition(100, 100);<br />
glutInitWindowSize(WIDTH, HEIGHT);<br />
glutInit(&argc, argv);<br />
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />
glutCreateWindow("球面線形補間");<br />
glutDisplayFunc(display);<br />
glutIdleFunc(idle);<br />
glutTimerFunc(10 , timer , 0);<br />
Init();<br />
glutMainLoop();<br />
return 0;<br />
}</p>
</td>
</tr></tbody></table><p> </p>
<p> </p>
<p> </p>