プログラムの整理と拡張(後編)
drawメソッドの整理その1
前回までの内容でスケッチをかなり整理できたが,複数の物体や光源に対応するなどの
機能拡張も行ったためdraw
メソッドの内容が肥大してしまった.
現在のところdraw
メソッドは以下のような処理内容を含んでいる.
for(yを0からH-1まで繰り返す) { for(xを0からW-1まで繰り返す) { 1. 座標(x,y)における視線方向を計算する. 2. for(全ての物体について繰り返す) { if(物体iと視線方向が交点を持つ場合) その交点が,現在見つかっている最も近い交点よりも近いならその情報を記憶する. } 3. if(ここまでに交点が見つかっている場合) { 環境光の反射光の放射輝度を計算して【放射輝度】に代入する. for(全ての光源について繰り返す) { 光源iによるライティングを計算する. 光源iからの光の拡散反射光の放射輝度を計算して【放射輝度】に加算する. 光源iからの光の鏡面反射光の放射輝度を計算して【放射輝度】に加算する. } 【放射輝度】を色に変換して描画色に設定する. } 4. 座標(x,y)を現在の描画色で塗る. } }
強調した部分は別のメソッドとして分離できそうである.そこで描画するシーンを構成するオブジェクトを
クラスScene
にまとめて,複数の物体の中から最も近い物体を返すメソッドを定義することにしよう.
shapes
,lightSources
,ambientIntensity
はいままでグローバル変数として保持していたものと同じである.
testIntersectionWithAll
メソッドが「複数の物体の中から最も近い物体を返すメソッド」である.
このメソッドは半直線を表すRay
のインスタンスを引数として受け取り,shapes
と順番に交差判定を行い,
半直線の始点に最も近い交点の情報と交差のあった物体の組を表すIntersectionTestResult
クラスのインスタンスを返す.
IntersecionTestResult
は以下のようなクラスである.
これらは以下のようにして使用する.
Scene scene; // シーン void setup() { scene = new Scene(); // シーンを初期化 // // scene.shapes や scene.lightSources に // データを追加するなどの処理 // } void draw() { //..中略.. Ray ray = /* 何らかの半直線 */; // 全ての物体との交差判定を試みる IntersectionTestResult res = scene.testIntersectionWithAll(ray); if ( res != null ) // 交点が見つかった場合 { res.intersectionPoint; // 最も近い交点の情報 res.shape; // 交差があった物体の情報 } //..中略.. }
drawメソッドの整理その2
前節の整理によってdraw
メソッドは以下のようになる.
for(yを0からH-1まで繰り返す) { for(xを0からW-1まで繰り返す) { 1. 座標(x,y)における視線方向を計算する. 2. 全ての物体と交差判定を行い,最も近い交点を探す(testIntersectionWithAll) 3. if(ここまでに交点が見つかっている場合) { 環境光の反射光の放射輝度を計算して【放射輝度】に代入する. for(全ての光源について繰り返す) { 光源iによるライティングを計算する. 光源iからの光の拡散反射光の放射輝度を計算して【放射輝度】に加算する. 光源iからの光の鏡面反射光の放射輝度を計算して【放射輝度】に加算する. } 【放射輝度】を色に変換して描画色に設定する. } 4. 座標(x,y)を現在の描画色で塗る. } }
強調した交点を探し見つかった場合に放射輝度を計算する,という部分も別のメソッドに分離しておこう.
draw
メソッドの見通しをよくするためという意味もあるが,この部分はこの後に反射や屈折を実装する場合に
単独のメソッドであることが必須となる.
以下のようなシグネチャのメソッドに分離する.
// // 放射輝度の計算を行うメソッド // FColor rayTrace(Scene scene, Ray ray);
rayTrace
メソッドは,Scene
とRay
のインスタンスを引数として受け取り,ray
が示す半直線に物体が存在する場合,
その交点における放射輝度を計算して返すメソッドである.ray
の方向に交差する物体がなければnull
を返す.
このメソッドによってdraw
メソッドは以下のように単純化される.
for(yを0からH-1まで繰り返す) { for(xを0からW-1まで繰り返す) { 1. 座標(x,y)における視線方向を計算する. 2. 視線方向における放射輝度を計算する(rayTrace) 3. 放射輝度を色に変換して描画色に設定する. 4. 座標(x,y)を現在の描画色で塗る. } }
課題
前提
課題2-8,課題2-9ともにシーンそのものは変更しないため,出力結果は「課題2-7 光源を複数にする」と同じである. 前述までの改変を与えても以下と同じ出力が得られなければならない.
課題2-8 testIntersectionWithAll
メソッドを実装する
前述したScene
クラスおよびtestIntersectionWithAll
メソッドを定義してdraw
メソッドを整理せよ.
「課題2-7 光源を複数にする」のスケッチをFullRayTracing
という名前で別名保存(FileメニューのSave Asをクリックして保存)してから取り組むこと.
以下の手順に従え.
G.1) 「課題2-7 光源を複数にする」のスケッチをFullRayTracing
という名前で保存する.
G.2) 以下をクリックすると必要なソースコードがコピーされるので,GeometryUtils
タブの末尾にペーストする.
G.3) Scene
クラスのtestIntersectionWithAll
メソッドに元から書いてある2行を削除し,実装する.
G.4) testIntersectionWithAll
メソッドの使用を前提としてdraw
メソッドを書き換える.
ヒント1
ほぼコピー&ペーストで完成する.
ヒント2
課題2-9 rayTrace
メソッドを実装する
前述したrayTrace
メソッドを定義してdraw
メソッドを整理せよ.
以下の手順に従え.
H.1) スケッチFullRayTracing
のメインのタブの末尾に以下をコピー&ペーストする.
// // 放射輝度の計算を行うメソッド // FColor rayTrace(Scene scene, Ray ray) { // TODO: Implement this method! throw new UnsupportedOperationException("Implement rayTrace(Scene, Ray)!"); }
rayTraceメソッドの仕様を再掲する.
rayTraceメソッドは,SceneとRayのインスタンスを引数として受け取り,rayが示す半直線に物体が存在する場合, その交点における放射輝度を計算して返すメソッドである.rayの方向に交差する物体がなければnullを返す.
H.2) rayTrace
メソッドの元から書いてある2行を削除し,実装する.
H.3) rayTrace
メソッドの使用を前提としてdraw
メソッドを書き換える.
ヒント1
ほぼコピー&ペーストで完成する.
0 Comments.