在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;
}

随机推荐

  1. Mac 使用远程 Ubuntu 机器进行时间备份

    设置 SMB 服务 首先在 Ubuntu 中配置 SMB 服务.可以参考 Ubuntu 设置 SMB 服务. 创建 APFS 磁盘映像 我们在 Ubuntu 上创建出的 SMB 共享文件夹可以用来存放 ...

  2. 【LLM训练系列】从零开始训练大模型之Phi2-mini-Chinese项目解读

    一.前言 本文主要是在复现和实践Phi2-mini-Chinese后,简要分析下Phi2-mini-Chinese这个项目,做一个学习实战总结. 原文发布于知乎:https://zhuanlan.zh ...

  3. 一款超级给力的弱网测试神器—Qnet(附视频)

    一.APP弱网测试背景 App在使用的过程中,难免会遇到不同的弱网络环境,像在公车上.在地铁.地下车库等.在这种情况下,手机常常会出现网络抖动.上行或下行超时,导致APP应用中出现丢包延迟,从而影响用 ...

  4. 5G网元功能与接口

    5G网元功能与接口 5G移动通信整体网络架构 5G网络功能之间的信息交互可以基于两种方式表示:其一为基于服务表示:其二为基于点对点表示.实时部署时,也可以采用两种方式相结合的表示方式. 并不是所有的接 ...

  5. flink 大批量任务提交 yarn 失败问题

    问题现象 用户迁移到新集群后,反馈他们开发平台大量 flink 任务提交失败了,当时集群的 yarn 资源是足够的 排查过程 用户是在他们的开发平台上提交的,查看他们失败的任务,发现是他们提交端主动 ...

  6. Kubernetes Deployment控制器(二十)

    前面我们学习了 ReplicaSet 控制器,了解到该控制器是用来维护集群中运行的 Pod 数量的,但是往往在实际操作的时候,我们反而不会去直接使用 RS,而是会使用更上层的控制器,比如我们今天要学习 ...

  7. Blazor 子组件与父组件通过 ChildEvents 传递数据的方法

    想要实现 Blazor 子组件向父组件传递数据, 参考 痴者工良的博文所描述的方式, .Net 5.0 下编译未能通过, 于是先修改一下, 简化为光触发事件通知而不传值 子组件 Child.razor ...

  8. 3. 用过Konva吗,用过他的api吗

    基础:使用konva,首先需要创建舞台也就是stage,然后创建一个Layer图层,将图层放到舞台上,将图形等内容放到图层上 ; 第一步:创建一个Stage舞台  , 就是创建一个 stage 实例 ...

  9. 5.flask 源码解析:请求

    目录 一.flask 源码解析:请求 1.1 简介 1.2 请求 Flask 源码分析完整教程目录:https://www.cnblogs.com/nickchen121/p/14763457.htm ...

  10. Android复习(三)清单文件中的元素——>uses-sdk

    <uses-sdk> Google Play 会利用在应用清单中声明的 <uses-sdk> 属性,从不符合其平台版本要求的设备上滤除您的应用.在设置这些属性前,请确保您了解  ...