課題04:拡散反射と鏡面反射

(1)完全拡散反射面に対する陰影付け

課題03で作成したプログラムを, 以下の方法で陰影付けを行うよう変更します.

環境光に対する反射係数 Ka, 物体表面の拡散反射係数 Kd, 物体表面の法線ベクトル N, 光線ベクトル L, 光源の強度 Il, 環境光の強度 Ia から,完全拡散反射面における反射光強度 I を求める関数 shade() を作成し,render() の前に置いてください.

void shade(const float *l, const float *n,
           const struct Material *k, float *i)
{
  /*
  ** 光線ベクトル L,物体表面の法線ベクトル N,
  ** 環境光に対する反射係数 Ka,
  ** 物体表面の拡散反射係数 Kd,
  ** 光源の強度 Il,環境光の強度 Ia から,
  ** 完全拡散反射面における反射光強度 I を求める
  */
}
Ka および Kd は,それぞれ Material という構造体の変数 red の a と d という要素に格納するものとします. したがって関数 shade() は,Material という構造体のポインタを引数として受け取り, それを介して Ka および Kd を取り出すようにします.

struct Material {
  float a[3];  /* 環境光に対する反射係数 Ka */
  float d[3];  /* 物体表面の拡散反射係数 Kd */
};

struct Material red = {
  { 0.5, 0.1, 0.1 },
  { 0.5, 0.1, 0.1 },
};

また,これらの材質パラメータを物体のデータと結びつけるために, 構造体 Sphere の要素に構造体 Material を指すポインタの要素 k を追加し,それを red のポインタで初期化しておきます.

struct Sphere {
  float p[3];  /* 球の中心位置 Pc */
  float r;     /* 球の半径 r */
  struct Material *k;
};

struct Sphere sphere = {
  { 0.0, 0.0, 4.0 },
  2.0,
  &red,
};

L および Il は,それぞれ Light という構造体の変数 light の p と i という要素に格納するものとします.また Ia は ia という配列変数に格納するものとします.

struct Light {
  float p[3];  /* 光線ベクトル L */
  float i[3];  /* 光源の強度 Il */
};

struct Light light = {
  { 0.424, 0.566, -0.707 },
  { 1.0, 1.0, 1.0 },
};

float ia[] = { 0.2, 0.2, 0.2 };  /* 環境光の強度 Ia */

どうしても分からなければ…

この関数 shade() を用いて, 以下の条件で反射光強度 I を求め, これをその画素における色 c に用いて画像を生成してください.

ちなみに (0.424, 0.566, -0.707) ≒ (3, 4, -5) / |(3, 4, -5)|

(2)鏡面反射成分を含んだ陰影付け

関数 shade() に視線ベクトル V, 物体表面の鏡面反射係数 Ks およびハイライトの広がり(輝き係数)Ke を与えて, 鏡面反射成分を含んだ反射光強度 I を求めるよう修正してください.

void shade(const float *l, const float *n, const float *v,
           const struct Material *k, float *i)
{
  /*
  ** 光線ベクトル L,物体表面の法線ベクトル N,
  ** 視線ベクトル V,
  ** 環境光に対する反射係数 Ka,
  ** 物体表面の拡散反射係数 Kd,
  ** 物体表面の鏡面反射係数 Ks,
  ** ハイライトの広がり(輝き係数)Ke,
  ** 光源の強度 Il,環境光の強度 Ia から,
  ** 完全拡散反射面における反射光強度 I を求める
  */
}

Ks および Ke は,構造体 Material の要素に s と e を追加し,この構造体の変数 red のそれぞれの要素に格納するものとします.

struct Material {
  float a[3];  /* 環境光に対する反射係数 Ka */
  float d[3];  /* 物体表面の拡散反射係数 Kd */
  float s[3];  /* 物体表面の鏡面反射係数 Ks */
  float e;     /* ハイライトの広がり */
};

struct Material red = {
  { 0.5, 0.1, 0.1 },
  { 0.5, 0.1, 0.1 },
  { 0.4, 0.4, 0.4 },
  40.0,
};

どうしても分からなければ…

修正した関数 shade() を用いて, 以下の条件で反射光強度 I を求め, これをその画素における色 c に用いて画像を生成してください.

(3)点光源による陰影付け

光線ベクトル L を光源の位置 Pl と交点の位置 P から求めて, 点光源による陰影付けを行ってください.

Pl は構造体 Light の変数 light の要素 p に格納するものとします.

struct Light {
  float p[3];  /* 光線の位置 Pl */
  float i[3];  /* 光源の強度 Il */
};

struct Light light = {
  { 3.0, 4.0, -5.0 },
  { 1.0, 1.0, 1.0 },
};

修正した関数 shade() を用いて, 以下の条件で反射光強度 I を求め, これをその画素における色 c に用いて画像を生成してください.

点光源の場合, 照射点に届く入射光の密度は光源と照射点の間の距離の2乗に反比例します. 画像が暗すぎる場合は光源の強度を調整するか, あるいは(邪道ですが,OpenGL なんかでもやっている) 入射光の密度を光源と照射点の間の距離(の1乗)に反比例するようにしたり, 距離に依存しないようにしてみてください.

どうしても分からなければ…

【次:課題05】