## rasterize_triangle

• 支持对其他指标的插值；
• 支持ssaa；
• 返回的结果为$\sum_{i\in triangleq} s_i / \sum_{i\in triangleq}$；
• 上一讲返回的结果为$\sum_{i\in triangleq} s_i / n^2$；
• 即只关于三角形内部的点求均值；
• ssaa的分别率通过最后一个命令行参数传入；
void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos)
{
// TODO: From your HW3, get the triangle rasterization code.
// 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

// 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;

// TODO: Interpolate the attributes:
// auto interpolated_color
// auto interpolated_normal
// auto interpolated_texcoords

// 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;

// 转换为齐次坐标
auto v = t.toVector4();

// TODO : Find out the bounding box of current triangle.
// bounding box
float x_min = 1e10;
float x_max = -1e10;
float y_min = 1e10;
float y_max = -1e10;
for (int i = 0; i < 3; i++) {
x_min = std::min(x_min, t.v[i](0));
x_max = std::max(x_max, t.v[i](0));
y_min = std::min(y_min, t.v[i](1));
y_max = std::max(y_max, t.v[i](1));
}
int x_min_int = int(x_min);
int x_max_int = int(x_max) + 1;
int y_min_int = int(y_min);
int y_max_int = int(y_max) + 1;

// 支持ssaa
float x, y;
// 间距
float d = 1.0 / n;
for (int i = x_min_int; i <= x_max_int; i++) {
for (int j = y_min_int; j <= y_max_int; j++) {
// 记录super-sample在三角形内的数量
int cnt = 0;
// 记录块内的最小深度
float z_interpolated_min = 1e10;
// msaa内的平均值
Eigen::Vector3f interpolated_color = Eigen::Vector3f::Zero();
Eigen::Vector3f interpolated_normal = Eigen::Vector3f::Zero();
Eigen::Vector2f interpolated_texcoords = Eigen::Vector2f::Zero();
// 记录在区域内的个数
float m = 0;
// 区域内的平均坐标
float x_mean = 0;
float y_mean = 0;
// 遍历每个super-sample
for (int p = 0; p < n; p++) {
for (int q = 0; q < n; q++) {
x = i + (p + 0.5) * d;
y = j + (q + 0.5) * d;
x_mean += x;
y_mean += y;
// 在三角形内则更新cnt
if (insideTriangle(x, y, t.v)) {
cnt++;
// 计算插值深度值
auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
// 齐次坐标系
float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
z_interpolated *= w_reciprocal;
z_interpolated_min = std::min(z_interpolated_min, z_interpolated);
// 计算个指标的插值结果
interpolated_color = interpolated_color + interpolate(alpha, beta, gamma, t.color[0], t.color[1], t.color[2], 1);
interpolated_normal = interpolated_normal + interpolate(alpha, beta, gamma, t.normal[0], t.normal[1], t.normal[2], 1);
interpolated_texcoords = interpolated_texcoords + interpolate(alpha, beta, gamma, t.tex_coords[0], t.tex_coords[1], t.tex_coords[2], 1);
// 更新个数
m += 1;
}
}
}

// 计算均值
interpolated_color = interpolated_color / m;
interpolated_normal = interpolated_normal / m;
interpolated_texcoords = interpolated_texcoords / m;
x_mean /= m;
y_mean /= m;

int index = get_index(i, j);
// 如果平均点在三角形内则生成结果
if (insideTriangle(x_mean, y_mean, t.v)) {
// 越小越近
if (z_interpolated_min < depth_buf[index]) {
// 得到颜色
// 设置颜色
Eigen::Vector2i point(i, j);
set_pixel(point, pixel_color);
// 更新深度
depth_buf[index] = z_interpolated_min;
}
}
}
}
}

./Rasterizer normal_1.png normal 1

./Rasterizer normal_2.png normal 2

• point: 光线打在物体上位置，即上图中三条线的交点；
• light.position: 光源位置；
• normal: $\mathrm n$；
• eye_pos：图中眼睛的位置；

Eigen::Vector3f phong_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
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 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.

Eigen::Vector3f light_direction = (light.position - point);
Eigen::Vector3f viewer_direction = (eye_pos - point);

Eigen::Vector3f intensity = light.intensity / light_direction.squaredNorm();

light_direction = light_direction.normalized();
viewer_direction = viewer_direction.normalized();

Eigen::Vector3f ambient = ka.cwiseProduct(amb_light_intensity);
Eigen::Vector3f diffuse = std::max(0.0f, normal.dot(light_direction)) * kd.cwiseProduct(intensity);
Eigen::Vector3f h = (light_direction + viewer_direction).normalized();
Eigen::Vector3f specular = std::pow(std::max(0.0f, normal.dot(h)), p) * ks.cwiseProduct(intensity);
result_color += ambient + diffuse + specular;
}

return result_color * 255.f;
}

./Rasterizer phong_1.png phong 1

./Rasterizer phong_2.png phong 2

Eigen::Vector3f texture_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f return_color = {0, 0, 0};
{
// TODO: Get the texture value at the texture coordinates of the current fragment
}

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 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.

Eigen::Vector3f light_direction = (light.position - point);
Eigen::Vector3f viewer_direction = (eye_pos - point);

Eigen::Vector3f intensity = light.intensity / light_direction.squaredNorm();

light_direction = light_direction.normalized();
viewer_direction = viewer_direction.normalized();

Eigen::Vector3f ambient = ka.cwiseProduct(amb_light_intensity);
Eigen::Vector3f diffuse = std::max(0.0f, normal.dot(light_direction)) * kd.cwiseProduct(intensity);
Eigen::Vector3f h = (light_direction + viewer_direction).normalized();
Eigen::Vector3f specular = std::pow(std::max(0.0f, normal.dot(h)), p) * ks.cwiseProduct(intensity);
result_color += ambient + diffuse + specular;
}

return result_color * 255.f;
}

./Rasterizer texture_1.png texture 1

./Rasterizer texture_2.png texture 2

• $h$为一个预设的函数，这里助教设置为h(u,v)=texture_color(u,v).norm，该函数是人为随意定义的，没有理论含义；
• $kh, kn$是为了控制生成结果；
• $t$为切线方向，即曲线方程为$f(x,y, z) = y\sqrt{x ^2 +z^2 }$，暂时不知道该方程是人为设置的，还是推导出来的；

Eigen::Vector3f bump_fragment_shader(const fragment_shader_payload& payload)
{

Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
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;

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)

float x = normal.x();
float y = normal.y();
float z = normal.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));
Eigen::Vector3f b = normal.cross(t);
Eigen::Matrix3f TBN;
TBN.col(0) = t;
TBN.col(1) = b;
TBN.col(2) = normal;
// 人为选择的函数
// kh, kn为预设的值, 是为了控制最后颜色
float dU = kh * kn * (payload.texture->getColor(u + 1.0 / w, v).norm() - huv);
float dV = kh * kn * (payload.texture->getColor(u, v + 1.0 / h).norm() - huv);
Eigen::Vector3f ln(-dU, -dV, 1);
normal = (TBN * ln).normalized();

Eigen::Vector3f result_color = {0, 0, 0};
result_color = normal;

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.

Eigen::Vector3f light_direction = (light.position - point);
Eigen::Vector3f viewer_direction = (eye_pos - point);

Eigen::Vector3f intensity = light.intensity / light_direction.squaredNorm();

light_direction = light_direction.normalized();
viewer_direction = viewer_direction.normalized();

Eigen::Vector3f ambient = ka.cwiseProduct(amb_light_intensity);
Eigen::Vector3f diffuse = std::max(0.0f, normal.dot(light_direction)) * kd.cwiseProduct(intensity);
Eigen::Vector3f h = (light_direction + viewer_direction).normalized();
Eigen::Vector3f specular = std::pow(std::max(0.0f, normal.dot(h)), p) * ks.cwiseProduct(intensity);
result_color += ambient + diffuse + specular;
}

return result_color * 255.f;
}

./Rasterizer bump_1.png bump 1

./Rasterizer bump_2.png bump 2

Eigen::Vector3f displacement_fragment_shader(const fragment_shader_payload& payload)
{

Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
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;

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 point = point + kn * n * h(u,v)
// Normal n = normalize(TBN * ln)

float x = normal.x();
float y = normal.y();
float z = normal.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));
Eigen::Vector3f b = normal.cross(t);
Eigen::Matrix3f TBN;
TBN.col(0) = t;
TBN.col(1) = b;
TBN.col(2) = normal;
// 人为选择的函数
// kh, kn为预设的值, 是为了控制最后颜色
float dU = kh * kn * (payload.texture->getColor(u + 1.0 / w, v).norm() - huv);
float dV = kh * kn * (payload.texture->getColor(u, v + 1.0 / h).norm() - huv);
Eigen::Vector3f ln(-dU, -dV, 1);
point = point + kn * normal * huv;
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.

Eigen::Vector3f light_direction = (light.position - point);
Eigen::Vector3f viewer_direction = (eye_pos - point);

Eigen::Vector3f intensity = light.intensity / light_direction.squaredNorm();

light_direction = light_direction.normalized();
viewer_direction = viewer_direction.normalized();

Eigen::Vector3f ambient = ka.cwiseProduct(amb_light_intensity);
Eigen::Vector3f diffuse = std::max(0.0f, normal.dot(light_direction)) * kd.cwiseProduct(intensity);
Eigen::Vector3f h = (light_direction + viewer_direction).normalized();
Eigen::Vector3f specular = std::pow(std::max(0.0f, normal.dot(h)), p) * ks.cwiseProduct(intensity);
result_color += ambient + diffuse + specular;
}

return result_color * 255.f;
}

./Rasterizer bump_1.png bump 1

./Rasterizer bump_2.png bump 2

## getColorBilinear

Eigen::Vector3f bilinear_texture_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f return_color = {0, 0, 0};
{
// TODO: Get the texture value at the texture coordinates of the current fragment
}
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 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.

Eigen::Vector3f light_direction = (light.position - point);
Eigen::Vector3f viewer_direction = (eye_pos - point);

Eigen::Vector3f intensity = light.intensity / light_direction.squaredNorm();

light_direction = light_direction.normalized();
viewer_direction = viewer_direction.normalized();

Eigen::Vector3f ambient = ka.cwiseProduct(amb_light_intensity);
Eigen::Vector3f diffuse = std::max(0.0f, normal.dot(light_direction)) * kd.cwiseProduct(intensity);
Eigen::Vector3f h = (light_direction + viewer_direction).normalized();
Eigen::Vector3f specular = std::pow(std::max(0.0f, normal.dot(h)), p) * ks.cwiseProduct(intensity);
result_color += ambient + diffuse + specular;
}

return result_color * 255.f;
}

Eigen::Vector3f getColorBilinear(float u, float v)
{
float u_img = u * width;
float v_img = (1 - v) * height;
int u_img_min = (int) u_img;
int u_img_max = u_img_min + 1;
int v_img_min = (int) v_img;
int v_img_max = v_img_min + 1;
float s = u_img - u_img_min;
float t = v_img - v_img_min;

auto c00 = img2Color(v_img_min, u_img_min);
auto c10 = img2Color(v_img_min, u_img_max);
auto c01 = img2Color(v_img_max, u_img_min);
auto c11 = img2Color(v_img_max, u_img_max);

auto c0 = lerp(s, c00, c10);
auto c1 = lerp(s, c01, c11);
auto color = lerp(t, c0, c1);

return color;
}

Eigen::Vector3f lerp(float s, Eigen::Vector3f a, Eigen::Vector3f b)
{
return a + s * (b - a);
}

./Rasterizer bump_1.png bump 1

./Rasterizer bump_2.png bump 2