GAMES101-现代计算机图形学学习笔记(4)作业3

前言

上篇作业2

本篇将更新作业3相关内容

作业3相关链接

games的作业3链接

我的源码

作业3简述

  • 插值计算
  • 各种shader实现

作业3相关知识笔记

  • Barycentric Coordinates
  • Blinn -Phong(Lambertian(Diffuse) Shading、Specular Shading、Ambient Shading)
  • Flat shading、Gouraud shading、Phong shading
  • Texture Magnification(Nearest、Bilinear、Bicubic)
  • MipMap(Range Query、Trilinear interpolation)
  • Anisotropic Filtering 、EWA filtering
  • Environment Map(Spherical Environment Map)、Cube Map 、Bump/normal map 、 Displacement mapping

作业3思路

注意:后面有代码展示,一定要自己先做一遍再看,而且我的设计不一定正确规范高效。

  • 根据作业2补充上透视矩阵,这里就不再赘述了

  • 实现rasterize_triangle()插值

    void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array& view_pos) 
    {
        // TODO: From your HW2, get the triangle rasterization code.
        auto v = t.toVector4();
        int x_max,x_min,y_max,y_min,index;
        x_min=floor(MIN(v[0].x(),MIN(v[1].x(),v[2].x())));
        x_max=ceil(MAX(v[0].x(),MAX(v[1].x(),v[2].x())));
        y_min=floor(MIN(v[0].y(),MIN(v[1].y(),v[2].y())));
        y_max=ceil(MAX(v[0].y(),MAX(v[1].y(),v[2].y())));
        // TODO : Find out the bounding box of current triangle.
        // iterate through the pixel and find if the current pixel is inside the triangle
        for(int x=x_min;x<=x_max;x++){
            for(int y=y_min;y<=y_max;y++){
                    if(insideTriangle(x+0.5f,y+0.5f,t.v)){                   
                        auto[alpha, beta, gamma] = computeBarycentric2D(x+0.5f, y+0.5f, t.v);                  
                        // 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 : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
                        index=get_index(x,y);
                        if(zp

    运行效果:
    GAMES101-现代计算机图形学学习笔记(4)作业3_第1张图片

  • 补充 phong_fragment_shader()

    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 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 v = (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. Then, accumulate that result on the *result_color* object.
            Eigen::Vector3f l = (light.position - point).normalized();
            Eigen::Vector3f h = (v + l).normalized();
            auto r2 = (light.position - point).squaredNorm();
    
            auto ambient = ka.cwiseProduct(amb_light_intensity);
    
            auto diffuse = kd.cwiseProduct(light.intensity/r2 * MAX(0.0f,normal.dot(l)));
    
            auto specular = ks.cwiseProduct(light.intensity/r2 * std::pow(MAX(0.0f,normal.dot(h)),p));
    
            result_color += ambient + diffuse + specular;
        }
    
        return result_color * 255.f;
    }
    

    运行效果:
    GAMES101-现代计算机图形学学习笔记(4)作业3_第2张图片

  • 补充texture_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());
            //return_color = payload.texture -> getColorBilinear(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 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 v = (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. Then, accumulate that result on the *result_color* object.
            Eigen::Vector3f l = (light.position - point).normalized();
            Eigen::Vector3f h = (v + l).normalized();
            auto r2 = (light.position - point).squaredNorm();
    
            auto ambient = ka.cwiseProduct(amb_light_intensity);
    
            auto diffuse = kd.cwiseProduct(light.intensity/r2 * MAX(0.0f,normal.dot(l)));
    
            auto specular = ks.cwiseProduct(light.intensity/r2 * std::pow(MAX(0.0f,normal.dot(h)),p));
    
            result_color += ambient + diffuse + specular;
        }
    
        return result_color * 255.f;
    }
    

    运行效果:
    GAMES101-现代计算机图形学学习笔记(4)作业3_第3张图片

  • 补充bump_fragment_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 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)
        Eigen::Vector3f n = normal;
        float x = n.x();
        float y = n.y();
        float z = n.z(); 
        //Vector t = (x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z))
        Eigen::Vector3f 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
        Eigen::Vector3f b = n.cross(t);
        t.normalize();
        b.normalize();
        //Matrix TBN = [t b n]
        Eigen::Matrix3f TBN = Eigen::Matrix3f::Identity();
        TBN << t.x(),b.x(),n.x(),\
               t.y(),b.y(),n.y(),\
               t.z(),b.z(),n.z();
    
        //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)
        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.0f/w,v).norm() - payload.texture -> getColor (u,v).norm());
        float dV = kh * kn * (payload.texture -> getColor(u,v+1.0f/h).norm() - payload.texture -> getColor(u,v).norm());
        Eigen::Vector3f ln = Eigen::Vector3f(-dU,-dV,1).normalized();
        
        //Normal n = normalize(TBN * ln)
        normal = (TBN * ln).normalized();
    
        Eigen::Vector3f result_color = {0, 0, 0};
        result_color = normal;
    
        return result_color * 255.f;
    }
    

    运行效果:
    GAMES101-现代计算机图形学学习笔记(4)作业3_第4张图片

  • 补充displacement_fragment_shader()

    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 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)
        Eigen::Vector3f n = normal;
        float x = n.x();
        float y = n.y();
        float z = n.z(); 
        // Vector t = (x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z))
        Eigen::Vector3f 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
        Eigen::Vector3f b = n.cross(t);
        t.normalize();
        b.normalize();
        // Matrix TBN = [t b n]
        Eigen::Matrix3f TBN = Eigen::Matrix3f::Identity();
        TBN << t.x(),b.x(),n.x(),\
               t.y(),b.y(),n.y(),\
               t.z(),b.z(),n.z();
        // 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)
        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.0f/w,v).norm() - payload.texture -> getColor (u,v).norm());
        float dV = kh * kn * (payload.texture -> getColor(u,v+1.0f/h).norm() - payload.texture -> getColor(u,v).norm());
        Eigen::Vector3f ln = Eigen::Vector3f(-dU,-dV,1).normalized();
        // Position p = p + kn * n * h(u,v)
        point += kn * n * (payload.texture -> getColor (u,v).norm());
        // Normal n = normalize(TBN * ln)
        normal = (TBN * ln).normalized();
    
    
        Eigen::Vector3f result_color = {0, 0, 0};
    
        Eigen::Vector3f view = (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. Then, accumulate that result on the *result_color* object.
            Eigen::Vector3f l = (light.position - point).normalized();
            Eigen::Vector3f h = (view + l).normalized();
            auto r2 = (light.position - point).squaredNorm();
    
            auto ambient = ka.cwiseProduct(amb_light_intensity);
    
            auto diffuse = kd.cwiseProduct(light.intensity/r2 * MAX(0.0f,normal.dot(l)));
    
            auto specular = ks.cwiseProduct(light.intensity/r2 * std::pow(MAX(0.0f,normal.dot(h)),p));
    
            result_color += ambient + diffuse + specular;
    
        }
    
        return result_color * 255.f;
    }
    

    运行效果:
    GAMES101-现代计算机图形学学习笔记(4)作业3_第5张图片

  • 提高部分

    1. 换用其他模型,更改main.cpp中obj_path和对应obj文件、texture文件即可

      这里为了方便观察我另外修改了eye_pos,注意不要过近。
      GAMES101-现代计算机图形学学习笔记(4)作业3_第6张图片

    2. 双线性插值

          Eigen::Vector3f getColorBilinear(float u,float v)
          {
              if(u<0)u=0;
              if(u>1)u=1;
              if(v<0)v=0;
              if(v>1)v=1;
      
              auto u_img = u * (width - 1);
              auto v_img = (1 - v) * (height - 1);
      
              /*
              Eigen::Vector2f u00(std::floor(u_img), std::floor(v_img));
              Eigen::Vector2f u10(std::ceil(u_img), std::floor(v_img));
              Eigen::Vector2f u00(std::floor(u_img), std::ceil(v_img));
              Eigen::Vector2f u00(std::ceil(u_img), std::ceil(v_img));
              */
      
              auto color00 = getColor((std::floor(u_img))/width,1-(std::floor(v_img))/height);
              auto color10 = getColor((std::ceil(u_img))/width, 1-(std::floor(v_img))/height);
              auto color01 = getColor((std::floor(u_img))/width,1-(std::ceil(v_img))/height);
              auto color11 = getColor((std::ceil(u_img))/width, 1-(std::ceil(v_img))/height);
              
      
              float s = u_img - std::floor(u_img);
              float t = v_img - std::floor(v_img);
      
              auto color0 = lerp(s,color00,color10);
              auto color1 = lerp(s,color10,color11);
              auto color = lerp(s,color0,color1);
      
              return Eigen::Vector3f(color[0], color[1], color[2]);
          }
      
          Eigen::Vector3f lerp(float coefficient,Eigen::Vector3f color_a,Eigen::Vector3f color_b)
          {
              return (1-coefficient) * color_a + coefficient * color_b;
          }
      

      对比:
      边缘细节显然双插值更好。GAMES101-现代计算机图形学学习笔记(4)作业3_第7张图片

你可能感兴趣的:(GAMES101-现代计算机图形学学习笔记(4)作业3)