CheapMeow

Forum Replies Created

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • in reply to: 请教老师一个问题,关于重心坐标 #16631 Score: 0
    CheapMeow
    Participant

    用面积计算是合适的

    比如我这里使用面积计算重心坐标,可以得到预期的效果

    
    static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector4f* v){
        Eigen::Vector2f p(x, y);
    
        Eigen::Vector2f tri_node_coords[3];
        for (int i = 0; i < 3; ++i) {
            tri_node_coords[i] = v[i].head<2>();
        }
    
        Eigen::Vector2f edge_1, edge_2;
        float s_sub_tri[3];
        for (int i = 0; i < 3; ++i) {
            edge_1 = tri_node_coords[(i + 1) % 3] - p;
            edge_2 = tri_node_coords[(i + 2) % 3] - p;
            s_sub_tri[i] = edge_1.x() * edge_2.y() - edge_2.x() * edge_1.y();
        }
    
        float s_sum = 0;
        for (int i = 0; i < 3; ++i) {
            s_sum += s_sub_tri[i];
        }
    
        return { s_sub_tri[0] / s_sum, s_sub_tri[1] / s_sum, s_sub_tri[2] / s_sum };
    }
    

    如果担心计算出来的重心坐标为负会不会不正确,那么可以试着在 rasterize_triangle() 光栅化三角形的时候就剔除掉那些重心坐标为负的点

    
    void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos) 
    {
        int x_screen_min = width - 1;
        int x_screen_max = 0;
        int y_screen_min = height - 1;
        int y_screen_max = 0;
    
        for (int i = 0; i < 3; i++) {
            x_screen_min = std::min(x_screen_min, (int)t.v[i][0]);
            y_screen_min = std::min(y_screen_min, (int)t.v[i][1]);
            x_screen_max = std::max(x_screen_max, (int)t.v[i][0]);
            y_screen_max = std::max(y_screen_max, (int)t.v[i][1]);
        }
    
        // temp var
    
        Eigen::Vector3f interpolated_color;
        Eigen::Vector3f interpolated_normal;
        Eigen::Vector2f interpolated_texcoords;
        Eigen::Vector3f interpolated_shadingcoords;
    
        for (int x = x_screen_min; x <= x_screen_max; ++x) {
            for (int y = y_screen_min; y <= y_screen_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);
                    if (alpha < 0.0f || alpha > 1.0f) continue;
                    if (beta < 0.0f || beta > 1.0f) continue;
                    if (gamma < 0.0f || gamma > 1.0f) continue;
    

    可见,在模型的每一个三角面的边上显示出缝隙

    也就是说,重心坐标为负的点也可能位于三角形的边上

    如果去掉了这些点,就相当于在三角形的边上没有颜色,那么渲染出来的就会在模型的每一个三角面的边上显示出缝隙

    所以只要你的 insideTriangle() 写对了,就不需要考虑 computeBarycentric2D() 算出来的重心坐标为负还是为正

    Attachments:
    You must be logged in to view attached files.
    in reply to: 作业3问题 #16630 Score: 0
    CheapMeow
    Participant

    个人理解是,我们已经固定了:

    摄像机的中心:世界坐标原点

    摄像机的前方向 g:-Z 方向

    摄像机的上方向 t:Y 方向

    在计算光线的时候,我们就是默认相机是这样固定的,不然我们在考虑光线的时候,我们还需要把相机的位置和角度纳入计算中,更麻烦了

    所以光线的计算是在观察空间中的,所以 viewspace_pos 是三角形顶点坐标经过 MV 变换之后的观察空间的坐标

    而 shader 中的光源的位置就是写死了观察空间中的位置

    感觉实际中光源的位置也是一个传入的值,或许也是需要经过变换的,但是在这个 shader 里为了简单就写死了

    参考:

    作业3 interpolated_shadingcoords

    in reply to: 作业1代码main.cpp中ind{ {0, 1, 2} }的作用 #16605 Score: 0
    CheapMeow
    Participant

    在 main 函数中,一开始定义了 pos 和 ind,然后 load 之后得到 pos_id 和 ind_id

    之后的循环之中没有更改 pos_id 和 ind_id,那么显然,一开始得到的 pos_id 和 ind_id 就是三角形的 pos 和 ind

    再看具体是怎么用这个 pos_id 和 ind_id 的,他是在光栅化器的 draw 函数中用的,用在 pos_buf 和 ind_buf

    
        auto& buf = pos_buf[pos_buffer.pos_id];
        auto& ind = ind_buf[ind_buffer.ind_id];
    

    然后之后的功能都是根据这个取出来的 buf 和 ind

    那么再看位置缓冲和顶点缓冲的定义:

    
        std::map<int, std::vector<Eigen::Vector3f>> pos_buf;
        std::map<int, std::vector<Eigen::Vector3i>> ind_buf;
    

    map 里面一个 id 对应一个 vector

    对于 pos_buf 是一个 id 对应一个 std::vector<Eigen::Vector3f>,根据常识以及之前 main 函数中的初始化写法可以知道,这里就是给了三个点的坐标的值,坐标用 Eigen::Vector3f 表示

    对于 ind_buf 同理,就是一个 id 对应三个顶点的序号

    这就很容易理解了。对于只有一个三角形的情况,这里取出来的 buf 和 ind 就是第一个三角形三个点的坐标的值,三个顶点的序号

    in reply to: 作业1的问题 #16603 Score: 0
    CheapMeow
    Participant

    这个报错的意思是,不能列表初始化结构体。
    感觉可能是因为你使用的 C++ 版本比较旧?
    我也搜到了一些相关的描述:
    https://www.cppblog.com/jinq0123/archive/2016/12/12/214479.html

    在这里提到了在结构体中初始化错误的理由:
    https://www.geeksforgeeks.org/structures-in-cpp/

    当声明数据类型时,不会为其分配内存。仅在创建变量时分配内存。

    但是在 C++ 中是可以这么写的

    所以综合来看更像是不同 C++ 版本下的差异……?

    • This reply was modified 1 year, 6 months ago by CheapMeow. Reason: Add discription for error
    in reply to: 作业1 绕X轴旋转会数组越界 #16598 Score: 0
    CheapMeow
    Participant

    就像楼上说的,出错在 rasterizer.cpp 的 set_pixel

    如果 x 和 y 同时为 0,ind 此时等于 height * width,但是数组范围为 [0, height * width – 1],因此出现了越界

    解决方法是不允许 x 和 y 同时为 0,也就是把小于号改成小于等于号

    
    void rst::rasterizer::set_pixel(const Eigen::Vector3f& point, const Eigen::Vector3f& color)
    {
        //old index: auto ind = point.y() + point.x() * width;
        if (point.x() <= 0 || point.x() >= width ||
            point.y() <= 0 || point.y() >= height) return;
        // if point.x() == 0 and point.y() == 0
        // then get ind == height * width
        // but size of frame_buf == height * width
        // so available index of frame_buf is [0, height * width - 1]
        // so don't allow point.x() == 0 and point.y() == 0
        auto ind = (height-point.y())*width + point.x();
        frame_buf[ind] = color;
    }
    
Viewing 5 posts - 1 through 5 (of 5 total)