作业要求
完善以下函数:
rasterize_triangle(const Triangle& t) // 在此处实现与作业2 类似的插值算法,实现法向量、颜色、纹理颜色的插值。
get_projection_matrix() // 将你自己在之前的实验中实现的投影矩阵填到此处,此时你可以运行./Rasterizer output.png normal 来观察法向量实现结果。
phong_fragment_shader() // 实现Blinn-Phong模型计算Fragment Color.
texture_fragment_shader() // 在实现Blinn-Phong的基础上,将纹理颜色视为公式中的kd,实现Texture Shading Fragment Shader.
bump_fragment_shader() // 在实现Blinn-Phong 的基础上,仔细阅读该函数中的注释,实现Bump mapping.
displacement_fragment_shader() // 在实现 Bump mapping 的基础上,实现displacement mapping.作业实现
三角形光栅化
直接按照注释中的提示,实现三角形光栅化即可。
void rst::rasterizer::rasterize_triangle(
const Triangle &t, const std::array<Eigen::Vector3f, 3> &view_pos) {
auto v = t.toVector4();
const int x_min =
static_cast<int>(std::min(v[0].x(), std::min(v[1].x(), v[2].x())));
const int x_max =
static_cast<int>(std::max(v[0].x(), std::max(v[1].x(), v[2].x())));
const int y_min =
static_cast<int>(std::min(v[0].y(), std::min(v[1].y(), v[2].y())));
const int y_max =
static_cast<int>(std::max(v[0].y(), std::max(v[1].y(), v[2].y())));
for (auto x = x_min; x <= x_max; x++) {
for (auto y = y_min; y <= y_max; y++) {
if (insideTriangle(x, y, t.v)) {
auto [alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
float Z = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
float zp = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() +
gamma * v[2].z() / v[2].w();
zp *= Z;
Z = -Z;
zp = -zp;
int ind = get_index(x, y);
if (zp < depth_buf[ind]) {
depth_buf[ind] = zp;
auto interpolated_color = interpolate(alpha, beta, gamma, t.color[0],
t.color[1], t.color[2], 1);
auto interpolated_normal = interpolate(
alpha, beta, gamma, t.normal[0], t.normal[1], t.normal[2], 1);
auto interpolated_texcoords =
interpolate(alpha, beta, gamma, t.tex_coords[0], t.tex_coords[1],
t.tex_coords[2], 1);
auto interpolated_shadingcoords = interpolate(
alpha, beta, gamma, view_pos[0], view_pos[1], view_pos[2], 1);
fragment_shader_payload payload(
interpolated_color, interpolated_normal.normalized(),
interpolated_texcoords, texture ? &*texture : nullptr);
payload.view_pos = interpolated_shadingcoords;
auto pixel_color = fragment_shader(payload);
set_pixel(Vector2i(x, y), pixel_color);
}
}
}
}
}实现Blinn-Phong模型计算Fragment Color
其中
Eigen::Vector3f light_vector = (light.position - point).normalized();
Eigen::Vector3f view_vector = (eye_pos - point).normalized();
Eigen::Vector3f half_vector = (light_vector + view_vector).normalized();
Eigen::Vector3f n_vector = normal.normalized();
float r2 = (light.position - point).dot(light.position - point);
// ambient
Eigen::Vector3f la = ka.cwiseProduct(amb_light_intensity);
// diffuse
Eigen::Vector3f ld = kd.cwiseProduct(light.intensity / r2) *
std::max(0.0f, n_vector.dot(light_vector));
// specular
Eigen::Vector3f ls = ks.cwiseProduct(light.intensity / r2) *
std::pow(std::max(0.0f, n_vector.dot(half_vector)), p);
result_color += la + ld + ls;实现Texture Shading Fragment Shader
把纹理颜色视为公式中的 ,实现Texture Shading Fragment Shader。
return_color = payload.texture->getColor(payload.tex_coords.x(),
payload.tex_coords.y());实现Bump mapping
Bump mapping 是一种通过法线贴图来模拟表面细节的技术。在实现 Bump mapping 的基础上,我们需要计算出偏移后的法线。这里参考注释。
float x = normal.x();
float y = normal.y();
float z = normal.z();
Eigen::Vector3f t = {x * y / sqrt(x * x + z * z), sqrt(x * x + z * z),
z * y / sqrt(x * x + z * z)};
Eigen::Vector3f b = normal.cross(t);
Eigen::Matrix3f TBN;
TBN << t, b, normal;
float u = payload.tex_coords.x();
float v = payload.tex_coords.y();
float dU =
kh * kn *
(payload.texture->getColor(u + 1.0f / payload.texture->width, v).norm() -
payload.texture->getColor(u, v).norm());
float dV =
kh * kn *
(payload.texture->getColor(u, v + 1.0f / payload.texture->height).norm() -
payload.texture->getColor(u, v).norm());
Eigen::Vector3f ln = {-dU, -dV, 1};
normal = (TBN * ln).normalized();
Eigen::Vector3f result_color = {0, 0, 0};
result_color = normal;实现displacement mapping
在实现 Bump mapping 的基础上,我们需要计算出偏移后的顶点位置。这里参考注释。
point = point + kn * normal * payload.texture->getColor(u, v).norm();双线性纹理插值
Eigen::Vector3f getColorBilinear(float u, float v) {
u = u * width;
v = (1 - v) * height;
int u0 = (int)u;
int v0 = (int)v;
int u1 = std::min(u0 + 1, width - 1);
int v1 = std::min(v0 + 1, height - 1);
float du = u - u0;
float dv = v - v0;
auto color0 = image_data.at<cv::Vec3b>(v0, u0);
auto color1 = image_data.at<cv::Vec3b>(v0, u1);
auto color2 = image_data.at<cv::Vec3b>(v1, u0);
auto color3 = image_data.at<cv::Vec3b>(v1, u1);
Eigen::Vector3f color;
for (int i = 0; i < 3; i++) {
color[i] = (1 - du) * (1 - dv) * color0[i] + du * (1 - dv) * color1[i] +
(1 - du) * dv * color2[i] + du * dv * color3[i];
}
return color;
}