Games101-作业3

修改函数 rasterize_triangle(const Triangle& t) in rasterizer.cpp: 在此处实现与作业 2 类似的插值算法,实现法向量、颜色、纹理颜色的插值。

//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos) 
{

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

    //创建三角形的包围盒
    float min_x = min(v[0].x(), min(v[1].x(), v[2].x()));
    float max_x = max(v[0].x(), max(v[1].x(), v[2].x()));
    float min_y = min(v[0].y(), min(v[1].y(), v[2].y()));
    float max_y = max(v[0].y(), max(v[1].y(), v[2].y()));


    //遍历包围盒中的所有像素
    for (int x = min_x; x <= max_x; x++) {
        for (int y = min_y; y <= max_y; y++) {
            //如果当前的像素在三角形内(+0.5是为了用像素中心做判断)
            if (insideTriangle(/*(float)*/x + 0.5, /*(float)*/y + 0.5, t.v)) {
                //用作业封装好的插值函数
                auto [alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);    

                //透视矫正(因为投影时会变)
                 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; //矫正

                 if (zp < depth_buf[get_index(x, y)]) {
                     //如果当前这个点中比深度缓存中的点近
                     //颜色插值,t.color[]代表每个点的颜色
                     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).normalized();
                     //纹理坐标
                     auto interpolated_texcoords = interpolate(alpha, beta, gamma, t.tex_coords[0], t.tex_coords[1], t.tex_coords[2], 1);
                     //view_pos[]是三角形顶点在view space中的坐标,插值是为了还原在camera space中的坐标,因为那才是真正要计算颜色的点
                     auto interpolated_shadingcoords = interpolate(alpha, beta, gamma, view_pos[0], view_pos[1], view_pos[2], 1);

                     //把得到的各种插值结果写成fragment_shader_payload类型的结构体
                     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);
                     //更新深度缓存和颜色
                     depth_buf[get_index(x, y)] = zp;
                     set_pixel(Vector2i(x, y), pixel_color);

                 }
            }
        }
    }
}

修改函数 get_projection_matrix() in main.cpp: 将你自己在之前的实验中实现的投影矩阵填到此处,此时可以观察法向量实现结果。

投影矩阵 :(OpenCVy轴是反过来的)

  // TODO: Use the same projection matrix from the previous assignments
    Matrix4f projection = Matrix4f::Identity();     //要返回的透视投影矩阵
    Matrix4f M_ortho_scale = Matrix4f::Identity();           //正交矩阵
    Matrix4f M_ortho_trans = Matrix4f::Identity();           //正交矩阵
    Matrix4f ProjectToOrth = Matrix4f::Identity();  //透视投影到正交投影

    //求PToO
    float angle = (eye_fov / 2) * MY_PI / 180.0f;   //一半的eyeFov
    float n = -zNear;
    float f = -zFar;      

    float t =n * tan(angle);
    float b = -1.0 * t;
    float r = aspect_ratio * t;
    float l = -1.0 * r;

    ProjectToOrth <<
        zNear, 0, 0, 0,
        0, zNear, 0, 0,
        0, 0, zNear + zFar, -(zNear * zFar),
        0, 0, 1, 0;
    M_ortho_scale << 2 / (r - l), 0, 0, 0,
        0, 2 / (t - b), 0, 0,
        0, 0, 2 / (zNear - zFar), 0,
        0, 0, 0, 1;
    M_ortho_trans << 1, 0, 0, -(r + l) / 2,
        0, 1, 0, -(t + b) / 2,
        0, 0, 1, -(zNear + zFar) / 2,
        0, 0, 0, 1;
   
    projection = M_ortho_scale * M_ortho_trans * ProjectToOrth*projection;
    return projection;

如何选择用法向量呢——片元着色器渲染的方式,由main()的传入参数决定,也就是(int argc, const char** argv)。

argc 是 argument count的缩写,表示传入main函数的参数个数。

argv 是 argument vector的缩写,表示传入main函数的参数序列或指针,并且第一个参数argv[0]一定是程序的名称,并且包含了程序所在的完整路径。

在这里可以修改,还可以写成texture等

 记得修改主函数中的路径

 

 修改函数 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.

        Eigen::Vector3f light_dir = (light.position - point).normalized();
        Eigen::Vector3f view_dir = (eye_pos - point).normalized();
        Eigen::Vector3f half_vector = (light_dir + view_dir).normalized();

        // 距离衰减
        float r2 = (light.position - point).dot(light.position - point);

        //环境光
        //cwiseProduct():矩阵点对点相乘
        Eigen::Vector3f La = ka.cwiseProduct(amb_light_intensity);

        //漫反射
        Eigen::Vector3f Ld = kd.cwiseProduct(light.intensity / r2);
        Ld *= std::max(0.0f, normal.normalized().dot(light_dir));

        //高光
        Eigen::Vector3f Ls = ks.cwiseProduct(light.intensity / r2);
        Ls *= std::pow(std::max(0.0f, normal.normalized().dot(half_vector)), p);

        result_color += (La + Ld + Ls);
    }

    return result_color * 255.f;
}

把刚刚调试界面的参数改成“phong

要注意的是所有向量都要归一化

 修改函数 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.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};

    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.
        Vector3f light_dir = (light.position - point).normalized();
        Vector3f view_dir = (eye_pos - point).normalized();
        Vector3f half_vector = (light_dir + view_dir).normalized(); //半程向量

        float r2 = (light.position - point).dot(light.position - point);

        //环境光
        Vector3f La = ka.cwiseProduct(amb_light_intensity);

        //漫反射
        Vector3f Ld = kd.cwiseProduct(light.intensity / r2);
        Ld *= max(0.0f, light_dir.dot(normal.normalized()));

        //高光
        Vector3f Ls = ks.cwiseProduct(light.intensity / r2);
        Ls *= pow(max(0.0f, half_vector.dot(normal.normalized())),p);

        result_color += (La + Ld + Ls);
    }

    return result_color * 255.f;
}

这一步其实就是用纹理颜色替换了Bullin-Phong模型中的Kd

 

 同样的,把参数写成texture

小牛身上的纹理就是从这张图上映射过去的!

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值