01_coordinate_transformation
Download
Report
Transcript 01_coordinate_transformation
プログラミング演習3
李 亜民クラス
第1回
座標変換
このコースについて
テーマ : 「Javaによるコンピュータグラフィックス入門」
初歩的なCG技術を学ぶ
3DCG用ライブラリ等は使用しない
目的 : アルゴリズムを実装する
数式等を元に、それを実現するコードを記述する
[CGは線形代数の塊]
ベクトル、行列といった概念を頻繁に使用します。
忘れたかも…という方は是非復習を!
これらの概念についての詳しい説明は省略します。
今回の内容
概念説明
3Dグラフィックスパイプライン
座標系
座標変換
直線の描画
作業
拡大/縮小、移動、回転、モデル変換、ビューポート変換
変換行列の合成
プロジェクトの準備
動作に必要なクラスの穴埋め
課題について
サンプルコードの実行について
Javaは最新版にしておくこと。
最新版のJavaでは、証明書が添付されていないAppletは動作
しないようになっている。
1.
2.
3.
4.
java「すべてのプログラム」→「Java」→「Configure Java」
「セキュリティ」タブに移動
例外サイトリストの「サイト・リストの編集」
「追加」ボタンを押し、作成された欄に
「http://cis.k.hosei.ac.jp/~yamin/lectures/programming3/」と記入して
「OK」。確認が出ますが「続行」し、Configure Javaを閉じる。
サンプルのAppletが動作することを確認して下さい。
概念説明
3Dグラフィックスパイプライン
座標系
座標変換
3Dグラフィックスパイプライン
一部省略しているが、概ね次のような流れで処理される。
①
3Dモデル構築
仮想空間に配置(モデル変換)
バーテックス(頂点)処理
カメラ空間に展開(ビュー変換、射影変換、ビューポート変換)
バックフェースカリング
ラスタライズ
ピクセルシェーディング
特殊効果の適用(テクスチャ、アルファ、Zバッファ等)
②
③
④
⑤
⑥
⑦
⑧
3Dグラフィックスパイプライン
①
②
③
④
⑤
⑥
⑦
⑧
本講義では、以下の部分を実装する。
3Dモデル構築
モデル変換
バーテックス処理
ビューポート変換
バックフェースカリング
ラスタライズ
ピクセルシェーディング
Zバッファの適用
:第3回
:第1回
:第4回
:第1回
:第3回
:第2回
:第4回
:第3回
座標系
左手座標系
Direct X等で使用
y軸を上、x軸を右とすると、z軸は奥が正方向
右手座標系
線形代数等で使用される
最近はこちらが主流か
z軸は手前が正方向
こちらを採用する
採用する座標系によって変換行列が変化するので注意!
座標変換
座標に回転・移動などの操作を加える
ユーザの操作、カメラの位置などによって変化
回転、移動、拡大(縮小)の3種が基本
座標変換を行列で表し、変換後の座標v’を計算
e11 𝑒12 𝑒13 𝑒14
𝑥
𝑥′
𝑒21 𝑒22 𝑒23 𝑒24
𝑦
𝑦′
′
𝒗 =
=
= 𝑴𝒗
′
𝑒
𝑒
𝑒
𝑒
𝑧
31
32
33
34
𝑧
𝑒41 𝑒42 𝑒43 𝑒44
𝑤
𝑤′
全操作を行列で表すために次元を1つ追加してある
[参考] 同次座標(斉次座標)
通常の座標に次元を1つ追加したもの
追加する次元(w)の値は1
𝑥
𝑥
𝑦
𝑦 →
𝑧
𝑧
1
𝑤 = 1である間はそのままx,y,zを使用できる
元に戻す場合はx,y,zをwで割る
𝑥
𝑥 𝑤
𝑦
→ 𝑦 𝑤
𝑧
𝑧 𝑤
𝑤
この授業の範囲では常に𝑤 = 1なので、特に考慮する必要はない
CG分野においては頻繁に使用される
平行移動や、パースペクティブ変換のためにwが必要
詳細が気になる人は本などで調べてみてください。
拡大/縮小
X軸方向にsx、Y軸方向にsy、Z軸方向にsz倍
S 𝑠𝑥, 𝑠𝑦, 𝑠𝑧 =
𝑠𝑥
0
0
0
0
𝑠𝑦
0
0
0
0
𝑠𝑧
0
0
0
0
1
平行移動
ベクトル 𝑥, 𝑦, 𝑧 を 𝑏𝑥 , 𝑏𝑦 , 𝑏𝑧 だけ移動
𝑇 𝑏𝑥 , 𝑏𝑦 , 𝑏𝑧 =
1
0
0
0
0
1
0
0
0 𝑏𝑥
0 𝑏𝑦
1 𝑏𝑧
0 1
ここで、同次座標を用いないと
𝑥 + 𝑏𝑥
𝑥′
𝑦 ′ = 𝑦 + 𝑏𝑦
𝑧 + 𝑏𝑧
𝑧′
となって行列で表せない
回転
2次元の回転
𝑥′
cos 𝜃
=
𝑦′
sin 𝜃
− sin 𝜃
cos 𝜃
𝑥 − 𝑜𝑥
𝑜𝑥
𝑦 − 𝑜𝑦 + 𝑜𝑦
o:は回転中心。回転行列は原点中心の回転なので、一旦中心を原
点に移動→回転→もとの座標に戻すというプロセスが必要
これを3次元に拡張する
上記の式はz軸中心の回転とみることができる
3次元の回転行列
1
0
0
0 cos 𝜃 − sin 𝜃
𝑅𝑥 𝜃 =
0 sin 𝜃 cos 𝜃
0
0
0
cos 𝜃 0 sin 𝜃
0
1
0
𝑅𝑦 𝜃 =
− sin 𝜃 0 cos 𝜃
0
0
0
cos 𝜃 −sin𝜃 0
sin 𝜃 cos 𝜃 0
𝑅𝑧 𝜃 =
0
0
1
0
0
0
※全て原点中心
0
0
0
1
0
0
0
1
0
0
0
1
モデル変換
ローカル(モデル)座標系をワールド座標系に変換
物体毎のローカル座標を拡大/縮小・移動・回転させることで
ワールド座標系に配置
[参考] ビュー変換/射影変換
ビュー変換
カメラ位置に応じて座標系を回転、移動
カメラから見た座標系に直す
射影変換
正射影変換
投映変換
x,y,zをそのまま使用。場合によっては、x,yを-1~1に、zを0~1に
遠近が表現できるよう、視野空間を立方体に変形
どちらも複雑なので、本講義では省略する
スクリーン変換
スクリーン(キャンバス)に描画する際に向き等を補正
Appletは左上が原点(0, 0)
→x軸回りに180度回転+スクリーン中心まで平行移動
1 0
0 𝑠𝑐𝑟𝑒𝑒𝑛𝑊/2
0 −1 0 𝑠𝑐𝑟𝑒𝑒𝑛𝐻/2
SC =
0 0 −1
0
0 0
0
1
座標変換行列の合成
変換後の座標をさらに変換
𝒗′ = 𝑴𝒏 ⋯ 𝐌𝟐 𝐌𝟏 𝒗
= 𝐌𝐧 ⋯ 𝐌𝟐 𝐌𝟏 𝒗
行列部分をまとめて先に計算
→同じ変換を行うベクトルが複数あるとき計算量を削減できる
式変形からも判るように、先に行う変換を後に付ける
変換の順番によって結果が異なるので注意!
座標変換を行う際の注意
変換後の値をさらに変換すると…?
変換を行った後の座標とは別に、変換前の座標を保持
しておく必要がある
当然、想定された結果にはならない
上書きしないように注意!
座標変換以外でも、ベクトル等を上書きする場合には注
意が必要
座標変換の例(1)
正方形 ポリゴンを例に座標変換プロセスを追う
頂点座標を定義
1
1
−1
−1
1 , −1 , −1 , 1
0
0
0
0
※内部的には、
1
1
−1
−1
1
−1
−1
1
,
,
,
0
0
0
0
1
1
1
1
という同次座標で処理する
座標変換の例(2)
Z軸を中心に45° 𝜋/4 回転し、さらに(2,5,0)移動するとする。
それぞれの変換について、変換行列を求める
𝜋
4
𝜋
sin
4
𝜋
4
𝜋
cos
4
cos
𝜋
𝑅𝑧
4
=
0
0
1
0
𝑇 2,5,0 =
0
0
−sin
0
1
0
0
0
0
0
0
1
0
2
5
0
1
0 0
0 0
1 0
0 1
=
1
2
1
2
0
0
−
1
2
0 0
1
2
0 0
0
0
1 0
0 1
座標変換の例(3)
変換行列を合成
M = 𝑇 2,5,0 𝑅𝑧
=
1
2
1
2
0
0
−
1
2
𝜋
4
=
0
2
1
2
0
5
0
0
1
0
0
1
1
0
0
0
0
1
0
0
0
0
1
0
2
5
0
1
1
2
1
2
0
0
−
1
2
0
0
1
2
0
0
0
0
1
0
0
1
座標変換の例(4)
合成された変換行列で座標変換
M𝒗1 =
1
2
1
2
0
0
−
1
2
0 2
1
2
0 5
0
0
1 0
0 1
2+
同様に、M𝒗2 =
5
0
1
1
1
0
1
=
2
2
, M𝒗𝟑 =
2
2
5+
2
0
1
2
5−
0
1
2
2
2−
, M𝒗4 =
5
0
1
2
2
座標変換の例(5)
実際にはこの後スクリーン変換等が必要
線形補間(lerp, Linear Interpolation)
2つのベクトルと補間係数αから間のベクトルを求める
𝒗′ = 1 − 𝛼 𝒗1 + 𝛼𝒗2
α : 補間係数(0~1)
v’ : 補間ベクトル
(v1とv2を通る直線上のベクトル)
3次元ベクトル 𝑥, 𝑦, 𝑧 なら
𝑥1
𝑥2
𝑥′
𝑦′ = 1 − 𝛼 𝑦1 + 𝛼 𝑦2
𝑧1
𝑧2
𝑧′
wは常に1なので無視して良い
以降、様々な場面で使用。
色や3次以上のベクトル、スカラーでも同様に補間可能。
直線の描画
座標v1~v2に直線を引くとする
基本アイデアとしては次のようになる
for y = v1.y to v2.y
xを計算(線形補間)
x,yに点をプロット
end
ただし、上記のままだと問題が発生する
傾きが浅い直線の場合、線が途切れる
xでループする必要がある
v1.y > v2.yのときには、デクリメントしながら
のループになる
線の方向を考慮した処理を行う必要がある
直線の描画 線の方向に応じた処理
v1から見てv2がどちら側にあるのかによって処理を分ける
if …
for (…,…,x++){…}
else if …
for (…,…,x--){…}
else if …
for (…,…,y++){…}
else if …
for (…,…,x--){…}
上記の通りにする必要はない
実装は各自工夫すること。やり方によっては、for文1つでも可能
「ブレゼンハムのアルゴリズム」について調べてみても良い
作業
プロジェクトの準備
クラスの穴埋め
プロジェクトの準備
プロジェクト名:任意
パッケージ名:lec01
授業ページからサンプルコードをダウンロードしてイン
ポートし、未完成のクラスを埋めてゆく
Canvas.java
Sample01.java
Matrix.java(未完成)
Vector.java(未完成)
Lec01.java(未完成)
Canvasクラス(1)
GUIの初期化、リスナー等をまとめた抽象クラス
public void init()
Applet等の初期化
インスタンス生成時に呼び出される
public void adjustmentValueChanged(AdjustmentEvent e)
スクロールバーを操作した時に呼ばれる
scrValueX,Y,Zにスクロールバーから得られる値を格納した後、
repaint()を呼び出し
Canvasクラス(2)
public void paint(Graphics g)
void drawPoint(x,y,color)
repaint()が呼ばれた後、プロセッサが空くと実行される
キャンバスをクリアー(白で塗りつぶし)した後、render()を呼びだし
指定ピクセルを指定色に塗る
これ以外のdraw…メソッドは使用しない
abstract void render()
抽象メソッド
フレームの描画処理を、継承先で実装
Sample01クラス
座標変換のプロセスや、継承したCanvasの使い方等をま
とめたクラス
public void init()
頂点データの初期化等
必ず、最初にスーパークラスのinit()を呼ぶ
void render()
描画処理
変換行列の計算、変換行列の合成、座標変換というプロセスを実行
Vectorクラス(未完成)
メンバ変数
コンストラクタ
double x, y, z, w
引数なし・x,y,z指定(共にw=1で初期化)
メソッド
void normalize() : (x, y, z)を正規化(wはそのまま)
Vector transform(Matrix M)
: 行列Mで座標変換を行い、変換結果を返す
double dot(…) : 内積を返す
Vector cross(…) : 外積を返す
Vector lerp(…) : 線形補間(次項参照)
[復習] 内積・外積
内積(スカラー)
𝑏𝑥
𝑎𝑥
𝒂 = 𝑎𝑦 , 𝒃 = 𝑏𝑦 とする。
𝑎𝑧
𝑏𝑧
𝒂 ∙ 𝒃 = 𝑎𝑥 𝑏𝑥 + 𝑎𝑦 𝑏𝑦 + 𝑎𝑧 𝑏𝑧
外積(ベクトル)
𝑎𝑦 𝑏𝑧 − 𝑎𝑧 𝑏𝑦
𝒂 × 𝒃 = 𝑎𝑧 𝑏𝑥 − 𝑎𝑥 𝑏𝑧
𝑎𝑥 𝑏𝑦 − 𝑎𝑦 𝑏𝑥
Vectorクラスについての注意点
dot(), cross()等で元のベクトルを上書きしないように注意
ベクトルは複数回使用することがある
アクセス修飾子は各自で判断する
各自で必要だと思うメソッドを追加しても良い
加算、反転、toString()等
Matrix(行列)クラス(未完成)
メンバ変数
コンストラクタ
double 4x4配列
引数なし・配列で指定
メソッド
Matrix scale(…) : 拡大縮小行列を返す
Matrix rotX(…),rotY(…),rotZ(…) : x,y,z軸回転行列を返す
Matrix translate(…) : 平行移動行列を返す
Matrix screen(…) : スクリーン変換行列を返す
Matrix mult(… ) : 行列どうしの掛け算
クラスメソッドとインスタンスメソッド
インスタンスメソッド:各インスタンスに対応
定義:void setRotX(theta){…}
参照:Matrix RX = new Matrix();
RX.setRotX(theta);
※引数なしのコンストラクタを使用
クラスメソッド:クラスに対応
定義:static Matrix rotX(theta){…}
参照:Matrix RX = Matrix.rotX(theta);
インスタンスなしでも参照可能!
詳細は各自調べてみてください。
第1回課題
1. 正方形が回転するプログラムを記述してください。
クラス:lec01に記述
init()に頂点などの初期化処理を実装
render()に描画処理を実装
Sample01を参考に、x,y,z回転行列とスクリーン変換行列を使用
drawLine()を直線の描画を記述
基本的に、//TODOとなっている部分を埋めてゆけばOK
2. [発展] 破線を描画してください。
drawBrokenLine(v1, v2, duration, interval) 等として、実線部分
と空白部分の長さを任意に決められるように記述して下さい。
実線/破線の切り替えをGUIで行えるようにして下さい。
課題の実行イメージ
直線
破線
レポートの形式について
1ページ目上部に、学籍番号、名前、提出日、レポート回
数、講義名等を明記。
1. 課題について自分の言葉で説明
2. ソースコード・コードの説明
3. 実行結果
引数、返り値、動作内容、工夫した点など。
工夫した点については、特に詳しく説明すること。
コードには適切にコメントを書くこと。
スクリーンショットと説明を併記
プログラムが正しいことが判るように工夫する
4. 考察・感想