Comments
Description
Transcript
プログラミング言語I 第3回 コンピュータ・グラフィックス1
プログラミング言語I 第3回 コンピュータ・グラフィックス1 埼玉大学工学部 電気電子システム工学科 伊藤 和人 コンピュータ・グラフィックスとは 計算機(コンピュータ)を使って人工的に作 り出す絵 実際には見られないものを可視化する まだ存在しないものをリアルに提示する 昔の建築物の再現、事故や事件の状況再現 半導体中の電流の密度 新製品のイメージ(模型の代わり) アート 実世界とはほとんど無関係な形状、色彩 映画など Copyright © 2008 Kazuhito Ito コンピュータ・グラフィックスの例 実際には見られないものを可視化する 昔の建築物の再現 Copyright © 2008 Kazuhito Ito 地下の構造物の様子 コンピュータ・グラフィックスの例 まだ存在しないものをリアルに提示する 新商品のモデル Copyright © 2008 Kazuhito Ito コンピュータ・グラフィックスの例 アート系 Copyright © 2008 Kazuhito Ito コンピュータグラフィックスの手順 モデリング 幾何学処理 計算機が処理可能なデータとして物体を表現 線、面などの集合として対象物を表す 移動、回転、拡大/縮小 レンダリング 2次元画像化 光(反射、透過、色、影)、テクスチャ(質感) Copyright © 2008 Kazuhito Ito レンダリング手法 塗りつぶし 隠面消去 マッピング シェーディング レイトレーシング ラジオシティ レイトレーシングに注目 Copyright © 2008 Kazuhito Ito レイトレーシングとは 画面を画素に分割 視点から画素に向かう視線(Ray)を延長(追跡, trace)した先の色を画素の色とする 視線 画素 視点 画面 Copyright © 2008 Kazuhito Ito 対象物 レイトレーシングの例 対象物の表し方(モデリング)の違い 単一の球としてモデリング 三角の集合としてモデリング まず球の場合を考える Copyright © 2008 Kazuhito Ito レイトレーシングの基礎(1) 直線の方程式 P = Pv + vt P Pv v P : 直線上の点(変数) Pv : 通過点(定点) v : 直線の方向ベクトル t : 任意の実数(変数) 太字はベクトル、細字は実数(スカラ) Copyright © 2008 Kazuhito Ito レイトレーシングの基礎(2) 視線(直線)の方程式 P = Pv + vt 視点 Pv v Pv として視点 方向ベクトル v = PS − Pv 画素 PS P 視線 画面 Copyright © 2008 Kazuhito Ito レイトレーシング: 球の場合(1) 球の定義 ある1点(中心)から同じ距離(半径)にある 点の集合 球の方程式 (P − PC ) 2 =R R 2 PC P P : 点(変数) PC : 球の中心 R : 球の半径 2 (P − PC ) = P − PC • P − PC = P − PC Copyright © 2008 Kazuhito Ito A • B ベクトルの内積 2 レイトレーシング: 球の場合(2) 視線と球面の交点を求める ⇒視線の式を球の式に代入 P = Pv + vt 2 2 (P − PC ) = R { P Pv v t + 2( Pv − PC ) • vt + ( Pv − PC ) − R = 0 2 2 2 2 t に関する二次方程式 実数解が存在する ⇒ 視線が球と交わる 実数解が存在しない ⇒ 視線が球と交わらない Copyright © 2008 Kazuhito Ito レイトレーシング: 球の場合(3) 実数解が存在するか否か ⇒判別式を調べる v t + 2( Pv − PC ) • vt + ( Pv − PC ) − R = 0 2 2 2 判別式 D = (( Pv − PC ) • v ) − v 2 2 2 ((P − P ) 2 v C −R 2 ) 実数解が存在する場合、解の公式を利用 − ( Pv − PC ) • v − D t0 = 2 v Copyright © 2008 Kazuhito Ito 交点の座標 P = Pv + vt0 なぜ‘+’は考えない? C言語によるプログラム(1) ベクトルの表現 3次元ベクトル P=(Px, Py, Pz) は Px, Py, Pz の3つの実数値の集まり 各成分ごとに別々の変数を使用 double Px, Py, Pz; 扱いが面倒 ⇒1個のベクトルのために常に3個の変数が必要 要素数3の配列を使用 double P[3]; P[0]がPx, P[1]がPy, P[2]がPz を担当 ⇒1個のベクトルは1個の配列として扱える Copyright © 2008 Kazuhito Ito 配列とは 同じ型の複数の変数をまとめて扱う 配列(array) 例えば、「プログラミング言語I」受講生80名の 成績 80人分の80個の変数、すべて整数型 3次元ベクトルの3つの成分は、すべて実数 C言語で同じ型の変数をまとめて扱う手段 1つ1つの変数は要素という Copyright © 2008 Kazuhito Ito 配列の宣言 型、名前、要素数を宣言する 型 配列名[要素数]; 例 int a[10]; 要素数が10の整数(int)型配列a 変数の型として指定できるすべての型が 可能 1つ1つの要素の型を指定すると考えれば よい 上の例では、各要素はint型 Copyright © 2008 Kazuhito Ito 要素の参照 配列の各要素を読み書きするには ⇒配列名に添え字(インデックス)を与える 例 a[5] 配列aの6番目の要素 添え字の範囲は0∼(要素数-1)まで int a[10]; a[0]∼a[9]が使用可能 各要素の使い方は変数と全く同じ 例 i = a[5]; 値の読み出し a[5] = j+1; 値の代入 a[5]++; 1だけ増加 Copyright © 2008 Kazuhito Ito 配列の効用 配列を使うと… int int int int mid[100]; final[100]; score[100]; i; : for( i=1 ; i<=80 ; i++ ){ score[i] = mid[i]*0.4+final[i]*0.6; } : 計算式は1つだけ書けばよい for文などで繰り返し実行 Copyright © 2008 Kazuhito Ito 配列の初期値 配列を宣言するときに初期値を指定可能 int a[3]={0, 20, 300}; a[0]は0, a[1]は20, a[2]は300が代入される 初期値指定が足りなければ0を補う int a[3]={0, 20}; a[0]は0, a[1]は20, a[2]は0が代入される 初期値指定がなければ初期化しない int a[3]; a[0], a[1], a[2]の初期値は不定 Copyright © 2008 Kazuhito Ito 浮動小数型 細かな数値、大きな数値を表す型 float ±1.175×10-38∼±1.175×10+38 (32ビット、有効桁数7) double ±2.225×10-308∼±2.225×10+308 (64ビット、有効桁数15) long double ±1.084×10-4932∼±1.084×10+4932 (80ビット、有効桁数19) 通常は double 型を利用 コンパイラによっては long doubleはdoubleと同じ Copyright © 2008 Kazuhito Ito C言語によるプログラム(2) 視点、球の宣言と定義 double Pv[3] = {0.0, 0.0, 2000.0}; double Pc[3] = {0.0, 0.0, -1000.0}; double R = 200.0; 中心PC (0,0,-1000) y 200 -200 O 視点 -200 Pv z (0,0,2000) Copyright © 2008 Kazuhito Ito 200 画面 半径 R=200 x C言語によるプログラム(2) 視線方向ベクトル double v[3]; /* 視線方向ベクトル */ int i, j; for( i = -200 ; i <= 199 ; i++ ){ for( j = -200 ; j <= 199 ; j++ ){ v[0] = i+0.5-Pv[0]; v[1] = j+0.5-Pv[1]; 座標(3.5,12.5) v[2] = 0-Pv[2]; … 13 } j=12 } 11 視線 Copyright © 2008 Kazuhito Ito 2 i=3 4 C言語によるプログラム(3) 2つのベクトルの内積を計算する関数定義 double InnerProduct( double a[3], double b[3] ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } 使い方 視線ベクトルvと別のベクトルuの内積 double r; r = InnerProduct( v, u ); 関数呼び出し 関数を呼び出す前に関数の定義(宣言)が必要 Copyright © 2008 Kazuhito Ito C言語によるプログラム(3) 判別式の計算 D = (( Pv − PC ) • v ) − v 2 2 ((P − P ) 2 v C −R 2 ) double A, B2, C, D; double Pvc[3]; PvC = Pv − PC int k; for( k=0 ; k<3 ; k++ ) Pvc[k] = Pv[k]-Pc[k]; 2 v A = InnerProduct( v, v ); Pv B2 = InnerProduct( Pvc, v ); C = InnerProduct( Pvc, Pvc )-R*R; D = B2*B2-A*C ; Copyright © 2008 Kazuhito Ito ( − PC ) • v (Pv − PC ) 2 −R 2 C言語によるプログラム(4) 判別式が非負ならば視線が球に当たる double v[3]; /* 視線方向ベクトル */ int i, j; for( k=0 ; k<3 ; k++ ) Pvc[k] = Pv[k]-Pc[k]; for( i = -200 ; i <= 199 ; i++ ){ for( j = -200 ; j <= 199 ; j++ ){ … D = B2*B2-A*C ; if( D >= 0 ){ /* 座標(i,j)に点を描く */ } } } Copyright © 2008 Kazuhito Ito C言語によるプログラム(5) 色を着けて点を描く /* 座標(i,j)に点を描く */ if( D >= 0 ){ DrawPoint( i, j, 255, 0, 0 ); }else{ DrawPoint( i, j, 0, 0, 127 ); } 球に当たる 背景 関数DrawPoint( int i, int j, int R, int G, int B ) 座標 Copyright © 2008 Kazuhito Ito 色(3原色) 条件分岐の構文: else節付if文 “もし(if)…ならば…を実行、さもなければ… を実行”という形式の条件分岐を表す else節をともなうif文の文法 if ( 式 ) 文1 else 文2 意味: 式が真の場合に文1を実行、 偽の場合に文2を実行 True 文1 Copyright © 2008 Kazuhito Ito 式 False 文2 合流 実行結果 視線が球に当たれば単に赤い点を描いただけ ⇒ 単に円になる(球は2次元に射影すると円) Copyright © 2008 Kazuhito Ito 光の考慮 対象物の色は、対象物自体の色と照明に よって決まる 照明の種類 直接光 点光源、面光源、平行光など ⇒面の傾き(法線)に依存して明るさが決まる 間接光(環境光) ⇒法線に関係なく(一定の)明るさが決まる 反射の種類 拡散反射(つや消し面など) 鏡面反射(光沢のある面など) Copyright © 2008 Kazuhito Ito 反射: 拡散反射 反射光の強さが反射の方向に依らず一定 反射光強さ=反射面(点)の明るさ×反射率 (I D cos α )× K D 明るさ 反射率 法線 n : 拡散反射率 KD I D : 照明の強さ α : 照射角 拡散反射光 (入射光と法線の成す角) Copyright © 2008 Kazuhito Ito α 光入射 vL P 反射面(点) 反射: 拡散反射 法線 n 反射光強さ (I D cos α )× K D 拡散反射 α v 光入射 L P 点光源の場合 v L = P − PL PL : 点光源の位置 ( − vL )• n cos α = =− vL n Copyright © 2008 Kazuhito Ito A • B = A B cos α vL • n (v L • v L ) (n • n) αはベクトルの成す角 レイトレーシングの基礎(3) 球面上の点 P における法線ベクトル n 法線: 接面に垂直な直線 ⇒ 球の中心から点 P に向かう直線 n n = P − PC v P 視線 具体的に視線と球の交点 P の 座標を求めることが必要 Copyright © 2008 Kazuhito Ito PC C言語によるプログラム(6) 視線と球の交点を求める − ( Pv − PC ) • v − D t0 = 2 v 代入 P = Pv + vt0 double A, B2, C, D; double P[3]; int k; double t0; t0 = (-B2-sqrt(D))/A; for( k=0 ; k<3 ; k++ ) P[k] = Pv[k]+v[k]*t0; Copyright © 2008 Kazuhito Ito C言語によるプログラム(7) 法線ベクトルおよび拡散反射強度を求める double PL[3] = {-20000, 20000, 20000}; double P[3], N[3], vL[3]; 光源座標 int k; 法線 double cosA; /* P は視線と球の交点 */ for( k=0 ; k<3 ; k++ ) N[k] = P[k]-Pc[k]; for( k=0 ; k<3 ; k++ ) vL[k] = P[k]-PL[k]; cosA = -InnerProduct( vL, N ); cosA /= sqrt( InnerProduct( vL, vL )* 光入射 InnerProduct( N, N ) ); /* 座標(i,j)に明るさcosAで点を描く */ Copyright © 2008 Kazuhito Ito レイトレーシングの基礎(4) cosA < 0 の場合 入射光と法線の成す 角が90度を超える P vL 点 P は球自身の影にある 黒色にする Copyright © 2008 Kazuhito Ito PC n C言語によるプログラム(8) 色を着けて点を描く if( D >= 0 ){ 球に当たる /* 座標(i,j)に明るさcosAで点を描く */ if( cosA >= 0 ){ DrawPoint( i, j, 255*cosA, 0, 0 ); }else{ DrawPoint( i, j, 0, 0, 0 ); 球自身の影 } }else{ DrawPoint( i, j, 0, 0, 127 ); 背景 } Copyright © 2008 Kazuhito Ito 実行結果 左上から照らされる球 ⇒ 拡散反射では、つや消し効果が得られる Copyright © 2008 Kazuhito Ito 反射: 鏡面反射 反射光の強さが反射の方向によって決まる 反射光強さ=反射面(点)の明るさ×反射率 (I ) cos γ × K S N S 明るさ K S : 拡散反射率 I S : 照明の強さ γ 反射率 法線 反射光 視線 : 反射受光角 (反射光と視線の成す角) N : 鏡面度(10∼20) Copyright © 2008 Kazuhito Ito 拡散反射光 v n vR γ α α 光入射 vL P 反射面(点) 反射: 鏡面反射 反射 vR 入射 γ α α vL v 視線 cos γ を求める ⇒ まず v R を求める P n v R + (− v L ) = 2 v L cos α n ( − vL )• n を代入 cos α = vL n vR ( − vL )• n =2 n+v Copyright © 2008 Kazuhito Ito n 2 n L n vR α α vL ( − vR )• v cos γ = vR v C言語によるプログラム(9) 鏡面反射強度を求める double P[3], N[3], vL[3], vR[3]; (− v L ) • n int k; 2 n double w, cosG; /* P は視線と球の交点 */ w = -InnerProduct( vL, N )/InnerProduct( N, N ); for( k=0 ; k<3 ; k++ ) vR[k] = 2*w*N[k]+vL[k]; vR cosG = -InnerProduct(vR,v)/ sqrt(InnerProduct(vR, vR)*InnerProduct(v,v)); if( cosG < 0 ) cosG = 0; ( − vR )• v cosG = pow(cosG,n); cos γ = cos γ n Copyright © 2008 Kazuhito Ito vR v 環境光 光源の位置、視線交点の法線の向きに依 らずに与えられる一定の明るさ I E : 環境光の強さ 拡散反射と同様に、視線方向によらず一 定の反射率とみなす Copyright © 2008 Kazuhito Ito 照明のまとめ 拡散反射、鏡面反射、環境光のうち、最も 明るいものを選び、点P の明るさとする { max K D I D cos α , K S I S cos γ , I E N 拡散反射 Copyright © 2008 Kazuhito Ito 鏡面反射 } 環境光 色について 赤(R), 緑(G), 青(B)の各原色について明 るさを評価する C D : 拡散反射の原色要素 CS : 鏡面反射の原色要素 C E : 環境光の原色要素 { max K D C D I D cos α , K S CS I S cos γ , C E I E N } 環境光、拡散反射については対象物の色、 鏡面反射については光源の色(通常は白) とすると「らしさ」が出る Copyright © 2008 Kazuhito Ito C言語によるプログラム(10) 拡散反射、鏡面反射、環境光を考慮 double Kd = 1.0, Ks = 0.7, Ie = 0.1, I = 255.0; double RGB[3] = {255, 0, 0}, color[3]; if( D >= 0 ){ 鏡面反射は白色 for( k=0 ; k<3 ; k++ ){ 拡散反射 color[k] = RGB[k]*Kd*cosA; if( color[k] < I*Ks*cosG ) color[k] = I*Ks*cosG; if( color[k] < RGB[k]*Ie ) color[k] = RGB[k]*Ie; } DrawPoint( i, j, color[0], color[1], color[2] ); }else{ 環境光 DrawPoint( i, j, 0, 0, 127 ); 背景 } Copyright © 2008 Kazuhito Ito 実行結果 左上から照らされる部分 ⇒ 拡散反射および鏡面反射 直接照らされない部分 ⇒ 環境光 Copyright © 2008 Kazuhito Ito 球が複数個ある場合(1) ⇒ 視点に最も近い球を表示すればよい Copyright © 2008 Kazuhito Ito 球が複数個ある場合(2) 視点に最も近い球を表示 視点 手前の球が 遠くの球を隠す 視線1 遠くの球が見えている 視点と球の交点のうち、 視点により近い交点を表示 Copyright © 2008 Kazuhito Ito 視線2 球が複数個ある場合(3) より近い交点を選ぶには 直線の式 v P = Pv + vt P2 P1 Pv P1 = Pv + vt1 P2 = Pv + vt 2 (t2 > 0, t1 > 0) P2 が P1 よりも視点 Pv に近ければ t2<t1 視線と交差する球について t を求め、最小の t を 与える球を選ぶ Copyright © 2008 Kazuhito Ito C言語によるプログラム(11) double Pc[2][3] = {{-50.0, 50.0, -1000.0}, {200.0, -200.0, -1700.0}}; double R[2] = {200.0, 200.0}; s=0, s=1番目の int s0 = -1; 球について for( s=0 ; s<2 ; s++ ){ A,Bを計算 for( k=0 ; k<3 ; k++ ) Pvc[k] = Pv[k]-Pc[s][k]; C = InnerProduct( Pvc, Pvc )-R[s]*R[s]; (省略) D = B2*B2-A*C; if( D >= 0 ){ 視線が球と交わる t = (-B2-sqrt(D))/A; 最小の t および if( s0 < 0 || t < t0 ){ その球の番号 s を s0 = s; t0 = t; } 記録 } s0=0なら最初の球なので必ず記録、 } } それ以外はtが小さければ記録 Copyright © 2008 Kazuhito Ito C言語の補足説明(1) 2次元配列: 添え字が2つある配列 double Pc[2][3] 6個の要素 要素数6(=2×3)、double型 Pc[0][0] Pc[0][1] Pc[0][2] Pc[1][0] Pc[1][1] Pc[1][2] 2次元配列の初期化: 1次元の場合を拡張 double Pc[2][3] = {{-50.0, 50.0, -1000.0}, {200.0, -200.0, -1700.0}}; Pc[0][0]=-50.0 Pc[0][1]=50.0 Pc[0][2]=-1000.0 Pc[1][0]=200.0 Pc[1][1]=-200.0 Pc[1][2]=-1700.0 Copyright © 2008 Kazuhito Ito C言語の補足説明(2) if文における複雑な条件 例: if( s0 < 0 || t < t0 ){ s0 = s; t0 = t; } 条件: s0 < 0 || t < t0 s0<0 または t<t0ならば真 最初はs0=-1なので必ず条件は真 ⇒ s0にs, t0にtを代入 (ここでs0は0以上) 以降はt<t0ならば、s0にs, t0にtを代入 最小のtをt0に、そのときのsをs0記録 Copyright © 2008 Kazuhito Ito C言語によるプログラム(12) double RGB[2][3] = {{255, 0, 0}, {0, 255, 0} }; 球の色 if( s0 >= 0 ){ /* 座標(i,j)に点を描く*/ 交点 for( k=0 ; k<3 ; k++ ) P[k] = Pv[k]+v[k]*t0; for( k=0 ; k<3 ; k++ ) N[k] = P[k]-Pc[s0][k]; 法線 for( k=0 ; k<3 ; k++ ) vL[k] = P[k]-PL[k]; 入射光 … cosA, cosGを計算(省略) for( k=0 ; k<3 ; k++ ){ color[k] = RGB[s0][k]*Kd*cosA; if( color[k] < I*Ks*cosG ) color[k] = I*Ks*cosG; if( color[k] < RGB[s0][k]*Ie ) color[k] = RGB[s0][k]*Ie; } DrawPoint( i, j, color[0], color[1], color[2] ); }else{ /* いずれの球にも当たらない=> 背景色*/ DrawPoint( i, j, 0, 0, 127 ); } Copyright © 2008 Kazuhito Ito 実行結果 球による影は? Copyright © 2008 Kazuhito Ito 影の考慮 交点から光源へ向かう直線を想定 光源 レイ・トレーシングの 本来の語源 視点 交点から光源に到達しない ⇒ 交点は影にある 視線と球の交点 Copyright © 2008 Kazuhito Ito 交点から光源へ向かう直線 直線の式 視線 光源 P = Pv + vt PL v1 = PL − P 交点 入射光 P ' = P + v1t ' Pv v P' 視点 交点 直線 P ' = P + v1t ' が球と 交わるか調べる ⇒ 交わるならば交点は影にある Copyright © 2008 Kazuhito Ito P C言語によるプログラム(13) if( s0 >= 0 ){ /* 座標(i,j)に点を描く*/ 交点 for( k=0 ; k<3 ; k++ ) P[k] = Pv[k]+v[k]*t0; … for( s=0 ; s<2 ; s++ ){ if( s == s0 ) continue; /* P[k]がある球自身は除外する*/ for( k=0 ; k<3 ; k++ ) v1[k] = PL[k]-P[k]; for( k=0 ; k<3 ; k++ ) Pvc1[k] = P[k]-Pc[s][k]; A = InnerProduct( v1, v1 ); B2 = InnerProduct( Pvc1, v1 ); C = InnerProduct( Pvc1, Pvc1 )-R[s]*R[s]; 直線 D = B2*B2-A*C ; if( D >= 0 && (-B2-sqrt(D))/A > 0 ) break; P ' = P + v1t ' } が光源側の if( s<2 ){ /* 交点Pから光源が見えない*/ 球と交わる cosA = cosG = 0.0; }else{ /* 交点Pから光源が見える*/ } Copyright © 2008 Kazuhito Ito cosA, cosGを計算 繰り返しの制御: continue文 繰り返し中で、continue から後ろをスキップ 例: for(m=0 ; m<10 ; m++ ){ 処理1 if( 条件 ) continue; 処理2 } 意味: ・まず処理1を実行 ・条件が成り立たなければ 処理2を実行、mを1増やす ・条件が成り立てば 処理2を実行せずに、 mを1増やす Copyright © 2008 Kazuhito Ito m=0 m<10 True 処理1 条件 False 処理2 m++ False True 繰り返しの制御: break文 繰り返しを中断 例: for(m=0 ; m<10 ; m++ ){ 処理1 if( 条件 ) break; 処理2 } 意味: ・まず処理1を実行 ・条件が成り立たなければ 処理2を実行、mを1増やす ・条件が成り立てば 処理2を実行せずに、 for文を終了する Copyright © 2008 Kazuhito Ito m=0 m<10 True 処理1 条件 False 処理2 m++ False True 実行結果 影なし Copyright © 2008 Kazuhito Ito 影を考慮 まとめ レイトレーシングを考察 モデリングを正しく行えば、原理は単純 レイトレーシングの原理をC言語でプログラ ム化する Copyright © 2008 Kazuhito Ito