GAMES101 作业1

news2024/10/6 2:22:38

文章目录

  • 作业内容
  • 构建视图矩阵(View)
  • 构建模型矩阵 (Model)
  • 构建透视矩阵(Projection)
  • 视口变换(Viewport transform)
  • 提高:将三角形绕任意过原点的轴旋转
    • 旋转过程中报错

作业内容

本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵。给定三维下三个
点 v0(2.0, 0.0, −2.0), v1(0.0, 2.0, −2.0), v2(−2.0, 0.0, −2.0), 你需要将这三个点的坐
标变换为屏幕坐标并在屏幕上绘制出对应的线框三角形 (在代码框架中,我们已
经提供了 draw_triangle 函数,所以你只需要去构建变换矩阵即可)。简而言之,
我们需要进行模型、视图、投影、视口等变换来将三角形显示在屏幕上。在提供
的代码框架中,我们留下了模型变换和投影变换的部分给你去完成。

需要在main.cpp中修改的函数

// 逐个元素地构建模型变换矩阵并返回该矩阵。在此函数中,你只需要实现三维中绕 z 轴旋转的变换矩阵,
// 而不用处理平移与缩放。
get_model_matrix(float rotation_angle):
//使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵。
get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar);

构建视图矩阵(View)

构建模型矩阵 (Model)

这里只需要考虑绕Z轴旋转的矩阵, 绕z轴旋转的矩阵在课程中如下
在这里插入图片描述

Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    Eigen::Matrix4f model = Eigen::Matrix4f::Identity();  //Unit Matrix

    // TODO: Implement this function
    // Create the model matrix for rotating the triangle around the Z axis.
    // Then return it.
    float rotation_angle_radian = rotation_angle * MY_PI / 180.0;
    Eigen::Matrix4f rotation_around_z;
    
    float c = cosf(rotation_angle_radian);
    float s = sinf(rotation_angle_radian)
    rotation_around_z << c, -s, 0, 0,
                         s, c, 0, 0,
                         0, 0, 1, 0,
                         0, 0, 0, 1;
    model = model * rotation_around_z;

    //std::cout << model << std::endl;

    return model;
}

构建透视矩阵(Projection)

在这里插入图片描述
计算投影矩阵,需要两步:

  1. 计算正射投影矩阵
    在这里插入图片描述

  2. 计算挤压(squish)矩阵
    计算挤压矩阵关键就是算A和B
    在这里插入图片描述
    在这里插入图片描述


Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
                                      float zNear, float zFar)
{
    // Students will implement this function
    
    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    // TODO: Implement this function
    // Create the projection matrix for the given parameters.
    // Then return it.

    // Step 1: convert from eye_fov(field of view) and aspect_ration to l, r, b, t
    float t = tan((eye_fov*MY_PI/180.0) / 2) * fabs(zNear);
    float r = aspect_ratio * t;
    float l = -r;
    float b = -t;

    // Step 2: Create Matrix for Orthographic Projection
    // First Create Translate matrix for move center to the origin
    Eigen::Matrix4f trans =  Eigen::Matrix4f::Identity();
    trans(0, 3) = -(r + l) / 2;
    trans(1, 3) = -(t + b) / 2;
    trans(2, 3) = -(zNear + zFar) / 2;

    // Scale to [-1,1]^3
    Eigen::Matrix4f scale = Eigen::Matrix4f::Identity();
    scale(0, 0) = 2.0 / (r - l);
    scale(1, 1) = 2.0 / (t - b);
    scale(2, 2) = 2.0 / (zNear - zFar);

    // Get Ortho matrix
    Eigen::Matrix4f ortho = scale * trans;
    //std::cout << "Orthographic:" << std::endl << ortho << std::endl;

     Step 3: Create Perspective to Orthographic matrix
    float A = zNear + zFar;
    float B = -zNear * zFar;
    Eigen::Matrix4f pers2ortho;
    pers2ortho << zNear, 0, 0, 0,
                0, zNear, 0, 0,
                0, 0, A, B,
                0, 0, 1, 0;

    projection = ortho * pers2ortho;
    //std::cout << projection << std::endl;

    return projection;
}

视口变换(Viewport transform)

Learn OpenGL 坐标系统
坐标系统
视口变换的部分是在rasterizer::draw接口内做的,视口变化的计算如下:
在这里插入图片描述

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 变换,并转换为齐次坐标,这一步就是将三角形转换到[1,1]*3的立方体中
        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)
        };
		
		// 把w归一化
        for (auto& vec : v) {
            vec /= vec.w();
        }
		
		// 视口变化部分计算
        for (auto & vert : v)
        {
            vert.x() = 0.5*width*(vert.x()+1.0);  //width/2*x (Scale) + width/2*1.0 
            vert.y() = 0.5*height*(vert.y()+1.0); //height/2*x + height/2*1.0
            vert.z() = vert.z() * f1 + f2;        //对z做的特殊处理
        }

        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);

        rasterize_wireframe(t);
    }
}

其中一开始对Z的特殊处理不太明白,看到其他博客里面说

可能是因为,近平面设置在0.1,远平面设置在50,用这个式子可以把转移到[-1,1]区间的z值映射到近平面和远平面之间。

参考x和y方向上的操作,实际上z方向也做了scale 和 transport 操作

  • 将z方向从[-1,1] 变换到[0.1, 100]
  • 将[0,0]平移到透视体的中点
    以下就是对z轴的变换做的特殊处理的理解,但是可能不对,是我自己画的示意图。下一节会讲解到Z-buffer,应该会有更好的理解
    在这里插入图片描述

提高:将三角形绕任意过原点的轴旋转

用到了PPT中的罗德里格斯公式,如何构造一个罗德里格斯公式呢

// converter angle to model matrix
Eigen::Matrix4f get_rotation(Vector3f axis, float angle)
{
    float a = angle * PI / 180.0;
    // Return for float value  
    float cosa = cosf(a), sina = sinf(a);
    Eigen::Matrix3f  I = Eigen::Matrix3f::Identity();
    axis = axis.normalized();

    // Get N matrix 
    Eigen::Matrix3f nhat;
    nhat << 0, -axis.z(), axis.y(),
             axis.z(), 0, -axis.x(),
            -axis.y(), axis.x(), 0;
    
    // Rodrigues’ Rotation Formula
    Eigen::Matrix3f rodrigues_rotation;
    rodrigues_rotation = I + (nhat * nhat) * (1 - cosa) + sina * nhat;

    // Contruct to Matrix4f
    Eigen::Matrix4f tRet = Eigen::Matrix4f::Zero();
    tRet.block<3, 3>(0, 0) = rodrigues_rotation;
    tRet.row(3) = Eigen::Vector4f{ 0,0,0,1 };

    return tRet;
}

Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    Eigen::Matrix4f model;
    // any axis 
    Vector3f axis{ 1, 1, 0 };
    Eigen::Matrix4f t = Eigen::Matrix4f::Identity();
    
    model = get_rotation(axis, rotation_angle);
       
    return model * t;
}

旋转过程中报错

随着按A或者D键旋转三角形,大概旋转了10次左右,程序会崩溃, 报错内容:

expression vector subscript out of range

定位发现是:

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;
    auto ind = (height-point.y())*width + point.x();
    // frame_buf size 为490000, 但是旋转过程中,ind出现大于490000的情况,此时超出了frame_buf的范围,所以会报上述错误
    // 额外增加的
    if (ind > frame_buf.size())
    {
        return;
    }
    frame_buf[ind] = color;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768211.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型开发(五):实现Jupyter本地调用OpenAI API

全文共3000余字&#xff0c;预计阅读时间约15分钟 | 满满干货&#xff0c;建议收藏&#xff01; 大模型开发(五)&#xff1a;实现Jupyter本地调用OpenAI API OpenAI作为本轮大语言模型技术进步的先驱&#xff0c;其系列大型模型在效果上一直保持着领先。其推出的各类模型如文本…

【PDF】HTML通过dom节点生成pdf

1、简要描述 上一篇博客主要讲的是pdf文件转换成canvas&#xff0c;然后进行相关的画框截图操作。 【PDF】Canvas绘制PDF及截图 本篇博客主要讲html中dom如何生成pdf文件&#xff08;前端生成pdf&#xff09;&#xff0c;后端生成pdf当然也可以&#xff0c;原理也是将html网…

数据容器入门(str)

字符串是字符的容器&#xff0c;一个字符串可以存放任意数量的字符 字符串的特点&#xff1a; 作为数据容器&#xff0c;字符串有如下特点&#xff1a; 只可以存储字符串长度任意&#xff08;取决于内存大小&#xff09;支持下标索引允许重复字符串存在不可以修改&#xff08;…

智慧数据驱动:基于smardaten构建多维数据可视化大屏

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

网络虚拟化相关的Linux接口介绍

Linux拥有丰富的网络虚拟化功能&#xff0c;能被虚拟机&#xff0c;容器还有云网络使用。在这篇文章中&#xff0c;我会给出所有通用网络虚拟化接口的简要介绍。没有代码分析&#xff0c;只有简短的接口介绍和在Linux上的使用操作。这系列接口都可以使用ip link命令实现。 这篇…

reggie优化06-项目部署

1、部署架构 2、部署环境 3、部署前端 4、部署后端 修改图片位置&#xff0c;并push至仓库

Redis数据类型(2)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 Redis数据类型1、Redis 键(key)1.1、KEYS pattern1.2、EXISTS k…

Vector - CANoe - VCDL与SomeIP

目录 一、基础介绍 二、vCDL介绍 1、vCDL工程创建 2、 vCDL编辑器关键字介绍 3、创建命名空间Datatype 接口示例 4、创建命名空间ICalculate 5、创建命名空间Participants 一、基础介绍 SomeIP作为车载以太网一个重要的组成部分&#xff0c;因为它的测试也是我们作为总…

windows PE 指南(基础部分)(二)

windows PE 指南&#xff08;基础部分&#xff09;&#xff08;二&#xff09; PE文件头IMAGE_OPTIONAL_HEADER.AddressOfEntryPointSectionAlignmentFileAlignment PE文件布局和装入后内存布局节表内容你想在PE文件&#xff08;PE内存映像&#xff09;里面找一个数据该怎么找&…

iOS-Block

Blocks的学习 Block的分类 Block根据其类型可以分为三类&#xff1a; 全局Block&#xff08;NSGlobalBlock&#xff09;栈Block&#xff08;NSMallocBlock&#xff09;堆Block&#xff08;NSStackBlock&#xff09; 而其区分的规则为&#xff1a; 如果没有引用局部变量&…

PHP特性之CTF中常见的PHP绕过

目录 一、关于md5()和sha1()的常见绕过 1、使用数组绕过 2、 使用特殊字符串绕过 二、strcmp绕过 三、switch绕过 四、intval绕过 一、关于md5()和sha1()的常见绕过 知识介绍&#xff1a; 1、对于php强比较和弱比较&#xff1a;md5()&#xff0c;sha1()函数无法处理数组…

【数据挖掘】如何为可视化准备数据

一、说明 想要开始您的下一个数据可视化项目吗&#xff1f;首先与数据清理友好。数据清理是任何数据管道中的重要步骤&#xff0c;可将原始的“脏”数据输入转换为更可靠、相关和简洁的数据输入。诸如Tableau Prep或Alteryx之类的数据准备工具就是为此目的而创建的&#xff0c;…

【ACM】—蓝桥杯大一暑期集训Day4

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前正在学习C/C、Java、算法等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&#xff…

基于STM32的homeassistant(采用FreeRTOS操作系统)【第一、二章优化拓展:Wifi、服务器连接验证以及UASRT串口区分】

第一、二章优化拓展开发环境&#xff1a; 主控STM32F103C8T6WIFI模块ESP01S开发语言C开发编译器 KEIL 组网方式WIFI服务器协议MQTT 硬件连接 STM32ESP01S3.3V3.3V GND GND GPIO2 (USRAT2-TX) RXGPIO3 (USART3-RX)TX 本章要点&#xff1a; 对ESP01S的AT指令的反馈指令进…

集合面试题--HashMap

目录 HashMap实现原理 HashMap的jdk1.7和jdk1.8有什么区别 总结 HashMap的put方法的具体流程 常见属性 添加数据的流程图 ​编辑 具体实现源码 总结 HashMap的扩容机制 总结 hashMap的寻址算法 总结 hashmap在1.7情况下的多线程死循环问题 HashMap实现原理 HashMap的…

MyBatis的多表操作

1 MyBatis的多表操作 1.1 多表模型介绍 我们之前学习的都是基于单表操作的&#xff0c;而实际开发中&#xff0c;随着业务难度的加深&#xff0c;肯定需要多表操作的。 多表模型分类 一对一&#xff1a;在任意一方建立外键&#xff0c;关联对方的主键。 一对多&#xff1a;在…

IDEA 工具- Java - Tomcat 9.x - 无法使用外部 tomcat 服务器的断点测试功能

问题&#xff1a;使用外部 Tomcat 运行项目&#xff0c;却无法使用断点功能测试 Java 项目 解决方法&#xff1a; 在 IDEA 工具的tomcat Edit configurations&#xff0c;进行修改 具体配置位置&#xff1a; Environment Variables 配置选项添加内容&#xff1a; NameValueJ…

Unity游戏源码分享-线条圆圈游戏Line and Circle Game Template

Unity游戏源码分享-线条圆圈游戏Line and Circle Game Template 圆圈穿过线条就通关 工程地址&#xff1a; https://download.csdn.net/download/Highning0007/88061484

java学习路程之篇十、知识点、数组介绍、二维数组介绍、静态初始化、访问元素、遍历元素、动态初始化、内存图、数组常见问题

文章目录 01、数组介绍02、数组静态初始化03、数组元素访问04、数组遍历操作05、数组动态初始化06、数组内存图07、数组常见问题08、二维数组介绍09、二维数组静态初始化10、二维数组遍历11、二维数组动态初始化12、二维数组内存图 01、数组介绍 02、数组静态初始化 03、数组元…