Games101 作业3 记录

完成作业

描述

  • 目标
    • 参数差值:正确插值颜色,法向量,纹理坐标,位置,并将他们传递给fragment_shader_payload
    • Blinn-Phong反射模型
    • Texture Mapping
    • Bump Mapping
    • 【提高】尝试其他模型
    • 【提高】实现双线性插值

实现

参数差值

  • 在上次作业的rasterize_triangle函数的基础上对插值部分做补充
if(insideTriangle(row+0.5f,col+0.5f,t.v)) {
    auto [alpha, beta, gamma] = computeBarycentric2D(row, col, 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;
    
    int ind = get_index(row, col);
    if(z_interpolated >= depth_buf[ind]) continue;
                
    depth_buf[ind] = z_interpolated;

    // TODO: Interpolate the attributes:
    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;
    // 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 pixel_color = fragment_shader(payload);

    set_pixel(Eigen::Vector2i(row, col), pixel_color);
}

Blinn-Phong反射模型

  • 通过给定参数计算出高光,环境光和漫反射
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};
    Eigen::Vector3f view_dir = (eye_pos - point).normalized();
    for (auto& light : lights)
    {
        // TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular* components are. 
        Eigen::Vector3f diffuse(0,0,0);
        Eigen::Vector3f specular(0,0,0);
        Eigen::Vector3f ambient(0,0,0);
        float rr = (light.position - point).squaredNorm();
        Eigen::Vector3f light_dir = (light.position - point).normalized();

        for(size_t i = 0; i < 3; i++) {
            float intensity = light.intensity[i] / rr;
            Eigen::Vector3f h = (view_dir + light_dir).normalized();

            diffuse[i] = kd[i] * intensity * std::max(0.0f, normal.dot(light_dir));
            specular[i] = ks[i] * intensity * std::pow(std::max(0.0f, normal.dot(h)), p);
            ambient[i] = amb_light_intensity[i] * ka[i];
        }
        // Then, accumulate that result on the *result_color* object.
        result_color += (diffuse + specular + ambient);
    }

    return result_color * 255.f;
}

纹理映射

  • 在Blinn-Phong反射模型的基础上将漫反射系数k_d更换为对应位置的纹理空间内的颜色值
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.x(), payload.tex_coords.y());
        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 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};
    Eigen::Vector3f view_dir = (eye_pos - point).normalized();
    for (auto& light : lights)
    {
        // TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular* components are. 
        Eigen::Vector3f diffuse(0,0,0);
        Eigen::Vector3f specular(0,0,0);
        Eigen::Vector3f ambient(0,0,0);
        float rr = (light.position - point).squaredNorm();
        Eigen::Vector3f light_dir = (light.position - point).normalized();

        for(size_t i = 0; i < 3; i++) {
            float intensity = light.intensity[i] / rr;
            Eigen::Vector3f h = (view_dir + light_dir).normalized();

            diffuse[i] = kd[i] * intensity * std::max(0.0f, normal.dot(light_dir));
            specular[i] = ks[i] * intensity * std::pow(std::max(0.0f, normal.dot(h)), p);
            ambient[i] = amb_light_intensity[i] * ka[i];
        }
        // Then, accumulate that result on the *result_color* object.
        result_color += (diffuse + specular + ambient);
    }

    return result_color * 255.f;
}

凹凸映射

  • 完成bump_fragment_shaderdisplacement_fragment_shader函数
  • 按照注释来就行
Dumping
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)

    float x = normal.x(), y = normal.y(), 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;

    int w = payload.texture->width, h = payload.texture->height;
    float u = payload.tex_coords.x(), v = payload.tex_coords.y();
    payload.texture->getColor(u,v);

    auto huv = payload.texture->getColor(u,v).norm();
    
    float dU = kh * kn * (payload.texture->getColor(u+1.0f/w,v).norm()-huv);
    float dV = kh * kn * (payload.texture->getColor(u,v+1.0f/h).norm()-huv);

    Eigen::Vector3f ln(-dU,-dV,1);
    Eigen::Vector3f n = (TBN * ln).normalized();

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

    return result_color * 255.f;
}
Displacement
  • 结合Blinn-Phong和Bump 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)

    float x = normal.x(), y = normal.y(), 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;

    int w = payload.texture->width, h = payload.texture->height;
    float u = payload.tex_coords.x(), v = payload.tex_coords.y();
    payload.texture->getColor(u,v);

    auto huv = payload.texture->getColor(u,v).norm();
    
    float dU = kh * kn * (payload.texture->getColor(u+1.0f/w,v).norm()-huv);
    float dV = kh * kn * (payload.texture->getColor(u,v+1.0f/h).norm()-huv);

    Eigen::Vector3f ln(-dU,-dV,1);
    point = point + kn * normal * huv;
    Vector3f n = (TBN * ln).normalized();

    Eigen::Vector3f result_color = {0,0,0};
    Eigen::Vector3f view_dir = (eye_pos - point).normalized();
    for (auto& light : lights)
    {
        // TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular* components are. 
        Eigen::Vector3f diffuse(0,0,0);
        Eigen::Vector3f specular(0,0,0);
        Eigen::Vector3f ambient(0,0,0);
        float rr = (light.position - point).squaredNorm();
        Eigen::Vector3f light_dir = (light.position - point).normalized();

        for(size_t i = 0; i < 3; i++) {
            float intensity = light.intensity[i] / rr;
            Eigen::Vector3f h = (view_dir + light_dir).normalized();

            diffuse[i] = kd[i] * intensity * std::max(0.0f, n.dot(light_dir));
            specular[i] = ks[i] * intensity * std::pow(std::max(0.0f, n.dot(h)), p);
            ambient[i] = amb_light_intensity[i] * ka[i];
        }
        // Then, accumulate that result on the *result_color* object.
        result_color += (diffuse + specular + ambient);
    }

    return result_color * 255.f;
}

提高

  • 实验其他模型没有做,可以在参考连接中找其他大佬的答案
  • 双线性插值
    • 分别在x和y两个方向上做线性插值
    • 注意:image_data和uv map上坐标原点的不同,一个是左上角(uv map),一个是左下角(image_data)
// Texture.hpp
Eigen::Vector3f getColorBilinear(float u, float v)
{
    float u_img = u * width;
    float v_img = (1 - v) * height;

    // find center point
    int cx = (u_img - (int)u_img) > 0.5 ? std::ceil(u_img) : std::floor(u_img);
    int cy = (v_img - (int)v_img) > 0.5 ? std::ceil(v_img) : std::floor(v_img);

    // find the color of the center point of the four pixels around the center
    // Note: image_data's origin is lower left corner
    //       texture map's origin is higher left corner
    auto u00 = image_data.at<cv::Vec3b>(cy+0.5, cx-0.5);
    auto u01 = image_data.at<cv::Vec3b>(cy-0.5, cx-0.5);
    auto u10 = image_data.at<cv::Vec3b>(cy+0.5, cx+0.5);
    auto u11 = image_data.at<cv::Vec3b>(cy-0.5, cx+0.5);

    // s, t
    auto s = u_img - (cx-0.5);
    auto t = v_img - (cy-0.5);

    // interpolation
    // Unsatisfactory results
    // auto u0 = u00 + s*(u10-u00);
    // auto u1 = u01 + s*(u11-u01);
    // auto color = u0 + t*(u1-u0);
    // better results
    auto u0 = (1-s)*u00 + s*u10;
    auto u1 = (1-s)*u01 + s*u11;
    auto color = (1-t)*u1 + t*u0;

    return Eigen::Vector3f(color[0], color[1], color[2]);
}

参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值