Chapter8. プログラムの整理と拡張(後編)

プログラムの整理と拡張(後編)

drawメソッドの整理その1

前回までの内容でスケッチをかなり整理できたが,複数の物体や光源に対応するなどの 機能拡張も行ったためdrawメソッドの内容が肥大してしまった.

現在のところdrawメソッドは以下のような処理内容を含んでいる.

リスト1. 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にまとめて,複数の物体の中から最も近い物体を返すメソッドを定義することにしよう.

shapeslightSourcesambientIntensityはいままでグローバル変数として保持していたものと同じである.

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メソッドは以下のようになる.

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メソッドは,SceneRayのインスタンスを引数として受け取り,rayが示す半直線に物体が存在する場合, その交点における放射輝度を計算して返すメソッドである.rayの方向に交差する物体がなければnullを返す.

このメソッドによってdrawメソッドは以下のように単純化される.

3. 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 光源を複数にする」と同じである. 前述までの改変を与えても以下と同じ出力が得られなければならない.

図1. HalfRayTracing_MultiLightsの生成結果

課題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

+ クリックで表示 クリックで非表示

ほぼコピー&ペーストで完成する.

-クリックで非表示

ヒント2

+ シェフの気まぐれ穴埋めソース クリックで非表示
-クリックで非表示

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>