任务:

  1. 修改函数rasterize_triangle(const Triangle& t) in rasterizer.cpp: 在此处实现与作业2 类似的插值算法,实现法向量、颜色、纹理颜色的插值。
  2. 修改函数get_projection_matrix() in main.cpp: 将你自己在之前的实验中实现的投影矩阵填到此处,此时你可以运行./Rasterizer output.png normal来观察法向量实现结果。
  3. 修改函数phong_fragment_shader() in main.cpp: 实现Blinn-Phong 模型计算Fragment Color.
  4. 修改函数texture_fragment_shader() in main.cpp: 在实现Blinn-Phong的基础上,将纹理颜色视为公式中的kd,实现Texture Shading FragmentShader.
  5. 修改函数bump_fragment_shader() in main.cpp: 在实现Blinn-Phong 的基础上,仔细阅读该函数中的注释,实现Bump mapping.
  6. 修改函数displacement_fragment_shader() in main.cpp: 在实现Bumpmapping 的基础上,实现displacement mapping.

其中从实现texture_fragment_shader()开始会有opencv报错,和读颜色错误有关,解决方法:添加链接描述
1.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();
    //粗略的碰撞盒生成
    int min_x = floor(std::min(v[0][0], std::min(v[1][0], v[2][0])));
    int min_y = floor(std::min(v[0][1], std::min(v[1][1], v[2][1])));
    int max_x = ceil(std::max(v[0][0], std::max(v[1][0], v[2][0])));
    int max_y = ceil(std::max(v[0][1], std::max(v[1][1], v[2][1])));

    for (int i = min_x; i <= max_x; i++) {
        for (int j = min_y; j <= max_y; j++) {
            if (insideTriangle(i + 0.5, j + 0.5, t.v)) {
                std::tuple<float, float, float> tmpTuple = computeBarycentric2D(float(i + 0.5), float(j + 0.5), t.v);
                float alpha = std::get<0>(tmpTuple);
                float beta = std::get<1>(tmpTuple);
                float gamma = std::get<2>(tmpTuple);
                // Z:当前像素深度 zp:zFar-aNear
                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 (depth_buf[get_index(i, j)] > zp) {
                    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);
                    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;
                    auto pixel_color = fragment_shader(payload);
                    depth_buf[get_index(i, j)] = zp;
                    set_pixel(Vector2i(i, j), pixel_color);
                }
            }
        }
    }

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

 
}

2.get_projection_matrix() in main.cpp:
直接用之前写的有图片显示颠倒的问题,改了一点

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
    // TODO: Use the same projection matrix from the previous assignments
    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
    eye_fov = eye_fov / 180 * M_PI;
    Eigen::Matrix4f M1;
    M1 << zNear, 0, 0, 0,
        0, zNear, 0, 0,
        0, 0, zNear + zFar, -zNear * zFar,
        0, 0, 1, 0;

    float t = -zNear * tan(eye_fov / 2);
    float b = -t;
    float r = t * aspect_ratio;
    float l = -r;
    Eigen::Matrix4f M2;
    M2 << 1, 0, 0, -(r + l) / 2,
        0, 1, 0, -(t + b) / 2,
        0, 0, 1, -(zNear + zFar) / 2,
        0, 0, 0, 1;

    Eigen::Matrix4f M3;
    M3 << 2 / (r - l), 0, 0, 0,
        0, 2 / (t - b), 0, 0,
        0, 0, 2 / (zNear - zFar), 0,
        0, 0, 0, 1;

    projection = M3 * M2 * M1;
    return projection;
}

3.phong_fragment_shader() in main.cpp
冯布灵的三项,加起来算就完事。
需要注意的是kd.cwiseProduct(lightInt / r),老师给的ppt里写的是I/r²,个人李姐是光照强度值直接除r值就是要算的从光源到观测点经过r衰减后的值。

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.
        Vector3f lightPos = light.position;
        Vector3f lightInt = light.intensity;
        
        float r = (lightPos - point).dot(lightPos - point);

        Vector3f n = normal.normalized();    //n向量
        Vector3f l = (lightPos - point).normalized();   //l向量
        Vector3f v = (eye_pos - point).normalized();    //v向量
        Vector3f h = (v + l).normalized();  //h向量

        Vector3f Ld = kd.cwiseProduct(lightInt / r) * __max(0.0f, n.dot(l));
        Vector3f Ls = ks.cwiseProduct(lightInt / r) * pow(__max(0.0f, n.dot(h)), p);

        result_color += (Ld + Ls);
    }
    Vector3f La = ka.cwiseProduct(amb_light_intensity);    // 环境光 直接乘他妈的
    result_color += La;

    return result_color * 255.f;
}

4.texture_fragment_shader() in main.cpp:
和上面基本差不多

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]); //颜色值设置为着色器的材质的uv坐标的颜色
    }
    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 lightPos = light.position;
        Vector3f lightInt = light.intensity;

        float r = (lightPos - point).dot(lightPos - point);

        Vector3f n = normal.normalized();    //n向量
        Vector3f l = (lightPos - point).normalized();   //l向量
        Vector3f v = (eye_pos - point).normalized();    //v向量
        Vector3f h = (v + l).normalized();  //h向量

        Vector3f Ld = kd.cwiseProduct(lightInt / r) * __max(0.0f, n.dot(l));
        Vector3f Ls = ks.cwiseProduct(lightInt / r) * pow(__max(0.0f, n.dot(h)), p);

        result_color += (Ld + Ls);
    }
    Vector3f La = ka.cwiseProduct(amb_light_intensity);    // 环境光 直接乘他妈的
    result_color += La;

    return result_color * 255.f;
}

5.bump_fragment_shader() in main.cpp:

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();
    Vector3f t{ x * y / sqrt(x * x + z * z), sqrt(x * x + z * z),z * y / sqrt(x * x + z * z) };
    Vector3f b = normal.cross(t);
    Matrix3f TBN{
        {t.x(),b.x(),normal.x()},
        {t.y(),b.y(),normal.y()},
        {t.z(),b.z(),normal.z()}
    };
    float u = payload.tex_coords.x();
    float v = payload.tex_coords.y();
    float w = payload.texture->width;
    float h = payload.texture->height;
    float dU = kh * kn * (payload.texture->getColor(u + 1 / w, v).norm() - payload.texture->getColor(u, v).norm());
    float dV = kh * kn * (payload.texture->getColor(u, v + 1 / h).norm() - payload.texture->getColor(u, v).norm());
    Vector3f ln{ -dU,-dV,1 };
    normal = (TBN * ln).normalized();

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

    return result_color * 255.f;
}

6.displacement_fragment_shader() in main.cpp

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();
    Vector3f t{ x * y / sqrt(x * x + z * z), sqrt(x * x + z * z),z * y / sqrt(x * x + z * z) };
    Vector3f b = normal.cross(t);
    Matrix3f TBN{
        {t.x(),b.x(),normal.x()},
        {t.y(),b.y(),normal.y()},
        {t.z(),b.z(),normal.z()}
    };
    float u = payload.tex_coords.x();
    float v = payload.tex_coords.y();
    float w = payload.texture->width;
    float h = payload.texture->height;
    float dU = kh * kn * (payload.texture->getColor(u + 1 / w, v).norm() - payload.texture->getColor(u, v).norm());
    float dV = kh * kn * (payload.texture->getColor(u, v + 1 / 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.
        Vector3f lightPos = light.position;
        Vector3f lightInt = light.intensity;

        float r = (lightPos - point).dot(lightPos - point);

        Vector3f n = normal.normalized();    //n向量
        Vector3f l = (lightPos - point).normalized();   //l向量
        Vector3f v = (eye_pos - point).normalized();    //v向量
        Vector3f h = (v + l).normalized();  //h向量

        Vector3f Ld = kd.cwiseProduct(lightInt / r) * __max(0.0f, n.dot(l));
        Vector3f Ls = ks.cwiseProduct(lightInt / r) * pow(__max(0.0f, n.dot(h)), p);

        result_color += (Ld + Ls);

    }
    Vector3f La = ka.cwiseProduct(amb_light_intensity);    // 环境光 直接乘他妈的
    result_color += La;

    return result_color * 255.f;
}
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐