GAMES101 PA3

发布于:2022-12-19 ⋅ 阅读:(1028) ⋅ 点赞:(0)

基础部分

MVP

这部分直接照抄 PA1 的答案就行:

Eigen::Matrix4f get_model_matrix(float angle)
{
    Eigen::Matrix4f rotation;
    angle = angle * MY_PI / 180.f;
    rotation <<
        cos(angle), 0, sin(angle), 0,
        0, 1, 0, 0,
        -sin(angle), 0, cos(angle), 0,
        0, 0, 0, 1;

    Eigen::Matrix4f scale;
    float coef = 1.0f; // 缩放因子
    coef = 2.5f;
    //coef = 5.0f;
    //coef = 7.0f;
    //coef = 8.0f;
    scale <<
        coef, 0, 0, 0,
        0, coef, 0, 0,
        0, 0, coef, 0,
        0, 0, 0, 1;

    Eigen::Matrix4f translate;
    translate << 
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1;

    return translate * rotation * scale;
}
Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos)
{
    Eigen::Matrix4f view = Eigen::Matrix4f::Identity();

    Eigen::Matrix4f translate;
    translate <<
        1, 0, 0, -eye_pos[0],
        0, 1, 0, -eye_pos[1],
        0, 0, 1, -eye_pos[2],
        0, 0, 0, 1;

    view = translate * view;

    return view;
}
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    float Y = eye_fov / 180.0f * MY_PI;  // degree2rad
    float Y_over_2 = Y * 0.5f;
    float cot_Y_over_2 = 1.0f / tan(Y_over_2);

    // Another solution
    Eigen::Matrix4f perspective_p;
    perspective_p <<
        -cot_Y_over_2 / aspect_ratio, 0, 0, 0,
        0, -cot_Y_over_2, 0, 0,
        0, 0, (zFar + zNear) / (zNear - zFar), 2.0f * zFar * zNear / (zFar - zNear),
        0, 0, 1, 0;

    return perspective_p * projection;
}

Normal Shader

Eigen::Vector3f normal_fragment_shader(const fragment_shader_payload& payload)
{
    Eigen::Vector3f return_color = (payload.normal.head<3>().normalized() + Eigen::Vector3f(1.0f, 1.0f, 1.0f)) / 2.f;
    Eigen::Vector3f result;
    result << return_color.x() * 255, return_color.y() * 255, return_color.z() * 255;
    return result;
}

在这里插入图片描述

Phong Shader

这部分直接照着 Blinn-Phong Rendering Equation 写就行:

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 = Eigen::Vector3f(0, 0, 0);
    Eigen::Vector3f view_dir = (-point).normalized();

    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_dir = (light.position - point).normalized();
        Eigen::Vector3f half_vector = ((light_dir + view_dir) / 2.0f).normalized();
        float r2 = (light.position - point).squaredNorm();

        auto ambient = ka.cwiseProduct(amb_light_intensity); // 间接光也是光源发出的,所以也要累加
        auto diffuse = kd.cwiseProduct(light.intensity / r2 * MAX(0.0f, normal.dot(light_dir)));
        auto specular = ks.cwiseProduct(light.intensity / r2 * std::pow(MAX(0.0f, normal.dot(half_vector)), p));

        result_color += ambient + diffuse + specular;
    }

    return result_color * 255.f;
}

在这里插入图片描述

Texture Shader

Blinn-Phong Rendering Equation 中的 kd 置换为 texture_color / 255.f 即可:

Eigen::Vector3f texture_fragment_shader(const fragment_shader_payload& payload)
{
    Eigen::Vector3f return_color = Eigen::Vector3f(0, 0, 0);

    if (payload.texture)
    {
        // TODO: Get the texture value at the texture coordinates of the current fragment

        float u = payload.tex_coords.x();
        float v = payload.tex_coords.y();
        return_color = payload.texture->getColor(u, v);
    }
    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 = Eigen::Vector3f(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 = Eigen::Vector3f(0, 0, 0);
    Eigen::Vector3f view_dir = (-point).normalized();
    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_dir = (light.position - point).normalized();
        Eigen::Vector3f halfVector = ((light_dir + view_dir) / 2.0f).normalized();
        float r2 = (light.position - point).squaredNorm();

        auto ambient = ka.cwiseProduct(amb_light_intensity); // 间接光也是光源发出的,所以也要累加
        auto diffuse = kd.cwiseProduct(light.intensity / r2 * MAX(0.0f, normal.dot(light_dir)));
        auto specular = ks.cwiseProduct(light.intensity / r2 * std::pow(MAX(0.0f, normal.dot(halfVector)), p));

        result_color += ambient + diffuse + specular;
    }

    return result_color * 255.f;
}

在这里插入图片描述

Bump Shader

照着推导方程写就行:

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 = Eigen::Vector3f(10, 10, 10);
    Eigen::Vector3f eye_pos = Eigen::Vector3f(0, 0, 10);

    float p = 150;

    Eigen::Vector3f color = payload.color;
    Eigen::Vector3f point = payload.view_pos;
    Eigen::Vector3f normal = payload.normal;

    // 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 kh = 0.2, kn = 0.1;

    float x = normal.x();
    float y = normal.y();
    float z = normal.z();

    Eigen::Vector3f t = Eigen::Vector3f(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;

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

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

    Eigen::Vector3f ln = Eigen::Vector3f(-dU, -dV, 1.f);
    Eigen::Vector3f n = (TBN * ln).normalized();  // Do not modify.

    Eigen::Vector3f result_color = Eigen::Vector3f(0, 0, 0);
    
    result_color = n;

    return result_color * 255.f;
}

在这里插入图片描述

Displacement Shader

Bump Shader 的基础上再接入 Blinn-Phong 的部分:

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 = Eigen::Vector3f(10, 10, 10);
    Eigen::Vector3f eye_pos = Eigen::Vector3f(0, 0, 10);

    float p = 150;

    Eigen::Vector3f color = payload.color;
    Eigen::Vector3f point = payload.view_pos;
    Eigen::Vector3f normal = payload.normal;


    // 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 kh = 0.2, kn = 0.1;

    float x = normal.x();
    float y = normal.y();
    float z = normal.z();

    Eigen::Vector3f t = Eigen::Vector3f(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;

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

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

    point += (kn * normal * payload.texture->getColor(u, v).norm());

    Eigen::Vector3f ln = Eigen::Vector3f(-dU, -dV, 1.f);
    normal = (TBN * ln).normalized();  // Do modify.

    Eigen::Vector3f result_color = Eigen::Vector3f(0, 0, 0);
    Eigen::Vector3f view_dir = (-point).normalized();
    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_dir = (light.position - point).normalized();
        Eigen::Vector3f half_vector = ((light_dir + view_dir) / 2.0f).normalized();
        float r2 = (light.position - point).squaredNorm();

        auto ambient = ka.cwiseProduct(amb_light_intensity); // 间接光也是光源发出的,所以也要累加
        auto diffuse = kd.cwiseProduct(light.intensity / r2 * MAX(0.0f, normal.dot(light_dir)));
        auto specular = ks.cwiseProduct(light.intensity / r2 * std::pow(MAX(0.0f, normal.dot(half_vector)), p));

        result_color += ambient + diffuse + specular;
    }

    return result_color * 255.f;
}

在这里插入图片描述

提高部分

尝试更多模型

寻找中…

双线性纹理插值

取周围四个点的颜色做三次插值就行,我写了两个lambda表达式clamplerp,用作截断和插值:

    Eigen::Vector3f getColorBilinear(float u, float v)
    {
        int u_img = static_cast<int>(u * width);
        int v_img = static_cast<int>((1 - v) * height);

        auto clamp = [](int low, int high, int val) {
            if (val < low)
                return low;
            else if (val > high)
                return high;
            else
                return val;
        };

        int u_min = clamp(0, width - 1,  floor(u_img));
        int u_max = clamp(0, width - 1,  ceil(u_img));
        int v_min = clamp(0, height - 1, floor(v_img));
        int v_max = clamp(0, height - 1, ceil(v_img));

        /*
          ^ U01 U11
          t U00 U10
            s >
        */
        cv::Vec3b U00 = image_data.at<cv::Vec3b>(v_max, u_min);
        cv::Vec3b U10 = image_data.at<cv::Vec3b>(v_max, u_max);
        cv::Vec3b U01 = image_data.at<cv::Vec3b>(v_min, u_min);
        cv::Vec3b U11 = image_data.at<cv::Vec3b>(v_min, u_max);

        auto lerp = [](auto& start, auto& end, float r) {
            return (1.f - r) * start + r * end;
        };

        auto s = (u_img - u_min) / (u_max - u_min);
        auto t = 1.f - (v_img - v_min) / (v_max - v_min);

        auto color_bottom = lerp(U00, U10, s);
        auto color_top    = lerp(U01, U11, s);
        auto color_binlinear = lerp(color_bottom, color_top, t);
        
        return Eigen::Vector3f(color_binlinear[0], color_binlinear[1], color_binlinear[2]);
    }

ps:要做一下采样才可以就看到明显的效果!


网站公告

今日签到

点亮在社区的每一天
去签到