当前位置: 首页 > article >正文

games101-作业

 作业1

games101 作业1及作业2分析及解决 详解透视矩阵 - dyccyber - 博客园

GAMES101——作业1 旋转与投影(含提高:罗德里格斯旋转公式)_games101作业1-CSDN博客

GAMES101——作业1 旋转与投影(含提高:罗德里格斯旋转公式)_games101作业1-CSDN博客

任务

实现

get_model_matrix

绕x,y,z轴的变换矩阵如下,算出两个三角函数值后直接代入即可


 

Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
        Eigen::Matrix4f model = Eigen::Matrix4f::Identity();    //创建一个单位矩阵

        float angle = rotation_angle / 180.0f * MY_PI;     //将角度制的角度转化为弧度制的角度,因为c++默认的三角函数用的是弧度制
        float s = std::sin(angle);
        float c = std::cos(angle);
        model << c, -s, 0, 0, s, c, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0;   //根据旋转矩阵的公式,直接给模型矩阵赋值

        return model;
}

get_projection_matrix

zNear是近平面到摄像机的距离,已知视角,可以根据正切函数求出一半的高度,最后乘2就可以得到近平面的高度,根据宽高比,求出近平面的宽度。再根据推导出的矩阵,代入数据即可求得所需的结果。

/*
float eye_fov; Y view ,观看
float aspect_ratio ;宽高比

*/

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
                                      float zNear, float zFar)
{
    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
 
    Eigen::Matrix4f persp_to_ortho;         //公式中的persp->ortho矩阵
    Eigen::Matrix4f ortho;                  //ortho矩阵
    float height = zNear*std::tan(eye_fov/2) * 2;   //视锥体挤成立方体,立方体的高
    float width = height * aspect_ratio;                                //立方体的宽
 
    persp_to_ortho << zNear, 0, 0, 0,               //根据公式求得persp->ortho矩阵
                      0,zNear,0,0,
                      0,0,zNear + zFar,-zNear*zFar,
                      0,0,1,0;
 
    ortho << 2.0/width , 0 ,0, 0,                   //根据公式求得ortho矩阵,这里直接将平移和缩放两步写在一起了
             0, 2.0/height,0,0,
             0,0,2.0/(zNear-zFar),-(zNear+zFar)/(zNear-zFar),
             0,0,0,1;
 
    projection = ortho * persp_to_ortho * projection;   
 
    return projection;
}

绘制过程:

代码分析

简要分析一下整体的一个绘制流程
首先定义了绘制的视口 同时初始化了像素缓冲区 与 深度缓冲区:

rst::rasterizer r(700, 700);
rst::rasterizer::rasterizer(int w, int h) : width(w), height(h)
{
    frame_buf.resize(w * h);
    depth_buf.resize(w * h);
}

定义相机位置、三角形三个顶点在空间中的位置,三个顶点的索引顺序,注意我这里相机位置和顶点位置设置的都和原来不一样,这里后面再提:

Eigen::Vector3f eye_pos = {0, 0, 0};

std::vector<Eigen::Vector3f> pos{
   
   {2, 0, 12}, {0, 2, 12}, {-2, 0, 12}};

std::vector<Eigen::Vector3i> ind{
   
   {0, 1, 2}};

然后创建对应三角形的顶点缓冲区以及索引缓冲区:

auto pos_id = r.load_positions(pos);
auto ind_id = r.load_indices(ind);
rst::pos_buf_id rst::rasterizer::load_positions(const std::vector<Eigen::Vector3f> &positions)
{
    auto id = get_next_id();
    pos_buf.emplace(id, positions);

    return {id};
}

rst::ind_buf_id rst::rasterizer::load_indices(const std::vector<Eigen::Vector3i> &indices)
{
    auto id = get_next_id();
    ind_buf.emplace(id, indices);

    return {id};
}

然后就是设置模型、观察以及透视矩阵,最后绘制
绘制部分:

void rst::rasterizer::draw(rst::pos_buf_id pos_buffer, rst::ind_buf_id ind_buffer, rst::Primitive type)
{
    if (type != rst::Primitive::Triangle)
    {
        throw std::runtime_error("Drawing primitives other than triangle is not implemented yet!");
    }
    读取对应的三角形的顶点以及索引信息
    auto& buf = pos_buf[pos_buffer.pos_id];
    auto& ind = ind_buf[ind_buffer.ind_id];

    float f1 = (100 - 0.1) / 2.0;
    float f2 = (100 + 0.1) / 2.0;

    Eigen::Matrix4f mvp = projection * view * model;
    for (auto& i : ind)
    {
        Triangle t;
       将读取到的顶点坐标转换成齐次坐标的形式,并进行MVP变换,然后存储下来。
        Eigen::Vector4f v[] = {
                mvp * to_vec4(buf[i[0]], 1.0f),
                mvp * to_vec4(buf[i[1]], 1.0f),
                mvp * to_vec4(buf[i[2]], 1.0f)
        };
        透视除法
        for (auto& vec : v) {
            vec /= vec.w();
        }
        转换到像素空间
        for (auto & vert : v)
        {
            vert.x() = 0.5*width*(vert.x()+1.0);
            vert.y() = 0.5*height*(vert.y()+1.0);
            vert.z() = vert.z() * f1 + f2;
        }
        设置三角形的各个顶点
        for (int i = 0; i < 3; ++i)
        {
            t.setVertex(i, v[i].head<3>());
            t.setVertex(i, v[i].head<3>());
            t.setVertex(i, v[i].head<3>());
        }
        设置各个顶点的颜色
        t.setColor(0, 255.0,  0.0,  0.0);
        t.setColor(1, 0.0  ,255.0,  0.0);
        t.setColor(2, 0.0  ,  0.0,255.0);
        绘制 这里是用线框形式绘制 使用的画线算法是Bresenham
        rasterize_wireframe(t);
    }
}


http://www.kler.cn/a/523871.html

相关文章:

  • 推动知识共享的在线知识库实施与优化指南
  • 剑指 Offer II 007. 数组中和为 0 的三个数
  • 基于Cipher的Java加密工具类
  • nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)
  • 获取snmp oid的小方法1(随手记)
  • Kmesh v1.0 正式发布
  • 国内外大语言模型领域发展现状与预期
  • 硬件学习笔记--35 AD23的使用常规操作
  • HTB:Forest[WriteUP]
  • 算法随笔_19: 数组中的最长山脉
  • DeepSeek助力学术文献搜索!
  • 安装VMware17
  • SQL进阶实战技巧:如何构建用户行为转移概率矩阵,深入洞察会话内活动流转?
  • JavaScript系列(45)--响应式编程实现详解
  • FFmpeg 自定义IO和格式转换
  • < OS 有关 > Android 手机 SSH 客户端 app: connectBot
  • JavaScript正则表达式
  • 【04-自己画P封装,并添加已有3D封装】
  • Ansible自动化运维实战--script、unarchive和shell模块(6/8)
  • 【第九天】零基础入门刷题Python-算法篇-数据结构与算法的介绍-六种常见的图论算法(持续更新)
  • leetcode 1493. 删掉一个元素以后全为 1 的最长子数组
  • 书生大模型实战营3
  • vs2013 使用 eigen 库编译时报 C2059 错的解决方法
  • 大数据Hadoop入门3
  • 2023年吉林省职业院校技能大赛网络系统管理样题-网络配置(华三代码)
  • electron typescript运行并设置eslint检测