zoukankan      html  css  js  c++  java
  • GAMES101 作业2

    请用来检验答案是否正确

    思路

    1. 判断点是否在三角形内

      若P点在ABC构成的三角形内,ABC中的任意一点与P点都在另外两点构成的线段的同一侧。假设AB为边,判断C、P点是否在同一侧,可通过AB与AP的叉积、AB与AC的叉积(叉积计算出垂直于这两个向量的向量),判断结果是否同方向来判断是否在同一侧(可以通过点积结果是否大于0)。

    2. 计算Bounds

      遍历三角形的三个点,取出最小和最大的x/y值,就是边界了。同时根据games101课上所说,将x,y分成一个个单位为1的格子,因此边界需要分别上下取整。

    3. 光栅化

      遍历格子中心点,根据案例给出的方法计算出深度值,和深度缓存比较,更小的值就更新深度缓存,设置颜色缓存。如果是开启SSAA,就遍历中心点时候,不直接用小格子的中心点,而是将单位格子再拆分成四个格子,分别计算四个小格子是否三角形内。最后取四个小格子的最小深度值来做深度测试。 这里需要注意的是,采样颜色时针对不在三角形内的小格子的部分,要使用帧缓存中的值来参与计算,否则会出现黑边的问题

    发现开启ssaa后性能好低,后面有空看看这块有没有什么优化方法

    Code

    计算点是否在三角形内:

    // 判断c、p点是否在ab边的同一侧
    static bool sameSide(Vector3f p, Vector3f a, Vector3f b, Vector3f c)
    {
        Vector3f ab = b - a;
        Vector3f ac = c - a;
        Vector3f ap = p - a;
        return (ab.cross(ac)).dot(ab.cross(ap)) >= 0;
    }
    
    static bool insideTriangle(float x, float y, const Vector3f* _v)
    {   
        // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
        Vector3f pos = {x, y, 1};
    
        return sameSide(pos, _v[0], _v[1], _v[2]) &&
               sameSide(pos, _v[2], _v[0], _v[1]) &&
               sameSide(pos, _v[1], _v[2], _v[0]);
    }
    

    光栅化三角形:

    // 获取三个里最小值
    static int GetMin(float a, float b, float c){
        return floor(std::min(a, std::min(b,c)));
    }
    // 获取三个里最大值
    static int GetMax(float a, float b, float c){
        return ceil(std::max(a, std::max(b,c)));
    }
    
    // Screen space rasterization
    void rst::rasterizer::rasterize_triangle(const Triangle& t) {
        auto v = t.toVector4();
        // TODO : Find out the bounding box of current triangle.
        int minx = GetMin(v[0][0], v[1][0], v[2][0]);
        int maxx = GetMax(v[0][0], v[1][0], v[2][0]);
        int miny = GetMin(v[0][1], v[1][1], v[2][1]);
        int maxy = GetMax(v[0][1], v[1][1], v[2][1]);
        
        // 是否开启反走样开关
        bool super_sampling = true;
    
        // iterate through the pixel and find if the current pixel is inside the triangle
        for (int x = minx; x <= maxx; x++)
        {
            for (int y = miny; y <= maxy; y++)
            {
                // 开启反走样计算
                if(super_sampling){
                    int count = 0;
                    float depth = std::numeric_limits<float>::infinity();
                    Vector2f midCube[4]{
                        {0.25, 0.25},
                        {0.25, 0.75},
                        {0.75, 0.25},
                        {0.75, 0.75}
                    };
                    for (int i = 0; i < 4; i++)
                    {
                        float posx = x + midCube[i][0];
                        float posy = y + midCube[i][1];
                        // insideTriangle 这里参数需要改为float或double,避免被强转int
                        if(insideTriangle(posx, posy, t.v)){
                            float alpha;
                            float beta;
                            float gamma;
                            auto zValue = computeBarycentric2D(posx, posy, t.v);
                            std::tie(alpha, beta, gamma) = zValue;
                            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;
                            depth = std::min(depth, z_interpolated);
                            count++;
                        }
                    }
                    if (count>0) {
                        int index = get_index(x,y);
                        if(depth < depth_buf[index]){
                            Vector3f point = {x, y , depth};
                            // 避免黑线问题
                            Vector3f color = t.getColor() * count / 4.0 + (4 - count) * frame_buf[index] / 4.0;
                            depth_buf[index] = depth;
                            set_pixel(point, color);
                        }
                    }
                }
                else 
                {
                    float posx = x + 0.5;
                    float posy = y + 0.5;
                    // If so, use the following code to get the interpolated z value.
                    if(insideTriangle(posx, posy, t.v)){
                        float alpha;
                        float beta;
                        float gamma;
                        auto zValue = computeBarycentric2D(posx, posy, t.v);
                        std::tie(alpha, beta, gamma) = zValue;
                        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;
                        // TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
    
                        int index = get_index(x,y);
                        if(z_interpolated < depth_buf[index]){
                            Vector3f point = {x, y , z_interpolated};
                            Vector3f color = t.getColor();
                            depth_buf[index] = z_interpolated;
                            set_pixel(point, color);
                        }
                    }
                }
                
            }
        }
    }
    

    未开启ssaa:
    未开启ssaa
    开启ssaa:
    开启ssaa

  • 相关阅读:
    驱动编程杂谈
    mysql数据库之视图
    mysql编程
    添加内核编译选项
    内核编译遇到的一些问题
    jffs2和yaffs2文件系统
    宿主机挂载和使用嵌入式文件系统
    只读文件系统
    Makefile的简单编写
    UITableview delegate dataSource调用探究
  • 原文地址:https://www.cnblogs.com/ruoh3kou/p/15522498.html
Copyright © 2011-2022 走看看