Chapter7. プログラムの整理と拡張(中編)

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

材質に関する整理

「課題2-5. 複数の物体を表示する」では複数の物体を表示させたが, 全ての物体が同じ色で描画されていた


図1. HalfRayTracing_MultiShapesの生成画像

これは反射係数などの値を全ての物体で共有していたためである.物体ごとにその表面の材質は異なるため, 反射係数などは個々の物体に紐付くデータと考えるのが自然である.そこでこの部分もクラスとして整理しよう.

反射係数などのパラメータは,前回までのスケッチだと以下のように定義していた.以下はスケッチの冒頭部分である.

PVector eyePos; // 視点位置
ArrayList<Shape> shapes; // 物体

LightSource lightSource;      // 光源
FColor      ambientIntensity; // 環境光の強さ

FColor kAmb;      // 環境光反射係数
FColor kDif;      // 拡散反射係数
FColor kSpe;      // 鏡面反射係数
float  shininess; // 光沢度

kAmb(環境光反射係数),kDif(拡散反射係数),kSpe(鏡面反射係数),shininess(光沢度)である. 前回までのスケッチではこれらはグローバル変数として管理していた.今回はこれらを4つのFColorと一つのfloat型を含む Material(材質)クラスに整理する.

ambientFactorが環境光反射係数,diffuseFactorが拡散反射係数,specularFactorが鏡面反射係数, shininessが光沢度である.この情報を物体を表すクラスShapeに関連づけるため,ShapeクラスにこのMaterialクラスの属性を追加する.

以下のように使用する.

Shape hoge = /* 何らかの物体オブジェクトを生成 */;

// 材質の情報を設定する.
hoge.material.ambientFactor.set(0.01, 0.01, 0.01); // 環境光反射係数
hoge.material.diffuseFactor.set(0.69, 0.69, 0.69); // 拡散反射係数
hoge.material.specularFactor.set(0.30, 0.30, 0.30); // 鏡面反射係数
hoge.material.shininess = 8.0; // 光沢度

複数の光源に対応する

前回までのスケッチでは,光源を一つに限定していた.

Phongの反射モデルでは,物体表面の反射光の輝度を以下のように表現すると述べた.

\( R_{r} = R_{a} + R_{d} + R_{s} \)
  • $$R_{a}$$:環境光の反射光の輝度
  • $$R_{d}$$:直接光の拡散反射光の輝度
  • $$R_{s}$$:直接光の鏡面反射光の輝度

Phongの反射モデルは本来複数の光源を考慮している.本来の式は以下である.

\( \displaystyle R_{r} = R_{a} + \sum_{\cal lights}\left(R_{di} + R_{si} \right) \)
  • $$R_{a}$$:環境光の反射光の輝度
  • $$R_{di}$$:i番目の光源からの直接光の拡散反射光の輝度
  • $$R_{si}$$:i番目の光源からの直接光の鏡面反射光の輝度

物体表面の輝度は,シーンの環境光と,シーンに存在する全ての光源からの光の反射光の総和となっている(図2).

図2. 複数の光源

放射輝度の計算は以下のようになる.

リスト1. 放射輝度の計算
if(視線レイと物体が交点を持つ場合)
{
  環境光の反射光の放射輝度を計算して【放射輝度】に代入する.

  for(全ての光源について繰り返す)
  {
    光源iからの光の拡散反射光の放射輝度を計算して【放射輝度】に加算する.

    光源iからの光の鏡面反射光の放射輝度を計算して【放射輝度】に加算する.
  }

  【放射輝度】を色に変換して描画色に設定する.
}

課題

課題2-6 物体ごとに色を変更する

「課題2-5. 複数の物体を表示する」を改造して,物体ごとに物体表面の色を変更できるようにせよ. このスケッチはHalfRayTracing_Materialという名前で保存すること(手順は後述する).

表示すべき物体は課題2-5と同じであるが,色の設定は以下のようにせよ.デフォルト値ではない部分は赤字にしてある.

  1. 球1
    • 中心$$(3,0,25)$$,半径$$1$$
    • 材質
      • 環境光反射係数:$$(0.01, 0.01, 0.01)$$
      • 拡散反射係数:$$(0.69, 0.00, 0.00)$$
      • 鏡面反射係数:$$(0.30, 0.30, 0.30)$$
      • 光沢度:$$8$$
  2. 球2
    • 中心$$(2,0,20)$$,半径$$1$$
    • 材質
      • 環境光反射係数:$$(0.01, 0.01, 0.01)$$
      • 拡散反射係数:$$(0.00, 0.69, 0.00)$$
      • 鏡面反射係数:$$(0.30, 0.30, 0.30)$$
      • 光沢度:$$8$$
  3. 球3
    • 中心$$(1,0,15)$$,半径$$1$$
    • 材質
      • 環境光反射係数:$$(0.01, 0.01, 0.01)$$
      • 拡散反射係数:$$(0.00, 0.00, 0.69)$$
      • 鏡面反射係数:$$(0.30, 0.30, 0.30)$$
      • 光沢度:$$8$$
  4. 球4
    • 中心$$(0,0,10)$$,半径$$1$$
    • 材質
      • 環境光反射係数:$$(0.01, 0.01, 0.01)$$
      • 拡散反射係数:$$(0.00, 0.69, 0.69)$$
      • 鏡面反射係数:$$(0.30, 0.30, 0.30)$$
      • 光沢度:$$8$$
  5. 球5
    • 中心$$(-1,0,5)$$,半径$$1$$
    • 材質
      • 環境光反射係数:$$(0.01, 0.01, 0.01)$$
      • 拡散反射係数:$$(0.69, 0.00, 0.69)$$
      • 鏡面反射係数:$$(0.30, 0.30, 0.30)$$
      • 光沢度:$$8$$
  6. 平面
    • 法線方向$$(0,1,0)$$, 位置$$(0,-1,0)$$
    • 材質
      • 環境光反射係数:$$(0.01, 0.01, 0.01)$$
      • 拡散反射係数:$$(0.69, 0.69, 0.69)$$
      • 鏡面反射係数:$$(0.30, 0.30, 0.30)$$
      • 光沢度:$$8$$

生成結果は以下のようになる.

図3. HalfRayTracing_Materialの生成結果

この課題ではMaterialクラスを追加する必要がある.以下の手順に従え.

F.1) 「課題2-5. 複数の物体を表示する」のスケッチをHalfRayTracing_Materialという名前で保存する.

F.2) 以下をクリックすると必要なソースコードがコピーされるので,GeometryUtilsタブの末尾にペーストする.

F.3) GeometryUtilsの84行目付近にShapeクラスの定義がある.このクラスにMeterialクラスのパブリックな属性materialを追加する.

変更前のコード
abstract class Shape
{
  public abstract IntersectionPoint testIntersection(Ray ray);
}
変更後のコード
abstract class Shape
{
  public Material material = new Material(); // <- 追加
  public abstract IntersectionPoint testIntersection(Ray ray);
}

F.4) シーン中の各物体が上述の設定になるようにプログラム全体を修正する.

ヒント

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

課題2-7 光源を複数にする

「課題2-6 物体ごとに色を変更する」を改造して,光源を複数設定できるようにせよ.
課題2-6のスケッチをHalfRayTracing_MultiLightsという名前で別名保存(ファイルメニューの名前を付けて保存をクリックして保存)してからとりくむこと.

設定するべき光源は以下の通りである.

  1. 点光源1
    • 位置$$(-5, 5, -5)$$
    • 光の強度$$(0.5, 0.5, 0.5)$$
  2. 点光源2
    • 位置$$(5, 0, -5)$$
    • 光の強度$$(0.5, 0.5, 0.5)$$
  3. 点光源3
    • 位置$$(5, 20, -5)$$
    • 光の強度$$(0.5, 0.5, 0.5)$$

複数の光源を保持するには,「課題2-5. 複数の物体を表示する」と同様に ArrayList<E>を用いる.以下のように使用する.

ArrayList<LightSource> lightSources; // 光源のリスト
// ..中略..

void setup()
{
  // ..中略..
  lightSources = new ArrayList<LightSource>(); // 光源のリストを生成

  LightSource piyo = /* 何らかの光源オブジェクト */ ;
  lightSources.add(piyo); // 光源のリストに追加
}

リスト内の要素を反復するには以下のようにする.

// リスト内の各要素を処理する
for(int i = 0; i < lightSources.size(); ++i)
{
  LightSource light = lightSources.get(i);
  // 何かの処理
}//for

// 以下でも同じ(こちらの方が簡潔)
for(LightSources light : lightSources)
{
  // 何かの処理
}//for

生成結果は以下のようになる.

図3. HalfRayTracing_MultiLightsの生成結果

ヒント

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

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>