games101_Homework3
在Raster部分实现数值插值,然后实现四种不同的像素着色器
作业描述:
作业1:修改函数 rasterize_triangle(const Triangle& t) in rasterizer.cpp: 在此 处实现与作业 2 类似的插值算法,实现法向量、颜色、纹理颜色的插值。
在rasterize_triangle函数中重复上次的包围盒进行点采样,在深度测试通过之后分别对法向量、颜色、纹理颜色、视图空间坐标做插值,然后通过shader计算出像素颜色后设定其值。

//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos) //t为经mvp变换后的顶点坐标,view_pos为mv变换后顶点在视图空间中的位置
{
// TODO: From your Homework3, get the triangle rasterization code.
auto v = t.toVector4(); // t.to is array<Vector4f, 3>,为三角形三个顶点坐标的齐次坐标表达 // Find out the bounding box of current triangle.
float min_x, max_x, min_y, max_y;
min_x = std::min(v[0].x(), std::min(v[1].x(), v[2].x()));
max_x = std::max(v[0].x(), std::max(v[1].x(), v[2].x()));
min_y = std::min(v[0].y(), std::min(v[1].y(), v[2].y()));
max_y = std::max(v[0].y(), std::max(v[1].y(), v[2].y())); // iterate through the pixel and find if the current pixel is inside the triangle
for(int x = min_x; x < max_x; ++x){
for(int y = min_y; y < max_y; ++y){
if(insideTriangle((float)x + 0.5, (float)y + 0.5, t.v)){
// If so, use the following code to get the interpolated z value.
// TODO: Inside your rasterization loop:
// * v[i].w() is the vertex view space depth value z.
// * Z is interpolated view space depth for the current pixel
// * zp is depth between zNear and zFar, used for z-buffer
auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v); //计算(x,y)点的重心坐标
float Z = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w()); //Z是当前像素的视图空间深度(插值),v[i].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; //zp是nf之间的深度 if(zp < depth_buf[get_index(x, y)]){
// set the z_buffer
depth_buf[get_index(x, y)] = zp; // TODO: Interpolate the attributes:
// auto interpolated_color
// auto interpolated_normal
// auto interpolated_texcoords
// auto interpolated_shadingcoords //着色点在 // Use: fragment_shader_payload payload( interpolated_color, interpolated_normal.normalized(), interpolated_texcoords, texture ? &*texture : nullptr);
// Use: payload.view_pos = interpolated_shadingcoords;
// Use: Instead of passing the triangle's color directly to the frame buffer, pass the color to the shaders first to get the final color;
// Use: auto pixel_color = fragment_shader(payload);
// 调用准备好的interpolate()函数获取这些属性的插值
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); //着色点在mv变换后可视空间的真实坐标
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); //调用我们设置的fragment_shader进行点的像素的着色 set_pixel(Vector2i(x, y), pixel_color); //调用写好的set_pixel函数写入framebuffer
}
}
}
}
}
注:本次作业的insideTriangle依然需要修改传入接口为 static bool insideTriangle(float x, float y, const Vector4f* _v)
作业2:修改函数 phong_fragment_shader() in main.cpp: 实现 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. // L = (Ka * Ia) + (Kd * I/r^2 * max(0, n·l)) + (Ks * (I / r^2) * max(0, n · h)^p)
// 光照方向
Eigen::Vector3f light_direc = (light.position - point).normalized();
// 视线方向
Eigen::Vector3f eye_direc = (eye_pos - point).normalized();
// 半程向量
Eigen::Vector3f half_vector = (light_direc + eye_direc).normalized();
// 距离的平方
float R2 = (light.position - point).squaredNorm(); // 环境光
auto ambient = ka.cwiseProduct(amb_light_intensity);
// 漫反射
auto diffuse = kd.cwiseProduct(light.intensity / R2) * std::max(0.0f, normal.dot(light_direc)) ;
// 高光
auto specular = ks.cwiseProduct(light.intensity / R2) * std::pow(std::max(0.0f, normal.dot(half_vector)), p); result_color += (ambient + diffuse + specular);
} return result_color * 255.f;
}
作业3:修改函数 texture_fragment_shader() in main.cpp: 在实现 Blinn-Phong 的基础上,将纹理颜色视为公式中的 kd,实现 Texture Shading Fragment Shader.

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. // L = (Ka * Ia) + (Kd * I/r^2 * max(0, n·l)) + (Ks * (I / r^2) * max(0, n · h)^p)
// 光照方向
Eigen::Vector3f light_direc = (light.position - point).normalized();
// 视线方向
Eigen::Vector3f eye_direc = (eye_pos - point).normalized();
// 半程向量
Eigen::Vector3f half_vector = (light_direc + eye_direc).normalized();
// 距离的平方
float R2 = (light.position - point).squaredNorm(); // 环境光
auto ambient = ka.cwiseProduct(amb_light_intensity);
// 漫反射
auto diffuse = kd.cwiseProduct(light.intensity / R2) * std::max(0.0f, normal.dot(light_direc)) ;
// 高光
auto specular = ks.cwiseProduct(light.intensity / R2) * std::pow(std::max(0.0f, normal.dot(half_vector)), p); result_color += (ambient + diffuse + specular);
} return result_color * 255.f;
}
作业4:修改函数 bump_fragment_shader() in main.cpp: 在实现 Blinn-Phong 的 基础上,仔细阅读该函数中的注释,实现 Bump mapping,将新的法线设置为颜色值。

Eigen::Vector3f bump_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 bump 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)
// Normal n = normalize(TBN * ln) auto n = normal;
auto x = n.x();
auto y = n.y();
auto z = n.z();
Vector3f t(x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z));
Vector3f b = n.cross(t);
auto u = payload.tex_coords.x(); //在切线空间中的x坐标
auto v = payload.tex_coords.y(); //在切线空间中的y坐标 Matrix3f TBN;
TBN << t.x(), t.y(), t.z(),
b.x(), b.y(), b.z(),
n.x(), n.y(), n.z();
// 纹理实际宽度
auto w = payload.texture->width;
// 纹理实际高度
auto h = payload.texture->height;
// U、V方向的切线(导数)
auto dU = kh * kn * (payload.texture->getColor(u + 1.0f / w, v).norm() - payload.texture->getColor(u,v).norm());
auto dV = kh * kn * (payload.texture->getColor(u, v + 1.0f / h).norm() - payload.texture->getColor(u,v).norm());
// 当前点的法向量
Vector3f ln(-dU, -dV, 1); //使用tbn矩阵将法线变换到世界空间中
normal = (TBN * ln).normalized(); // Eigen::Vector3f result_color = {0, 0, 0};
result_color = normal; return result_color * 255.f;
}
作业5:修改函数 displacement_fragment_shader() in main.cpp: 在实现 Bump mapping 的基础上,实现 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) auto n = normal;
auto x = n.x();
auto y = n.y();
auto z = n.z();
Vector3f t(x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z));
Vector3f b = n.cross(t);
auto u = payload.tex_coords.x(); //在切线空间中的x坐标
auto v = payload.tex_coords.y(); //在切线空间中的y坐标
Matrix3f TBN;
TBN << t.x(), t.y(), t.z(),
b.x(), b.y(), b.z(),
n.x(), n.y(), n.z();
auto w = payload.texture->width;
auto h = payload.texture->height;
auto dU = kh * kn * (payload.texture->getColor(u + 1.0f / w, v).norm() - payload.texture->getColor(u,v).norm());
auto dV = kh * kn * (payload.texture->getColor(u, v + 1.0f / h).norm() - payload.texture->getColor(u,v).norm());
Vector3f ln(-dU, -dV, 1); // 计算当前点新的位置,产生位移
point += (kn * normal * 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. // L = (Ka * Ia) + (Kd * I/r^2 * max(0, n·l)) + (Ks * (I / r^2) * max(0, n · h)^p)
// 光照方向
Eigen::Vector3f light_direc = (light.position - point).normalized();
// 视线方向
Eigen::Vector3f eye_direc = (eye_pos - point).normalized();
// 半程向量
Eigen::Vector3f half_vector = (light_direc + eye_direc).normalized();
// 距离的平方
float R2 = (light.position - point).squaredNorm(); // 环境光
auto ambient = ka.cwiseProduct(amb_light_intensity);
// 漫反射
auto diffuse = kd.cwiseProduct(light.intensity / R2) * std::max(0.0f, normal.dot(light_direc)) ;
// 高光
auto specular = ks.cwiseProduct(light.intensity / R2) * std::pow(std::max(0.0f, normal.dot(half_vector)), p); result_color += (ambient + diffuse + specular);
} return result_color * 255.f;
}
随机推荐
- Mac 使用远程 Ubuntu 机器进行时间备份
设置 SMB 服务 首先在 Ubuntu 中配置 SMB 服务.可以参考 Ubuntu 设置 SMB 服务. 创建 APFS 磁盘映像 我们在 Ubuntu 上创建出的 SMB 共享文件夹可以用来存放 ...
- 【LLM训练系列】从零开始训练大模型之Phi2-mini-Chinese项目解读
一.前言 本文主要是在复现和实践Phi2-mini-Chinese后,简要分析下Phi2-mini-Chinese这个项目,做一个学习实战总结. 原文发布于知乎:https://zhuanlan.zh ...
- 一款超级给力的弱网测试神器—Qnet(附视频)
一.APP弱网测试背景 App在使用的过程中,难免会遇到不同的弱网络环境,像在公车上.在地铁.地下车库等.在这种情况下,手机常常会出现网络抖动.上行或下行超时,导致APP应用中出现丢包延迟,从而影响用 ...
- 5G网元功能与接口
5G网元功能与接口 5G移动通信整体网络架构 5G网络功能之间的信息交互可以基于两种方式表示:其一为基于服务表示:其二为基于点对点表示.实时部署时,也可以采用两种方式相结合的表示方式. 并不是所有的接 ...
- flink 大批量任务提交 yarn 失败问题
问题现象 用户迁移到新集群后,反馈他们开发平台大量 flink 任务提交失败了,当时集群的 yarn 资源是足够的 排查过程 用户是在他们的开发平台上提交的,查看他们失败的任务,发现是他们提交端主动 ...
- Kubernetes Deployment控制器(二十)
前面我们学习了 ReplicaSet 控制器,了解到该控制器是用来维护集群中运行的 Pod 数量的,但是往往在实际操作的时候,我们反而不会去直接使用 RS,而是会使用更上层的控制器,比如我们今天要学习 ...
- Blazor 子组件与父组件通过 ChildEvents 传递数据的方法
想要实现 Blazor 子组件向父组件传递数据, 参考 痴者工良的博文所描述的方式, .Net 5.0 下编译未能通过, 于是先修改一下, 简化为光触发事件通知而不传值 子组件 Child.razor ...
- 3. 用过Konva吗,用过他的api吗
基础:使用konva,首先需要创建舞台也就是stage,然后创建一个Layer图层,将图层放到舞台上,将图形等内容放到图层上 ; 第一步:创建一个Stage舞台 , 就是创建一个 stage 实例 ...
- 5.flask 源码解析:请求
目录 一.flask 源码解析:请求 1.1 简介 1.2 请求 Flask 源码分析完整教程目录:https://www.cnblogs.com/nickchen121/p/14763457.htm ...
- Android复习(三)清单文件中的元素——>uses-sdk
<uses-sdk> Google Play 会利用在应用清单中声明的 <uses-sdk> 属性,从不符合其平台版本要求的设备上滤除您的应用.在设置这些属性前,请确保您了解 ...