問1
Rayの方向を法線で反射させた方向を返す関数Vec3 reflect(const Vec3& d, const Vec3& n)を作れ。
解答例
まず反射した方向を求める。
を水平な成分と垂直な成分(に平行)に分解することを考えよう。するとは
と書ける。
は
と書ける。よっては
と書ける。
反射した方向も同様に水平成分、垂直成分に分解すると
と書けるから
この式で反射ベクトルが計算できる。
Vec3 reflect(const Vec3& d, const Vec3& n) {
return d - 2*dot(d, n)*n;
}
問2
Phongの反射モデルを使って陰影計算を行ってみましょう。
Phongの反射モデルでは、光源の方向を、Rayの方向を、衝突点の法線をとし、をで反射させたものをとすると、光の強さは
で与えられます。
はを満たすの区間に含まれる実数です。はハイライトの強さを制御する0以上の実数です。これらのパラメーターを色々と変化させて画像を生成してみてください。
解答例
問1で実装したreflect()を使ってを計算できる。
#include "vec3.h"
#include "image.h"
#include "sphere.h"
#include "camera.h"
Vec3 reflect(const Vec3& d, const Vec3& n) {
return d - 2*dot(d, n)*n;
}
int main() {
Image img(512, 512);
Camera cam(Vec3(0, 0, -3), Vec3(0, 0, 1));
Sphere sphere(Vec3(0, 0, 0), 1.0);
Vec3 sunDir = normalize(Vec3(1, 1, -1));
double kd = 0.5;
double ks = 0.5;
double alpha = 128.0;
for(int i = 0; i < img.width; i++) {
for(int j = 0; j < img.height; j++) {
double u = (2.0*i - img.width)/img.width;
double v = (2.0*j - img.height)/img.height;
Ray ray = cam.getRay(u, v);
Hit hit;
if(sphere.intersect(ray, hit)) {
Vec3 color = Vec3(1, 1, 1);
Vec3 r = reflect(-1*sunDir, hit.hitNormal);
double I = kd*std::max(dot(hit.hitNormal, sunDir), 0.0) + ks*std::pow(std::max(dot(-1*ray.direction, r), 0.0), alpha);
img.setPixel(i, j, I*color);
}
else {
img.setPixel(i, j, Vec3(0, 0, 0));
}
}
}
img.ppm_output();
}