1. 源代码
1.1 phong_fragment_shader()
Blinn-Phong 模型计算 Fragment Color
Eigen::Vector3f phong_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
Eigen::Vector3f kd = payload.color;
Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);
auto l1 = light{{20, 20, 20}, {500, 500, 500}};
auto l2 = light{{-20, 20, 0}, {500, 500, 500}};
std::vector<light> lights = {l1, l2};
Eigen::Vector3f amb_light_intensity{10, 10, 10};
Eigen::Vector3f eye_pos{0, 0, 10};
float p = 150;
Eigen::Vector3f color = payload.color;
Eigen::Vector3f point = payload.view_pos;
Eigen::Vector3f normal = payload.normal;
Eigen::Vector3f result_color = {0, 0, 0};
for (auto& light : lights)
{
// TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular*
// components are. Then, accumulate that result on the *result_color* object.
auto light_vec = light.position - point;
auto view_vec = eye_pos - point;
auto radius2 = light_vec.dot(light_vec);
auto light_vec_norm = light_vec.normalized();
auto view_vec_norm = view_vec.normalized();
// ambient term
result_color += ka.cwiseProduct(amb_light_intensity);
// diffuse term
result_color += kd.cwiseProduct(light.intensity) / radius2
* std::max(0.0f, light_vec_norm.dot(normal));
// specular term
auto h_vec = (light_vec_norm + view_vec_norm).normalized();
result_color += ks.cwiseProduct(light.intensity) / radius2
* std::pow(std::max(0.0f, h_vec.dot(normal)), p);
}
// for debugging
// std::clog << result_color << std::endl;
return result_color * 255.f;
}
1.2 texture_fragment_shader()
将纹理颜色参数视作公式中的 k d k_d kd 。
Eigen::Vector3f texture_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f return_color = {0, 0, 0};
if (payload.texture)
{
// TODO: Get the texture value at the texture coordinates of the current fragment
return_color = payload.texture->getColor(payload.tex_coords(0), payload.tex_coords(1));
}
Eigen::Vector3f texture_color;
texture_color << return_color.x(), return_color.y(), return_color.z();
Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
Eigen::Vector3f kd = texture_color / 255.f;
Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);
auto l1 = light{{20, 20, 20}, {500, 500, 500}};
auto l2 = light{{-20, 20, 0}, {500, 500, 500}};
std::vector<light> lights = {l1, l2};
Eigen::Vector3f amb_light_intensity{10, 10, 10};
Eigen::Vector3f eye_pos{0, 0, 10};
float p = 150;
Eigen::Vector3f color = texture_color;
Eigen::Vector3f point = payload.view_pos;
Eigen::Vector3f normal = payload.normal;
Eigen::Vector3f result_color = {0, 0, 0};
for (auto& light : lights)
{
// TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular*
// components are. Then, accumulate that result on the *result_color* object.
// copied from function *phong_fragment_shader*
auto light_vec = light.position - point;
auto view_vec = eye_pos - point;
auto radius2 = light_vec.dot(light_vec);
auto light_vec_norm = light_vec.normalized();
auto view_vec_norm = view_vec.normalized();
// ambient term
result_color += ka.cwiseProduct(amb_light_intensity);
// diffuse term
result_color += kd.cwiseProduct(light.intensity) / radius2
* std::max(0.0f, light_vec_norm.dot(normal));
// specular term
auto h_vec = (light_vec_norm + view_vec_norm).normalized();
result_color += ks.cwiseProduct(light.intensity) / radius2
* std::pow(std::max(0.0f, h_vec.dot(normal)), p);
}
return result_color * 255.f;
}
1.3 displacement_fragment_shader()
实现 displacement mapping(位移贴图)
Eigen::Vector3f displacement_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
Eigen::Vector3f kd = payload.color;
Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);
auto l1 = light{{20, 20, 20}, {500, 500, 500}};
auto l2 = light{{-20, 20, 0}, {500, 500, 500}};
std::vector<light> lights = {l1, l2};
Eigen::Vector3f amb_light_intensity{10, 10, 10};
Eigen::Vector3f eye_pos{0, 0, 10};
float p = 150;
Eigen::Vector3f color = payload.color;
Eigen::Vector3f point = payload.view_pos;
Eigen::Vector3f normal = payload.normal;
float kh = 0.2, kn = 0.1;
// TODO: Implement displacement mapping here
// Let n = normal = (x, y, z)
// Vector t = (x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z))
// Vector b = n cross product t
// Matrix TBN = [t b n]
// dU = kh * kn * (h(u+1/w,v)-h(u,v))
// dV = kh * kn * (h(u,v+1/h)-h(u,v))
// Vector ln = (-dU, -dV, 1)
// Position p = p + kn * n * h(u,v)
// Normal n = normalize(TBN * ln)
// copied from function *bump_fragment_shader*
// map to local coord. system
Eigen::Vector3f n = normal;
Eigen::Vector3f t;
t << n.x()*n.y()/std::sqrt(n.x()*n.x()+n.z()*n.z()),
std::sqrt(n.x()*n.x()+n.z()*n.z()),
n.z()*n.y()/std::sqrt(n.x()*n.x()+n.z()*n.z());
Eigen::Vector3f b = n.cross(t);
Eigen::Matrix3f TBN;
TBN << t, b, n;
// finite difference
float u = payload.tex_coords(0), v = payload.tex_coords(1);
float w = payload.texture->width;
float h = payload.texture->height;
// w: width of texture
float dU = kh * kn * ( payload.texture->getColor(u+1.0f/w, v).norm() - payload.texture->getColor(u, v).norm() );
// h: height of texture
float dV = kh * kn * ( payload.texture->getColor(u+1, v+1.0f/h).norm() - payload.texture->getColor(u, v).norm() );
Eigen::Vector3f ln = {-dU, -dV, 1.0f};
// displacement
point += kn * n * payload.texture->getColor(u, v).norm();
normal = (TBN * ln).normalized();
Eigen::Vector3f result_color = {0, 0, 0};
for (auto& light : lights)
{
// TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular*
// components are. Then, accumulate that result on the *result_color* object.
// copied from function *phong_fragment_shader*
auto light_vec = light.position - point;
auto view_vec = eye_pos - point;
auto radius2 = light_vec.dot(light_vec);
auto light_vec_norm = light_vec.normalized();
auto view_vec_norm = view_vec.normalized();
// ambient term
result_color += ka.cwiseProduct(amb_light_intensity);
// diffuse term
result_color += kd.cwiseProduct(light.intensity) / radius2
* std::max(0.0f, light_vec_norm.dot(normal));
// specular term
auto h_vec = (light_vec_norm + view_vec_norm).normalized();
result_color += ks.cwiseProduct(light.intensity) / radius2
* std::pow(std::max(0.0f, h_vec.dot(normal)), p);
}
return result_color * 255.f;
}