计算机图形学games101作业3

1,026 阅读4分钟

本次实验中,完成的任务是:

  1. 修改函数 rasterize_triangle(const Triangle& t) in rasterizer.cpp: 在此

    处实现与作业 2 类似的插值算法,实现法向量、颜色、纹理颜色的插值。

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.
    auto v=t.v;
    //求得三角形边界范围
    float minx=std::min(v[0].x(),std::min(v[1].x(),v[2].x()));
    float miny=std::min(v[0].y(),std::min(v[1].y(),v[2].y()));
    float maxx=std::max(v[0].x(),std::max(v[1].x(),v[2].x()));
    float maxy=std::max(v[0].y(),std::max(v[1].y(),v[2].y()));
    minx=std::floor(minx);
    miny=std::floor(miny);
    maxx=std::ceil(maxx);
    maxy=std::ceil(maxy);
    for(int x=minx;x<maxx;x++){
        for(int y=miny;y<maxy;y++){
            if(insideTriangle(float(x)+0.5,float(y)+0.5,t.v)){
                //获取alpha,beta,gamma重心坐标分量
                auto[alpha, beta, gamma] = computeBarycentric2D(float(x)+0.5,float(y)+0.5, 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;
                if(z_interpolated<depth_buf[get_index(x,y)]){
                    depth_buf[get_index(x,y)]=z_interpolated;
                    //对颜色,法向量,纹理坐标,视图空间坐标进行线性插值
                    Eigen::Vector3f interpolated_color= interpolate(alpha,beta,gamma,t.color[0],t.color[1],t.color[2],1.0);
                    Eigen::Vector3f interpolated_normal= interpolate(alpha,beta,gamma,t.normal[0],t.normal[1],t.normal[2],1.0);
                    Eigen::Vector2f interpolated_texcoords= interpolate(alpha,beta,gamma,t.tex_coords[0],t.tex_coords[1],t.tex_coords[2],1.0);
                    Eigen::Vector3f interpolated_shadingcoords= interpolate(alpha,beta,gamma,view_pos[0],view_pos[1],view_pos[2],1.0);
                    fragment_shader_payload payload( interpolated_color, interpolated_normal.normalized(), interpolated_texcoords, texture ? &*texture : nullptr);
                    payload.view_pos = interpolated_shadingcoords;
                    //使用着色器着色
                    Eigen::Vector3f pixel_color = fragment_shader(payload);
                    Eigen::Vector2i point;
                    point<<x,y;
                    set_pixel(point,pixel_color);
                }
            }
        }
    }
}
  1. 修改函数 get_projection_matrix() in main.cpp: 将你自己在之前的实验中 实现的投影矩阵填到此处,此时你可以运行 ./Rasterizer output.png normal 来观察法向量实现结果。
//透视变换矩阵
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();
    float top = -tan(DEG2RAD(eye_fov/2.0f) * abs(zNear));
    float right = top * aspect_ratio;

    projection << zNear/right,0,0,0,
            0,zNear/top,0,0,
            0,0,(zNear+zFar)/(zNear-zFar),(2*zNear*zFar)/(zFar-zNear),
            0,0,1,0;
    return projection;
}
  1. 修改函数 phong_fragment_shader() in main.cpp: 实现 Blinn-Phong 模型计 算 Fragment 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};
    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.
        //分别计算光源与点之间的距离、光的方向、视线方向、半程向量方向
        float r=(light.position-point).norm();
        Vector3f l=(light.position-point).normalized();
        Vector3f v=(eye_pos-point).normalized();
        Vector3f h=(l+v).normalized();
        //计算环境光强度、漫反射光强度、高光强度
        Vector3f la=ka.cwiseProduct(amb_light_intensity);
        Vector3f ld=kd.cwiseProduct(light.intensity/(r*r))*std::max(0.f,normal.dot(l));
        Vector3f ls=ks.cwiseProduct(light.intensity/(r*r))*pow(std::max(0.f,normal.dot(h)),p);
        result_color+=la+ld+ls;
    }
    return result_color * 255.f;
}
  1. 修改函数 texture_fragment_shader() in main.cpp: 在实现 Blinn-Phong 的基础上,将纹理颜色视为公式中的 kd,实现 Texture Shading Fragment Shader.
//根据纹理颜色进行 Blinn-Phong光照模型着色
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);
    //纹理颜色作为kd漫反射中的系数
    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.
        float r=(light.position-point).norm();
        Vector3f l=(light.position-point).normalized();
        Vector3f v=(eye_pos-point).normalized();
        Vector3f h=(l+v).normalized();
        Vector3f la=ka.cwiseProduct(amb_light_intensity);
        Vector3f ld=kd.cwiseProduct(light.intensity/(r*r))*std::max(0.f,normal.dot(l));
        Vector3f ls=ks.cwiseProduct(light.intensity/(r*r))*pow(std::max(0.f,normal.dot(h)),p);
        result_color+=la+ld+ls;
    }

    return result_color * 255.f;
}
  1. 修改函数 bump_fragment_shader() in main.cpp: 在实现 Blinn-Phong 的 基础上,仔细阅读该函数中的注释,实现 Bump mapping.
//凹凸贴图
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)
    //按照以上公式计算法向量等
    Vector3f n=normal;
    float x=n.x(),y=n.y(),z=n.z();
    Vector3f t(x*y/ sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/ sqrt(x*x+z*z));
    Vector3f b=n.cross(t);
    Matrix<float,3,3> TBN;
    TBN << t.x(),b.x(),n.x(),t.y(),b.y(),n.y(),t.z(),b.z(),n.z();
    float u=payload.tex_coords.x(),v=payload.tex_coords.y();
    float width=payload.texture->width;
    float height=payload.texture->height;
    float dU=kh*kn*(payload.texture->getColor(std::min(u+1.f/width,1.f),v).norm() -\
            payload.texture->getColor(u,v).norm()
    );
    float dV=kh*kn*(payload.texture->getColor(u,std::min(v+1.f/height,1.f)).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;
}
  1. 修改函数 displacement_fragment_shader() in main.cpp: 在实现 Bump mapping 的基础上,实现 displacement 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)
    Vector3f n=normal;
    float x=n.x(),y=n.y(),z=n.z();
    Vector3f t(x*y/ sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/ sqrt(x*x+z*z));
    Vector3f b=n.cross(t);
    Matrix<float,3,3> TBN;
    TBN << t.x(),b.x(),n.x(),t.y(),b.y(),n.y(),t.z(),b.z(),n.z();
    float u=payload.tex_coords.x(),v=payload.tex_coords.y();
    float width=payload.texture->width;
    float height=payload.texture->height;
    float dU=kh*kn*(payload.texture->getColor(std::min(u+1.f/width,1.f),v).norm() -\
            payload.texture->getColor(u,v).norm()
    );
    float dV=kh*kn*(payload.texture->getColor(u,std::min(v+1.f/height,1.f)).norm() -\
            payload.texture->getColor(u,v).norm()
    );
    Vector3f ln{-dU,-dV,1};
    //发生实际位移
    point+=kn*n*payload.texture->getColor(payload.tex_coords.x(),payload.tex_coords.y()).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*
        float r=(light.position-point).norm();
        Vector3f l=(light.position-point).normalized();
        Vector3f v=(eye_pos-point).normalized();
        Vector3f h=(l+v).normalized();
        Vector3f la=ka.cwiseProduct(amb_light_intensity);
        Vector3f ld=kd.cwiseProduct(light.intensity/(r*r))*std::max(0.f,normal.dot(l));
        Vector3f ls=ks.cwiseProduct(light.intensity/(r*r))*pow(std::max(0.f,normal.dot(h)),p);
        result_color+=la+ld+ls;
    }

    return result_color * 255.f;
}