...

プログラミング言語I 第3回 コンピュータ・グラフィックス1

by user

on
Category: Documents
8

views

Report

Comments

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
Fly UP