プログラミング入門 - ビスケット viscuit...人 にんげん 間がへんだと思 おも っても コンピュータにはわからない コンピュータは言 い
プログラミング言語I 第3回 コンピュータ ... · プログラミング言語i 第3回...
-
Upload
nguyenthuan -
Category
Documents
-
view
254 -
download
0
Transcript of プログラミング言語I 第3回 コンピュータ ... · プログラミング言語i 第3回...
プログラミング言語I 第3回
コンピュータ・グラフィックス1
埼玉大学工学部電気電子システム工学科
伊藤 和人
Copyright © 2008 Kazuhito Ito
コンピュータ・グラフィックスとは
計算機(コンピュータ)を使って人工的に作り出す絵
実際には見られないものを可視化する
昔の建築物の再現、事故や事件の状況再現
半導体中の電流の密度
まだ存在しないものをリアルに提示する新製品のイメージ(模型の代わり)
アート
実世界とはほとんど無関係な形状、色彩
映画など
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)
直線の方程式
tv vPP +=
P
vt
vP: 直線上の点(変数): 通過点(定点)
: 任意の実数(変数): 直線の方向ベクトル
P
vP v
太字はベクトル、細字は実数(スカラ)
Copyright © 2008 Kazuhito Ito
レイトレーシングの基礎(2)
視線(直線)の方程式
画面
画素視点
視線
tv vPP += vP として視点方向ベクトル
P
vPv
vS PPv −=
SP
Copyright © 2008 Kazuhito Ito
レイトレーシング: 球の場合(1)
球の定義
球の方程式
( ) 22 RC =− PPPR
CP: 点(変数) : 球の中心
: 球の半径
CPP
R
ある1点(中心)から同じ距離(半径)にある点の集合
( ) 22CCCC PPPPPPPP −=−•−=−
BA• ベクトルの内積
Copyright © 2008 Kazuhito Ito
レイトレーシング: 球の場合(2)
視線と球面の交点を求める⇒視線の式を球の式に代入
( ) 22 RC =− PPtv vPP +=
( ) ( ) 02 2222 =−−+•−+ Rtt CvCv PPvPPv
P
vP
t に関する二次方程式
実数解が存在する ⇒視線が球と交わる
実数解が存在しない ⇒視線が球と交わらない
{
Copyright © 2008 Kazuhito Ito
レイトレーシング: 球の場合(3)
実数解が存在するか否か⇒判別式を調べる
実数解が存在する場合、解の公式を利用
( ) ( ) 02 2222 =−−+•−+ Rtt CvCv PPvPPv判別式
( )( ) ( )( )2222 RD CvCv −−−•−= PPvvPP
( )20 v
vPP Dt Cv −•−−=
0tv vPP +=交点の座標
なぜ‘+’は考えない?
Copyright © 2008 Kazuhito Ito
C言語によるプログラム(1)
ベクトルの表現
各成分ごとに別々の変数を使用
要素数3の配列を使用
3次元ベクトル P=(Px, Py, Pz) はPx, Py, Pzの3つの実数値の集まり
double Px, Py, Pz;
⇒1個のベクトルのために常に3個の変数が必要
double P[3];P[0]がPx, P[1]がPy, P[2]がPzを担当
⇒1個のベクトルは1個の配列として扱える
扱いが面倒
Copyright © 2008 Kazuhito Ito
配列とは
同じ型の複数の変数をまとめて扱う
例えば、「プログラミング言語I」受講生80名の成績
80人分の80個の変数、すべて整数型3次元ベクトルの3つの成分は、すべて実数
配列(array)C言語で同じ型の変数をまとめて扱う手段
1つ1つの変数は要素という
Copyright © 2008 Kazuhito Ito
配列の宣言
型、名前、要素数を宣言する
変数の型として指定できるすべての型が可能
1つ1つの要素の型を指定すると考えればよい
上の例では、各要素はint型
型 配列名[要素数];
int a[10];例 要素数が10の整数(int)型配列a
Copyright © 2008 Kazuhito Ito
要素の参照
配列の各要素を読み書きするには⇒配列名に添え字(インデックス)を与える
添え字の範囲は0~(要素数-1)まで
各要素の使い方は変数と全く同じ
a[5]例 配列aの6番目の要素
i = a[5];
a[5] = j+1;
a[5]++;
例 値の読み出し
値の代入
1だけ増加
int a[10]; a[0]~a[9]が使用可能
Copyright © 2008 Kazuhito Ito
配列の効用
配列を使うと…
計算式は1つだけ書けばよいfor文などで繰り返し実行
int mid[100];int final[100];int score[100];int i;
:for( i=1 ; i<=80 ; i++ ){
score[i] = mid[i]*0.4+final[i]*0.6;}
:
Copyright © 2008 Kazuhito Ito
配列の初期値
配列を宣言するときに初期値を指定可能
初期値指定が足りなければ0を補う
初期値指定がなければ初期化しない
int a[3]={0, 20, 300};a[0]は0, a[1]は20, a[2]は300が代入される
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
浮動小数型
細かな数値、大きな数値を表す型
±1.175×10-38~±1.175×10+38
(32ビット、有効桁数7)float
double
long double
±2.225×10-308~±2.225×10+308
(64ビット、有効桁数15)
±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;
z
y
x
vP
O
画面
視点
(0,0,2000)
(0,0,-1000)
半径 R=200
CP中心
-200
-200
200
200
Copyright © 2008 Kazuhito Ito
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];v[2] = 0-Pv[2];…
}}
C言語によるプログラム(2)
視線方向ベクトル
2 i=3 411
j=12
13
座標(3.5,12.5)
視線
Copyright © 2008 Kazuhito Ito
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
double A, B2, C, D;double Pvc[3];int k;for( k=0 ; k<3 ; k++ ) Pvc[k] = Pv[k]-Pc[k];
A = InnerProduct( v, v );B2 = InnerProduct( Pvc, v );C = InnerProduct( Pvc, Pvc )-R*R;D = B2*B2-A*C ;
C言語によるプログラム(3)
判別式の計算
( )( ) ( )( )2222 RD CvCv −−−•−= PPvvPP
2v( ) vPP •− Cv
( ) 22 RCv −− PP
CvvC PPP −=
Copyright © 2008 Kazuhito Ito
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 )座標 色(3原色)
球に当たる
背景
Copyright © 2008 Kazuhito Ito
条件分岐の構文: else節付if文“もし(if)…ならば…を実行、さもなければ…を実行”という形式の条件分岐を表すelse節をともなうif文の文法
if ( 式 ) 文1 else 文2意味: 式が真の場合に文1を実行、 偽の場合に文2を実行
式
文1
True False
文2合流
Copyright © 2008 Kazuhito Ito
実行結果
視線が球に当たれば単に赤い点を描いただけ⇒ 単に円になる(球は2次元に射影すると円)
Copyright © 2008 Kazuhito Ito
光の考慮
対象物の色は、対象物自体の色と照明によって決まる
照明の種類直接光点光源、面光源、平行光など⇒面の傾き(法線)に依存して明るさが決まる間接光(環境光)⇒法線に関係なく(一定の)明るさが決まる反射の種類拡散反射(つや消し面など)鏡面反射(光沢のある面など)
Copyright © 2008 Kazuhito Ito
反射: 拡散反射
反射光の強さが反射の方向に依らず一定
反射光強さ=反射面(点)の明るさ×反射率
n
Lvα
( ) DD KI ×αcos
αDI : 照明の強さ
: 照射角P
DK : 拡散反射率 光入射
拡散反射光
反射面(点)
明るさ 反射率法線
(入射光と法線の成す角)
Copyright © 2008 Kazuhito Ito
反射: 拡散反射
反射光強さ
点光源の場合
n
Lvα
LL PPv −=
P
LP : 点光源の位置
( )( ) ( )nnvv
nvnv
nv••
•−=
•−=
LL
L
L
Lαcos
光入射拡散反射( ) DD KI ×αcos
αcosBABA =• αはベクトルの成す角
法線
Copyright © 2008 Kazuhito Ito
レイトレーシングの基礎(3)球面上の点 P における法線ベクトル法線: 接面に垂直な直線
v
n⇒球の中心から点 P に向かう直線
CPPn −=
CP
P
n
具体的に視線と球の交点 P の座標を求めることが必要
視線
Copyright © 2008 Kazuhito Ito
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;
C言語によるプログラム(6)
視線と球の交点を求める
( )20 v
vPP Dt Cv −•−−=
0tv vPP +=代入
Copyright © 2008 Kazuhito Ito
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で点を描く */
C言語によるプログラム(7)
法線ベクトルおよび拡散反射強度を求める
光源座標
法線
光入射
Copyright © 2008 Kazuhito Ito
レイトレーシングの基礎(4)
cosA < 0 の場合
Lv
n
CP
P入射光と法線の成す角が90度を超える
点 P は球自身の影にある
黒色にする
Copyright © 2008 Kazuhito Ito
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
反射: 鏡面反射
反射光の強さが反射の方向によって決まる
反射光強さ=反射面(点)の明るさ×反射率
n
LvαγSI : 照明の強さ
: 反射受光角
P
SK : 拡散反射率 光入射
拡散反射光
反射面(点)
明るさ 反射率法線
(反射光と視線の成す角)
( ) SN
S KI ×γcos
反射光Rvαv
視線 γ
N : 鏡面度(10~20)
Copyright © 2008 Kazuhito Ito
反射: 鏡面反射
を求める⇒ まず を求める
n
Lvα
P
αv γRv
( )nnvvv αcos2 LLR =−+
( )nv
nv
L
L •−=αcos
( )L
LR vn
nnvv +
•−= 22
を代入
( )vv
vv
R
R •−=γcos
入射
反射
視線γcosRv
n
LvRv αα
Copyright © 2008 Kazuhito Ito
double P[3], N[3], vL[3], vR[3];int k;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];cosG = -InnerProduct(vR,v)/
sqrt(InnerProduct(vR, vR)*InnerProduct(v,v));if( cosG < 0 ) cosG = 0;cosG = pow(cosG,n);
C言語によるプログラム(9)
鏡面反射強度を求める
( )2n
nv •− L
Rv
( )vv
vv
R
R •−=γcos
γncos
Copyright © 2008 Kazuhito Ito
環境光
光源の位置、視線交点の法線の向きに依らずに与えられる一定の明るさ
拡散反射と同様に、視線方向によらず一定の反射率とみなす
EI : 環境光の強さ
Copyright © 2008 Kazuhito Ito
照明のまとめ
拡散反射、鏡面反射、環境光のうち、最も明るいものを選び、点P の明るさとする
{ }EN
SSDD IIKIK ,cos,cosmax γα拡散反射 鏡面反射 環境光
Copyright © 2008 Kazuhito Ito
色について
赤(R), 緑(G), 青(B)の各原色について明るさを評価する
環境光、拡散反射については対象物の色、鏡面反射については光源の色(通常は白)とすると「らしさ」が出る
{ }EEN
SSSDDD ICICKICK ,cos,cosmax γα
DC : 拡散反射の原色要素
SC : 鏡面反射の原色要素
EC : 環境光の原色要素
Copyright © 2008 Kazuhito Ito
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 );
}
C言語によるプログラム(10)拡散反射、鏡面反射、環境光を考慮
背景
鏡面反射は白色
拡散反射
環境光
Copyright © 2008 Kazuhito Ito
実行結果
左上から照らされる部分 ⇒ 拡散反射および鏡面反射直接照らされない部分 ⇒ 環境光
Copyright © 2008 Kazuhito Ito
球が複数個ある場合(1)
⇒ 視点に最も近い球を表示すればよい
Copyright © 2008 Kazuhito Ito
球が複数個ある場合(2)視点に最も近い球を表示
視点
視線1
視線2
手前の球が遠くの球を隠す
遠くの球が見えている
視点と球の交点のうち、視点により近い交点を表示
Copyright © 2008 Kazuhito Ito
球が複数個ある場合(3)
より近い交点を選ぶには
tv vPP +=vP
直線の式2Pv
1P
11 tv vPP +=22 tv vPP +=
P2 が P1 よりも視点 Pv に近ければ t2<t1
視線と交差する球について t を求め、最小の t を与える球を選ぶ
(t2 > 0, t1 > 0)
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};int s0 = -1;for( s=0 ; s<2 ; s++ ){
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;if( s0 < 0 || t < t0 ){
s0 = s; t0 = t;}
}}
}
A,Bを計算(省略)
s=0, s=1番目の球について
視線が球と交わる
最小の tおよびその球の番号 s を記録
s0=0なら最初の球なので必ず記録、それ以外はtが小さければ記録
Copyright © 2008 Kazuhito Ito
C言語の補足説明(1)
2次元配列: 添え字が2つある配列
2次元配列の初期化: 1次元の場合を拡張
double Pc[2][3]
Pc[0][0] Pc[0][1] Pc[0][2]Pc[1][0] Pc[1][1] Pc[1][2]
要素数6(=2×3)、double型
6個の要素
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文における複雑な条件
最初はs0=-1なので必ず条件は真⇒ s0にs, t0にtを代入 (ここでs0は0以上)以降はt<t0ならば、s0にs, t0にtを代入
if( s0 < 0 || t < t0 ){s0 = s; t0 = t;
}
s0 < 0 || t < t0 s0<0 または t<t0ならば真
例:
最小の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];…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 );
}
cosA, cosGを計算(省略)
球の色
交点
法線
入射光
Copyright © 2008 Kazuhito Ito
実行結果
球による影は?
Copyright © 2008 Kazuhito Ito
影の考慮
交点から光源へ向かう直線を想定
視点交点から光源に到達しない⇒ 交点は影にある
視線と球の交点
光源 レイ・トレーシングの本来の語源
Copyright © 2008 Kazuhito Ito
交点から光源へ向かう直線
直線の式
vP
P
v 'P
tv vPP +=
'' 1tvPP +=
PPv −= L1
LP
視点
光源
視線
入射光
交点
交点
'' 1tvPP +=直線 が球と
交わるか調べる
⇒ 交わるならば交点は影にある
Copyright © 2008 Kazuhito Ito
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;
}if( s<2 ){ /* 交点Pから光源が見えない*/
cosA = cosG = 0.0;}else{ /* 交点Pから光源が見える*/
}
交点
'' 1tvPP +=が光源側の球と交わる
直線
cosA, cosGを計算
Copyright © 2008 Kazuhito Ito
繰り返しの制御: continue文繰り返し中で、continueから後ろをスキップ
for(m=0 ; m<10 ; m++ ){処理1if( 条件 ) continue;処理2
}
例:
m=0
処理1
m++
m<10True
False
意味: ・まず処理1を実行・条件が成り立たなければ処理2を実行、mを1増やす・条件が成り立てば処理2を実行せずに、mを1増やす
処理2
True
False条件
Copyright © 2008 Kazuhito Ito
繰り返しの制御: break文繰り返しを中断
for(m=0 ; m<10 ; m++ ){処理1if( 条件 ) break;処理2
}
例:m=0
処理1
m++
m<10True
False
意味: ・まず処理1を実行・条件が成り立たなければ処理2を実行、mを1増やす・条件が成り立てば処理2を実行せずに、for文を終了する
処理2
True
False条件
Copyright © 2008 Kazuhito Ito
実行結果
影を考慮影なし
Copyright © 2008 Kazuhito Ito
まとめ
レイトレーシングを考察
モデリングを正しく行えば、原理は単純
レイトレーシングの原理をC言語でプログラム化する