座標系の設定 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
© Copyright 2025 ExpyDoc