首页 > 其他分享 >games101_Homework3

games101_Homework3

时间:2024-03-02 23:55:43浏览次数:14  
标签:Eigen color auto Vector3f light Homework3 games101 payload

摘要:在Raster部分实现数值插值,然后实现四种不同的像素着色器

作业描述:

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

在rasterize_triangle函数中重复上次的包围盒进行点采样,在深度测试通过之后分别对法向量、颜色、纹理颜色、视图空间坐标做插值,然后通过shader计算出像素颜色后设定其值。

//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos)     //t为经mvp变换后的顶点坐标,view_pos为mv变换后顶点在视图空间中的位置
{
    // TODO: From your Homework3, get the triangle rasterization code.  
    auto v = t.toVector4();    // t.to is array<Vector4f, 3>,为三角形三个顶点坐标的齐次坐标表达

    // Find out the bounding box of current triangle.
    float min_x, max_x, min_y, max_y;
    min_x = std::min(v[0].x(), std::min(v[1].x(), v[2].x()));
    max_x = std::max(v[0].x(), std::max(v[1].x(), v[2].x()));
    min_y = std::min(v[0].y(), std::min(v[1].y(), v[2].y()));
    max_y = std::max(v[0].y(), std::max(v[1].y(), v[2].y()));

    // iterate through the pixel and find if the current pixel is inside the triangle
    for(int x = min_x; x < max_x; ++x){
        for(int y = min_y; y < max_y; ++y){
            if(insideTriangle((float)x + 0.5, (float)y + 0.5, t.v)){
                // If so, use the following code to get the interpolated z value.
                // 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 
                auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);                 //计算(x,y)点的重心坐标
                float Z = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());    //Z是当前像素的视图空间深度(插值),v[i].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;    //zp是nf之间的深度

                if(zp < depth_buf[get_index(x, y)]){
                    // set the z_buffer
                    depth_buf[get_index(x, y)] = zp;

                    // 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);
                    // 调用准备好的interpolate()函数获取这些属性的插值
                    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);                       //法向量
                    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);                //着色点在mv变换后可视空间的真实坐标
                    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);    //调用我们设置的fragment_shader进行点的像素的着色

                    set_pixel(Vector2i(x, y), pixel_color);     //调用写好的set_pixel函数写入framebuffer
                }
            }
        }
    }
}

注:本次作业的insideTriangle依然需要修改传入接口为 static bool insideTriangle(float x, float y, const Vector4f* _v)

作业2:修改函数 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.
        
        // L = (Ka * Ia) + (Kd * I/r^2 * max(0, n·l)) + (Ks * (I / r^2) * max(0, n · h)^p)
        // 光照方向
        Eigen::Vector3f light_direc = (light.position - point).normalized();
        // 视线方向
        Eigen::Vector3f eye_direc = (eye_pos - point).normalized();
        // 半程向量
        Eigen::Vector3f half_vector = (light_direc + eye_direc).normalized();
        // 距离的平方
        float R2 = (light.position - point).squaredNorm();

        // 环境光
        auto ambient = ka.cwiseProduct(amb_light_intensity);
        // 漫反射
        auto diffuse = kd.cwiseProduct(light.intensity / R2) * std::max(0.0f, normal.dot(light_direc)) ;
        // 高光
        auto specular = ks.cwiseProduct(light.intensity / R2) * std::pow(std::max(0.0f, normal.dot(half_vector)), p);

        result_color += (ambient + diffuse + specular);
    }

    return result_color * 255.f;
}

作业3:修改函数 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[0], payload.tex_coords[1]);
    }
    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.
        
        // L = (Ka * Ia) + (Kd * I/r^2 * max(0, n·l)) + (Ks * (I / r^2) * max(0, n · h)^p)
        // 光照方向
        Eigen::Vector3f light_direc = (light.position - point).normalized();
        // 视线方向
        Eigen::Vector3f eye_direc = (eye_pos - point).normalized();
        // 半程向量
        Eigen::Vector3f half_vector = (light_direc + eye_direc).normalized();
        // 距离的平方
        float R2 = (light.position - point).squaredNorm();

        // 环境光
        auto ambient = ka.cwiseProduct(amb_light_intensity);
        // 漫反射
        auto diffuse = kd.cwiseProduct(light.intensity / R2) * std::max(0.0f, normal.dot(light_direc)) ;
        // 高光
        auto specular = ks.cwiseProduct(light.intensity / R2) * std::pow(std::max(0.0f, normal.dot(half_vector)), p);

        result_color += (ambient + diffuse + specular);
    }

    return result_color * 255.f;
}

作业4:修改函数 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)
    
    auto n = normal;
    auto x = n.x();
    auto y = n.y();
    auto 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);
    auto u = payload.tex_coords.x();        //在切线空间中的x坐标
    auto v = payload.tex_coords.y();        //在切线空间中的y坐标

    Matrix3f TBN;
    TBN << t.x(), t.y(), t.z(),
           b.x(), b.y(), b.z(),
           n.x(), n.y(), n.z();
    // 纹理实际宽度
    auto w = payload.texture->width;
    // 纹理实际高度
    auto h = payload.texture->height;
    // U、V方向的切线(导数)
    auto dU = kh * kn * (payload.texture->getColor(u + 1.0f / w, v).norm() - payload.texture->getColor(u,v).norm());
    auto dV = kh * kn * (payload.texture->getColor(u, v + 1.0f / h).norm() - payload.texture->getColor(u,v).norm());
    // 当前点的法向量
    Vector3f ln(-dU, -dV, 1);

    //使用tbn矩阵将法线变换到世界空间中
    normal = (TBN * ln).normalized();   //

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

    return result_color * 255.f;
}

作业5:修改函数 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)

    auto n = normal;
    auto x = n.x();
    auto y = n.y();
    auto 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);
    auto u = payload.tex_coords.x();        //在切线空间中的x坐标
    auto v = payload.tex_coords.y();        //在切线空间中的y坐标
    Matrix3f TBN;
    TBN << t.x(), t.y(), t.z(),
           b.x(), b.y(), b.z(),
           n.x(), n.y(), n.z();
    auto w = payload.texture->width;
    auto h = payload.texture->height;
    auto dU = kh * kn * (payload.texture->getColor(u + 1.0f / w, v).norm() - payload.texture->getColor(u,v).norm());
    auto dV = kh * kn * (payload.texture->getColor(u, v + 1.0f / 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.
        
        // L = (Ka * Ia) + (Kd * I/r^2 * max(0, n·l)) + (Ks * (I / r^2) * max(0, n · h)^p)
        // 光照方向
        Eigen::Vector3f light_direc = (light.position - point).normalized();
        // 视线方向
        Eigen::Vector3f eye_direc = (eye_pos - point).normalized();
        // 半程向量
        Eigen::Vector3f half_vector = (light_direc + eye_direc).normalized();
        // 距离的平方
        float R2 = (light.position - point).squaredNorm();

        // 环境光
        auto ambient = ka.cwiseProduct(amb_light_intensity);
        // 漫反射
        auto diffuse = kd.cwiseProduct(light.intensity / R2) * std::max(0.0f, normal.dot(light_direc)) ;
        // 高光
        auto specular = ks.cwiseProduct(light.intensity / R2) * std::pow(std::max(0.0f, normal.dot(half_vector)), p);

        result_color += (ambient + diffuse + specular);
    }

    return result_color * 255.f;
}

标签:Eigen,color,auto,Vector3f,light,Homework3,games101,payload
From: https://www.cnblogs.com/wosun/p/18049469

相关文章

  • games101_Homework4
    摘要:实现四个点的贝塞尔曲线作业描述:•bezier:该函数实现绘制Bézier曲线的功能。它使用一个控制点序列和一个OpenCV::Mat对象作为输入,没有返回值。它会使t在0到1的范围内进行迭代,并在每次迭代中使t增加一个微小值。对于每个需要计算的t,将调用另一个函数recursive......
  • GAMES101 Rasterization 光栅化
    向量点乘的作用计算两个方法方向夹角计算两个方向是否接近关于两个方向的计算向量叉乘\[\vec{a}\times\vec{b}=\begin{pmatrix}y_az_b-y_bz_a\\z_ax_b-x_az_b\\x_ay_b-y_ax_b\end{pmatrix}\]\[\veca\times\vecb=A^*b=\begin{pmatrix}0&-z_a&y_a\\z_a&0&-x_a\\-y_a&x......
  • games101_Homework1
    作业描述:本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵。给定三维下三个点v0(2.0,0.0,−2.0),v1(0.0,2.0,−2.0),v2(−2.0,0.0,−2.0),你需要将这三个点的坐标变换为屏幕坐标,并在屏幕上绘制出对应的线框三角形(在代码框架中,我们已经提供了draw_triangl......
  • games101_Homework0
    作业描述:给定一个点P=(2,1),将该点绕原点先逆时针旋转45◦,再平移(1,2),计算出变换后点的坐标(要求用齐次坐标进行计算)。作业解答:#include<cmath>#include<eigen3/Eigen/Core>#include<eigen3/Eigen/Dense>#include<iostream>intmain(){//definepoin......
  • games101-2 透视深度插值矫正与抗锯齿分析
    透视深度插值矫正与抗锯齿分析深度插值的差错原因透视深度插值公式推导games101中的错误msaa与ssaa简要定义games101中ssaa的实现games101中msaa的实现深度插值的差错原因当投影的图形与投影的平面不平行时,这时进行透视投影,从上图中可以看出,投影平面上的线段时均匀......
  • games101一些问题及思考
    games101一些问题及思考1.透视投影为什么z值变大从透视投影矩阵可以看出z会变大,但从直观上怎么想呢。想象一段向无穷远处延伸的铁轨,假设有100m,但照片中前一半明显不足50m,后一段明显多于50m,可以体会到近平面和远平面之间的点都会向远平面压缩,使得出现近大远小的情况。2.各个......
  • [GAMES101] 我的结课打卡
    ......
  • games101-homework-notes
    Games101作业笔记Created:2023-06-19T12:00+08:00Published:2023-08-17T16:23+08:00Categories:ComputerGraphics目录pa0hw1ProjectionMatrixTriangleRasterizerprocesshw2insidetrianglerasterize_trianglemyhw2bugs使用\(y+0.5\)setindex导致三角形分裂屏幕两......
  • games101-lecture-notes
    Games101课程笔记Created:2023-06-07T20:54+08:00Published:2023-08-16T21:05+08:00Categories:ComputerGraphics目录Lecture01:OverviewofComputerGraphicsmotivation:学了有什么用?课程内容课程资源Lecture02:ReviewofLinearAlgebra点乘叉乘叉乘的作用Lecture03......
  • GAMES101笔记(04)
    本篇对应的是第七课上节课讲完了光栅化的内容,这节课讲的有深度测试,光照和着色深度测试我在学校看shader入门精要的时候有些印象,但也仅此而已了,我觉得还是要先补一下图形学的知识再去啃入门精要会好一些 深度缓存在计算机成像时,对于一个我们要输出的画面,如何确保画面上的东......