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. 考察・感想