作业3
问题描述
重心坐标公式:
auto v = t.toVector4();
// 构建包围盒
float min_x = std::min(v[0][0], std::min(v[1][0], v[2][0]));
float max_x = std::max(v[0][0], std::max(v[1][0], v[2][0]));
float min_y = std::min(v[0][1], std::min(v[1][1], v[2][1]));
float max_y = std::max(v[0][1], std::max(v[1][1], v[2][1]));
//依次遍历包围盒所有像素
for (int x = min_x; x <= max_x; x++)
{
for (int y = min_y; y <= max_y; y++)
{ //判断当前点是否在三角形内
if (insideTriangle(x + 0.5, y + 0.5, t.v))
{
//重心坐标公式 求 alpha, beta, gamma三点值
auto [alpha, beta, gamma] = computeBarycentric2D(x + 0.5, y + 0.5, t.v);
//v[i].w()为顶点视图空间深度值z。
//Z是为当前像素插值的视图空间深度
//zp是zNear和zFar之间的深度,用于z缓冲
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;
//如果当前 深度值小 更新深度值
if (zp < depth_buf[get_index(x, y)])
{
// 根据重心 插入属性 颜色 法线 纹理 材质坐标
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).normalized();
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, interpolated_texcoords, texture ? &*texture : nullptr);
payload.view_pos = interpolated_shadingcoords;
//不是直接将三角形的颜色传递到帧缓冲区,而是首先将颜色传递到着色器以获得最终的颜色
auto pixel_color = fragment_shader(payload);
// 更新深度
depth_buf[get_index(x, y)] = zp;
// 更新颜色
set_pixel(Eigen::Vector2i(x, y), pixel_color);
}
}
}
}
环境光:
漫反射:
高光
Eigen::Vector3f light_dir = light.position - point;// 光线距离
Eigen::Vector3f view_dir = eye_pos - point;// 视线方向
float r = light_dir.dot(light_dir);// 衰减因子
// La 环境光 颜色强度
Eigen::Vector3f La = ka.cwiseProduct(amb_light_intensity);
// Ld 漫反射 (I/(r*r))
Eigen::Vector3f Ld = kd.cwiseProduct(light.intensity / r);//衰减
Ld *= std::max(0.0f, normal.normalized().dot(light_dir.normalized()));
// Ls 高光
Eigen::Vector3f h = (light_dir + view_dir).normalized();//半程向量
Eigen::Vector3f Ls = ks.cwiseProduct(light.intensity / r);//衰减
Ls *= std::pow(std::max(0.0f, normal.normalized().dot(h)), p);
result_color += (La + Ld + Ls);
查找纹理颜色的接口:Vector3f getColor(float u, float v)
Eigen::Vector3f getColor(float u, float v)
{
// 坐标限定
if (u < 0) u = 0;
if (u > 1) u = 1;
if (v < 0) v = 0;
if (v > 1) v = 1;
auto u_img = u * width;
auto v_img = (1 - v) * height;
auto color = image_data.at<cv::Vec3b>(v_img, u_img);
return Eigen::Vector3f(color[0], color[1], color[2]);
}
Eigen::Vector3f return_color = {0, 0, 0};
if (payload.texture)
{
// 在当前片段的纹理坐标处获取纹理值
return_color = payload.texture->getColor(payload.tex_coords.x(), payload.tex_coords.y());
}
Eigen::Vector3f texture_color;
texture_color << return_color.x(), return_color.y(), return_color.z();
//漫反射 反射出 纹理颜色
Eigen::Vector3f kd = texture_color / 255.f;
实现凹凸映射
Eigen::Vector3f n = normal;// Let n = normal = (x, y, z)
float x = normal.x();
float y = normal.y();
float z = normal.z();
// Vector t = (x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z))
Eigen::Vector3f t{ x * y / std::sqrt(x * x + z * z), std::sqrt(x * x + z * z), z * y / std::sqrt(x * x + z * z) };
// Vector b = n cross product t
Eigen::Vector3f b = normal.cross(t);
// Matrix TBN = [t b n]
Eigen::Matrix3f TBN;
TBN << t.x(), b.x(), n.x(),
t.y(), b.y(), n.y(),
t.z(), b.z(), n.z();
float u = payload.tex_coords.x();
float v = payload.tex_coords.y();
float w = payload.texture->width;
float h = payload.texture->height;
// dU = kh * kn * (h(u+1/w,v)-h(u,v))
// dV = kh * kn * (h(u,v+1/h)-h(u,v))
float dU = kh * kn * (payload.texture->getColor(u + 1.0f / w, v).norm() - payload.texture->getColor(u, v).norm());
float dV = kh * kn * (payload.texture->getColor(u, v + 1.0f / h).norm() - payload.texture->getColor(u, v).norm());
// Vector ln = (-dU, -dV, 1)
Eigen::Vector3f ln{ -dU,-dV,1.0f };
// Normal n = normalize(TBN * ln)
n = (TBN * ln).normalized();
return n * 255.f;
凹凸贴图
// TODO: 在这里实现位移映射 同上
// 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)
point += (kn * n * payload.texture->getColor(u, v).norm());
// Normal n = normalize(TBN * ln)