スライド資料

座標系の設定
2次元座標変換
y
人差指
• OpenGLでは基本は右手座標系
• 座標系
中指
– 2次元、3次元の区別はしていない
z
– z軸正方向が手前になっている
– x軸正方向は右、y軸正方向は上
• 平行移動、回転、拡大縮小、鏡映
• 合成変換、アフィン変換
• 同次座標系、変換行列
– 空間に配置されたオブジェクトを統合する座標系
• ダブルバッファリングによるちらつきのない動画
• モデリング座標系(オブジェクト座標系)
– 物体を定義する座標系
• 解析幾何の基本事項
1
( x, y)
q
y'
y
y
0
x'
0
0
点の回転は、入れ替えた座標系の回転と等価
変換前座標系
y cosq
x
q
y q
変換前座標系
q
y' = x sinq + y cosq
y'
y ' ( x, y) = ( x' , y ' )
x
=
x
0
( x' , y' )
x sin q
q
x
x'
x'
x cosq
x'
x'
変換後座標系
x' = x cosq - y sin q
æ X ö æ x ö æaö
çç ÷÷ = çç ÷÷ + çç ÷÷
è Y ø è yø èbø
• 回転変換
Q( X , Y )
b
x' = x cos q - y sin q
y ' = x sin q + y cos q
• 拡大縮小変換
X = s×x
Y =t×y
3
0
y
x
a
Q( X , Y )
θ
y
t
Q( X , Y )
1
P( x, y)
0
- sin q öæ x ö
÷ç ÷
cosq ÷øçè y ÷ø
P( x, y)
æaö
ここで çç ÷÷ は移動量ベクトル
èbø
X = x cos q - y sin q
Y = x sin q + y cos q
点の回転の変換式
æ x' ö æ cosq
çç ÷÷ = çç
è y ' ø è sin q
2
• 平行移動変換
変換後座標系
行列表現では
y sin q
y
– x軸正方向は右、y軸正方向は下
点Pから点Qへ座標変換
y
2次元回転変換の式の導出
y'
x
0
• デバイス座標系
( x' , y' )
x
• ワールド座標系
• 変換処理とプログラムコード
y
親指
0
P( x, y)
x
0
1 s
x
• 上記の変換式は表現形式が異なる
– 高速演算では形式を統一化したい
4
1
座標変換行列(1/2)
2次元座標変換の統一形式
y
• 平行移動変換(PからQへ)
• モデリング座標系で定義された点群を
変換行列で、ワールド座標系に変換する
Y
( X ,Y )
0
X
ワールド座標系
é xù
éX ù
ê Y ú = æç 座標変換 ö÷ê y ú
÷ê ú
ê ú ç 行列
øê 1 ú
è
ë û
ëê 1 ûú
– 本来2次元ベクトルの加算で済む
é X ù æ 1 0 a öé x ù
ê Y ú = ç 0 1 b ÷ê y ú
÷ê ú
ê ú ç
êë 1 úû çè 0 0 1 ÷ø êë 1 úû
y
• 回転変換
( x, y )
x
0
– 原点中心
– 原点中心
– 座標変換形式を統一化できる
– 無限遠点を表現できる
• 鏡映変換
– y軸に関して
– 直線y=xに関して
③
p öæ cosq
֍
q ֍ sin q
1 ÷øçè 0
• アフィン変換
éX ù æa b
êY ú = ç d e
ê ú ç
êë 1 úû çè 0 0
c öé x ù
÷
f ÷êê y úú
1 ÷øêë 1 úû
cos q
0
②
0 öæ 1 0 - p öé x ù
֍
÷
0 ÷ç 0 1 - q ÷êê y úú
1 ÷øçè 0 0 1 ÷øêë 1 úû
①
0
y
0 öé x ù
÷
0 ÷êê y úú
1 ÷øêë 1 úû
é X ù æ s 0 0 öé x ù
ê Y ú = ç 0 t 0 ÷ê yú
÷ê ú
ê ú ç
ç
÷
ëê 1 ûú è 0 0 1 ø êë 1 ûú
Q' ( X ' , Y ' )
Q( X , Y )
θ
P( x, y)
x
0
y
t
Q( X , Y )
1
P( x, y)
x
1 s
6
P( x, y)
y=x
Q' ' ( X ' ' , Y ' ' )
0
x
y
③
• 変換前後の位置を結ぶ
ベクトルで表現する
( X ,Y )
( x, y )
æ X ö æ cos q
çç ÷÷ = çç
è Y ø è sin q
- sin q öæ x ö
÷ç ÷
cos q ÷øçè y ÷ø
q = p / 6 の場合
y
( - sin q , cos q )
(cos q , sin q )
Q( X , Y )
②θ θ
q
0
x
a
回転変換行列の特性
y
é X ' 'ù æ 0 1 0 ö é x ù
ê Y ' ' ú = ç 1 0 0 ÷ê y ú
÷ê ú
ê ú ç
êë 1 úû çè 0 0 1 ÷ø êë 1 úû
- sin q
cos q
P( x, y)
0
0
• 合成変換(原点以外の点周りの回転変換)
é X ù æ1 0
êY ú = ç 0 1
ê ú ç
êë 1 úû çè 0 0
- sin q
b
5
座標変換行列(2/2)
é X 'ù æ - 1 0 0 öé x ù
ê Y ' ú = ç 0 1 0 ÷ê y ú
÷ê ú
ê ú ç
ç
÷
ëê 1 ûú è 0 0 1 øêë 1 ûú
é X ù æ cos q
ê Y ú = ç sin q
ê ú ç
êë 1 úû çè 0
• 拡大縮小変換
モデリング座標系
• 同次座標系
Q( X , Y )
P( x, y)
①
x
p
æ1ö
1. xy 座標系の ççè 0 ÷÷ø ベクトルを XY 座標系で見ると
æ0ö
2. xy 座標系の çç 1 ÷÷ ベクトルを XY座標系で見ると
è ø
3. xy 座標系の原点を XY座標系でみると æçç c ö÷÷
èfø
7
æaö
çç ÷÷
èd ø
æbö
çç e ÷÷
è ø
• 実数固有値を持たない
• 各行ベクトル同士、各列
ベクトル同士は直交
• 行列式が1(正方向回転)
• 転置行列が逆行列
• 2次元の場合、可換
( X ,Y )
π/6
x
( x, y )
回転行列の変換特性のベクトル場表現
8
2
モデリング座標系変換のコード化(1/2)
æ 単位 ö
モデリング座標系変換のコード化(2/2)
y
ç
÷
glLoadIdentity( );
この時点での変換行列は çè 行列 ÷ø
rot
glPushMatrix( ); 変換行列をスタックへ保存
yt
glTranslatef( xt, yt,0. ); 回転軸ベクトル(z軸方向)
rot x
glRotatef( rot,0.,0.,1. );
回転角(度単位)
xt
glScalef( 200.,200.,200. );
éxù
éX ù
ê Y ú = æç 単位 ö÷æç 平行 ö÷æç回転 ö÷æç 拡大ö÷ ê y ú
ê ú ç 行列÷ç 移動÷ç 変換 ÷ç 縮小÷ ê ú
glColor3f( 0.,0.,1. );
ø
è
è
ø
ø
è
ø
è
ëê 1 ûú
ëê 1 ûú
glCallList( SQUARE );
この時点での変換行列の中身
glRotatef( rot,0.,0.,1. );
éX ù
éxù
glScalef( 0.6,0.6,0.6 );
ê Y ú = æç 単位 ö÷æç 平行 ö÷æç 回転 ö÷æç 拡大 ö÷æç 回転 ö÷æç 拡大 ö÷ ê y ú
ç
÷
ç
÷
ç
÷
ç
÷
ç
÷
ç
÷
ê
ú
ê ú
行列
移動
縮小
縮小
変換
変換
glColor3f( 0.,1.,0. );
øè
øè
øè
øè
øè
ø ê1 ú
êë 1 úû è
ë û
glCallList( SQUARE );
この時点での変換行列の中身
æ 単位 ö
glPopMatrix();
ç
÷
スタックの中身を変換行列に入れる
この時点での変換行列の中身は çè 行列 ÷ø
æ 単位 ö
y
çç
÷÷
glLoadIdentity( );
è 行列 ø
glPushMatrix( );変換行列をスタックへ保存
yt
glTranslatef( xt, yt,0. );
rot
rot x
glRotatef( rot,0.,0.,1. );
xt
glScalef( 200.,200.,200. ); éê X ùú æ単位 öæ平行 öæ回転 öæ 拡大 öéê x ùú
֍
֍
֍
÷ y
Y =ç
ê ú ç 行列 ÷ç 移動 ÷ç 変換 ÷ç 縮小 ÷ ê ú
øè
øè
øê1 ú
øè
glColor3f( 0.,0.,1. );
êë 1 úû è
ë û
glCallList( SQUARE );
この時点での変換行列の中身
æ 単位 ö
glPopMatrix( );
この時点での変換行列の中身は çç 行列 ÷÷
è
ø
glRotatef( rot,0.,0.,1. );
X
x
é
ù
é
ù
glScalef( 0.6,0.6,0.6 );
ê Y ú = æç 単位 ö÷æç 回転 ö÷æç 拡大 ö÷ ê yú
ê ú ç 行列 ÷ç 変換 ÷ç 縮小 ÷ ê ú
glColor3f( 0.,1.,0. );
øè
øê1ú
øè
êë 1 úû è
ë û
glCallList( SQUARE );
この時点での変換行列の中身
9
変換行列の階層化
モデリング座標系
glLoadIdentity( ); æçç 単位 ö÷÷
è 行列 ø
glPushMatrix( );
glTranslatef( x0,y0,0. ); éê X ùú æ 単位 öæ 車体 öéê x ùú
(x0,y0)
֍
÷ y
Y =ç
ê ú ç 行列÷ç 移動 ÷ê ú
glColor3f( 0.,1.,0. );
è
ø
è
ø
ëê 1 ûú
ëê 1 ûú
glCallList( BODY );
æ 単位 öæ 車体 ö
çç
÷÷çç
÷÷
glPushMatrix( );
(x1,y1) (x2,y1)
è 行列 øè 移動 ø
glTranslatef( x1,y1,0. );
ワールド座標系
glRotatef( rot,0.,0.,1. é);X ù æ 単位 öæ 車体 öæ 前タイヤ öæ 前タイヤ ö é xù
ê ú
ê ú
glColor3f( 1.,0.6,0. ); ê Y ú = ççè 行列 ÷÷øççè 移動 ÷÷øççè 移動 ÷÷øççè回転 ÷÷ø ê yú
êë 1 úû
êë1 úû
glCallList( TIRE );
æ 単位 öæ 車体 ö
glPopMatrix( );
çç
÷÷çç
÷÷
glTranslatef( x2,y1,0. ); è 行列 øè 移動 ø
glRotatef( rot,0.,0.,1. ); éê X ùú æ 単位 öæ 車体 öæ 後タイヤ öæ 後タイヤ öéê x ùú æ 単位 ö
ç
֍
֍
֍
÷
ê Y ú = ç 行列 ÷ç 移動 ÷ç 移動 ÷ç 回転 ÷ê y ú
çç
÷÷
glCallList( TIRE );
è
øè
øè
øè
øê 1 ú
è 行列 ø
ëê 1 ûú
ë û
glPopMatrix( );
11
10
高速描画用ディスプレイリスト化
#define TIRE
1
glNewList( TIRE, GL_COMPILE ); // タイヤ定義始まり
glColor3f( 1.,0.8,0. ); // 茶色
glBegin(GL_TRIANGLE_FAN); // 円板
glVertex2f( 0.,0. );
for( t=0.; t<6.3; t+=0.0625 ) glVertex2f( r*cos(t), r*sin(t) );
glEnd( );
glColor3f( 0.,0.,0. ); // 黒色
glBegin(GL_LINE_LOOP); // 輪郭円定義
for( t=0.; t<6.3; t+=0.0625 ) glVertex2f( r*cos(t), r*sin(t) );
glEnd( );
s = r*0.707;
glBegin(GL_LINES); // スポーク部分定義
glVertex2f( 0.,-r ); glVertex2f( 0.,r ); glVertex2f( -r,0. ); glVertex2f( r,0. );
glVertex2f( -s,-s ); glVertex2f( s,s );glVertex2f( -s,s ); glVertex2f( s,-s );
glEnd( );
glEndList( );
// タイヤ定義終わり
12
3
動画に必要なダブルバッファリング
• 描画と表示は別々の記憶メモリを使う
• 描画し終わったら、
メモリ
アクセスするメモリを 書込み 領域1 表示
切り替える
メモリ
領域2
・ダブルバッファリングの指定
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutSwapBuffers( );
・シングルバッファリングの指定
割込み処理(コールバック)関連の関数例
glutReshapeFunc( (*func)(w, h) )・・再描画
glutPostRedisplay( (*func) ) ・・・再描画
glutMouseFunc( (*func)(b, s, x, y) )・・・マウスクリック
glutMotionFunc( (*func)(x, y) ) ・・・マウスドラッグ
glutKeyboardFunc( (*func)(key, x, y) )・・キー
glutSpecialFunc( (*func)(key, x, y) )・・・矢印キー
glutIdleFunc( (*func) ) ・・・常時動作する関数
glutTimerFunc(time,(*func),0)・・・一定間隔毎動作
*func:関数名
glutInitDisplayMode( GLUT_RGBA | GLUT_SINGLE );
glFlush( );
http://www.cs.uccs.edu/~ssemwal/man.html ・・・glut関数の説明
13
14
OpenGLの座標変換、表示関連関数
• 変換行列
– glTranslatef(x,y,z), glRotatef(angle,x,y,z ), glScalef(s,t,u),
– glLoadIdentity( )
2次元座標系の種類
現在の変換行列に右側から掛ける
度単位(ラジアンではない) 回転軸ベクトル
– 変換行列に直接アクセスする関数:glMultMatrixd(mx),
glLoadMatrixd(mx), glGetFloatd(GL_MODELVIEW_MATRIX, mx)
• 直交座標系
A( Ax , Ay )
( x, y )
– ( x, y )
• 極座標系
– ( r ,θ)
• 変換行列のスタック操作
( r ,θ)
P(α,β,γ) = P( x, y )

b
B(B x , B y )

a
C(C x , C y )
• 重心座標系
– glPushMatrix( ), glPopMatrix( )
• 表示関連(表示リスト、ダブルバッファ)
– glNewList(n,GL_COMPILE), glEndList( ), glCallList( )
– glutInitDisplayMode(・・), glutSwapBuffers( ), glFlush( )
15
P =αA +βB +γC
但し、α+β+γ= 1
0 ≦α,β,γ≦1 ・・①



a = CA, b = CB, p = CP とおくと、



p = a a + b b よりa , b , g は求まる
点 P の三角形内外判定が容 易(①が満たされない とき)
16
4
平面解析幾何(1/2)
平面解析幾何(2/2)
• 2直線: ax + by + c = 0 ,px + qy + r = 0 に於いて
aq - pb
tan q =
ap + bq
q
– なす角θは、
– 特に直交するときは(分母)=0より ap + bq = 0
– 交点を通る直線の式は ax + by + c + k ( px + qy + r ) = 0
ax + by + c
px + qy + r
– 交角を二等分する直線は a + b = ± p + q
2
2
2
2
• 点 ( x , y ) から直線 ax + by + c = 0 までの距離 h は
0
• 3直線
ax0 + by 0 + c
a2 + b2
ax + by + c = 0
lx + my + n = 0
px + qy + r = 0
符号は直線のどちら側かを示す
が1点で交わる条件 a
b
1 =
•
( x1 , y1 ), p 2 = ( x2 , y 2 )
を結ぶ線分上の点
 

p = p1 (1 - t ) + p2t
 
2点 p1 , p2 を m : n


 mp2 + np1 
p=
p1
m+n
(m > n )
m : n

p

m n =0
p
q
r

p2
S =±
符号は頂点を巡る方向の差
17
は
に内分、外分する点はそれぞれ


 mp2 - np1
p=
m-n
1
c

p
( 0 £ t £ 1)
m

p1

p2 n
• Hesseの標準形(直線) x cos q + y sin q = p
x
y 1
(x , y )
• 三角形の面積:S
1
0
h=±

• 2点 p
x2
2
x3
1
1
y2 1
y3 1
( x2 , y2 )

p
p
q
1
( x3 , y 3 )
18
2次元座標変換の課題
• 回転している棒に旗を固定する
• 回転している棒に旗をぶらさげる
• サンプルプログラム等を参考に自由なプロ
グラムを作成
– 動きがあって、キーボードか、マウスで操作可能
19
5