games101作业6

news2024/12/23 7:04:40

作业要求

  • Render() in Renderer.cpp: 将你的光线生成过程粘贴到此处,并且按照新框
    架更新相应调用的格式。
  • Triangle::getIntersection in Triangle.hpp: 将你的光线-三角形相交函数
    粘贴到此处,并且按照新框架更新相应相交信息的格式。
    在本次编程练习中,你需要实现以下函数:
  • IntersectP(const Ray& ray, const Vector3f& invDir,
    const std::array<int, 3>& dirIsNeg) in the Bounds3.hpp: 这个函数的
    作用是判断包围盒 BoundingBox 与光线是否相交,你需要按照课程介绍的算
    法实现求交过程。
  • getIntersection(BVHBuildNode* node, const Ray ray)in BVH.cpp: 建
    立 BVH 之后,我们可以用它加速求交过程。该过程递归进行,你将在其中调
    用你实现的 Bounds3::IntersectP.

具体实现

  • Render()函数,与之前不同的是,在这里定义了一个光线Ray类,所以在算出来光线的方向之后需要生成一个Ray类的对象,其中光线的原点就是相机的位置,具体代码如下:
void Renderer::Render(const Scene& scene)
{
    std::vector<Vector3f> framebuffer(scene.width * scene.height);

    float scale = tan(deg2rad(scene.fov * 0.5));
    float imageAspectRatio = scene.width / (float)scene.height;
    Vector3f eye_pos(-1, 5, 10);
    int m = 0;
    for (uint32_t j = 0; j < scene.height; ++j) {
        for (uint32_t i = 0; i < scene.width; ++i) {
            // generate primary ray direction
            float x = (2 * (i + 0.5) / (float)scene.width - 1) *
                      imageAspectRatio * scale;
            float y = (1 - 2 * (j + 0.5) / (float)scene.height) * scale;
            // TODO: Find the x and y positions of the current pixel to get the
            // direction
            //  vector that passes through it.
            // Also, don't forget to multiply both of them with the variable
            // *scale*, and x (horizontal) variable with the *imageAspectRatio*

            // Don't forget to normalize this direction!
            Vector3f dir = normalize(Vector3f(x, y, -1));
            Ray r(eye_pos,dir);
            framebuffer[m++] = scene.castRay(r, 0);

        }
        UpdateProgress(j / (float)scene.height);
    }
    UpdateProgress(1.f);

    // save framebuffer to file
    FILE* fp = fopen("binary.ppm", "wb");
    (void)fprintf(fp, "P6\n%d %d\n255\n", scene.width, scene.height);
    for (auto i = 0; i < scene.height * scene.width; ++i) {
        static unsigned char color[3];
        color[0] = (unsigned char)(255 * clamp(0, 1, framebuffer[i].x));
        color[1] = (unsigned char)(255 * clamp(0, 1, framebuffer[i].y));
        color[2] = (unsigned char)(255 * clamp(0, 1, framebuffer[i].z));
        fwrite(color, 1, 3, fp);
    }
    fclose(fp);    
}
  • Triangle::getIntersection()函数,与上个作业不同的是,在这里把交点的信息封装成了一个Intersection对象,所以在这 之前需要熟悉一下Intersection类里面的信息,如下所示。
struct Intersection
{
    Intersection(){
        happened=false;
        coords=Vector3f();
        normal=Vector3f();
        distance= std::numeric_limits<double>::max();
        obj =nullptr;
        m=nullptr;
    }
    bool happened;   //表示光线是否与物体相交
    Vector3f coords; //相交的交点坐标
    Vector3f normal;  //相交点所在平面的法向量
    double distance; //相交点距离原点也就是相机的距离
    Object* obj;  //相交物体的类型,通过给的代码可以看出,这些类型主要有Sphere,Triangle,MeshTriangle
    Material* m;  //相交物体的材质
};

具体实现如下:

inline Intersection Triangle::getIntersection(Ray ray)
{
    Intersection inter;

    if (dotProduct(ray.direction, normal) > 0)
        return inter;
    double u, v, t_tmp = 0;
    Vector3f pvec = crossProduct(ray.direction, e2);
    double det = dotProduct(e1, pvec);
    if (fabs(det) < EPSILON)
        return inter;

    double det_inv = 1. / det;
    Vector3f tvec = ray.origin - v0;
    u = dotProduct(tvec, pvec) * det_inv;
    if (u < 0 || u > 1)
        return inter;
    Vector3f qvec = crossProduct(tvec, e1);
    v = dotProduct(ray.direction, qvec) * det_inv;
    if (v < 0 || u + v > 1)
        return inter;
    t_tmp = dotProduct(e2, qvec) * det_inv;

    // TODO find ray triangle intersection
    if(t_tmp < 0)  //t小于0没有交点
    return  inter;

    Vector3f tmp = ray.origin + t_tmp*ray.direction;
    inter.happened = true;
    inter.coords = tmp;
    inter.distance = sqrtf(dotProduct(t_tmp*ray.direction,t_tmp*ray.direction));
    inter.normal = this->normal;
    inter.m = this->m;
    inter.obj = this;
    return inter;
}
  • Bounds3::IntersectP()函数,该函数是判断光线是否与包围盒相交,需要知道课上讲的实现过程以及这个函数所给参数意义
    • 原理
      我们以2D AABB为例子,因此只有x,y两对平面,3D情况可类推:
      在这里插入图片描述
      首先如上图最左边所示,求出光线与x平面的交点,将先进入的交点(偏小的那个)记为 tmin, 后出去的交点(偏大的那个)记为 tmax,紧接着如中间图所示计算出光线与y平面的两个交点同样记为另外一组tmin, tmax,当然计算的过程中要注意如果任意的 t < 0,那么这代表的是光线反向传播与对应平面的交点。找出tmin中的较大值记为tenter,tmax中的较小值记为texit。接着还需要继续判断tenter和texit之间的关系才能确定光线和包围盒是否相交,如下图所示:
      在这里插入图片描述
    • 参数意义:ray就是光线;invDir表示一个向量,这个向量和ray中direction向量有关系,如果direction是(x,y,z),那么invDir就是(1.0/x,1.0/y,1.0/z),方便后面计算光线与平面的交点;dirIsNeg表示光线的方向;
    • 计算光线与平面的交点
      知道原理和参数意义之后就剩下计算问题了,具体方法如下
      在这里插入图片描述
      式子中的Ox,dx都是知道的,其中dx可以用invDir来代替就可以写成乘法的形式。现在只剩Px不知道,我们来看Bounds3这个类,它为我们提供了pMin,pMax两个三维向量,存储的就是包围盒的两个顶点,pMin表示包围盒x,y,z值最小的顶点,pMax表示包围盒x,y,z值最大的顶点。把pMin里面的x值换成Px相当于求出光线到达包围盒最前面那个面的时间,pMax里面的x值换成Px相当于求出光线到达包围盒最后面那个面的时间,依次就可以求出光线到达最左最右面,最上最下面的时间。代码如下:
inline bool Bounds3::IntersectP(const Ray& ray, const Vector3f& invDir,
                                const std::array<int, 3>& dirIsNeg) const
{
    // invDir: ray direction(x,y,z), invDir=(1.0/x,1.0/y,1.0/z), use this because Multiply is faster that Division
    // dirIsNeg: ray direction(x,y,z), dirIsNeg=[int(x>0),int(y>0),int(z>0)], use this to simplify your logic
    // TODO test if ray bound intersects
    float txmin = (pMin.x - ray.origin.x) * invDir.x;
    float txmax = (pMax.x - ray.origin.x) * invDir.x;
    float tymin = (pMin.y - ray.origin.y) * invDir.y;
    float tymax = (pMax.y - ray.origin.y) * invDir.y;
    float tzmin = (pMin.z - ray.origin.z) * invDir.z;
    float tzmax = (pMax.z - ray.origin.z) * invDir.z;

    //dirIsNeg表示光线的方向,如果是负的则为0,正的则为1
    if(!dirIsNeg[0])
    std::swap(txmin,txmax);
    if(!dirIsNeg[1])
    std::swap(tymin,tymax);
    if(!dirIsNeg[2])
    std::swap(tzmin,tzmax);

    float tenter = std::max(std::max(txmin,tymin),txmin);
    float texit = std::min(std::min(txmax,tymax),tzmax);

    if(texit >= 0.0 && texit > tenter)
    return true;
    return false;
}
  • BVHAccel::getIntersection()函数,该函数返回光线与包围盒内物体的交点信息,大致过程如下
    • 光线是否与包围盒相交,不相交直接返回
    • 相交的话判断是不是叶子结点,如果是就调用该节点中物体的getIntersection()得到交点信息;(根据函数上面BVHAccel::recursiveBuild()函数可知,叶子结点里面只有一个物体)
    • 不是叶子结点就继续递归下去,找出光线与两个子树的交点信息,返回距离最近的
      代码如下:
Intersection BVHAccel::getIntersection(BVHBuildNode* node, const Ray& ray) const
{
    // TODO Traverse the BVH to find intersection
    std::array<int, 3> dirIsNeg;
    dirIsNeg[0] = (ray.direction[0]>0);
    dirIsNeg[1] = (ray.direction[1]>0);
    dirIsNeg[2] = (ray.direction[2]>0);
    Intersection inter,interLeft,interRight;
    if(!node->bounds.IntersectP(ray,ray.direction_inv,dirIsNeg))  //没有交点
    return inter;
    if(node->left == nullptr && node->right == nullptr)  //是叶子结点
    {
        inter = node->object->getIntersection(ray);
        return inter;
    }

    //不是叶子结点
    interLeft = getIntersection(node->left,ray);
    interRight = getIntersection(node->right,ray);
    if(interLeft.distance < interRight.distance) return interLeft;
    else return interRight;
}

运行结果

在这里插入图片描述

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

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

相关文章

删除排序链表中的重复元素(java)

删除链表中的重复元素 leetcode 83 题 删除链表中的重复元素解题思路代码链表专题 leetcode 83 题 删除链表中的重复元素 leetcode 83 题 – 跳转链接 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。…

Python numpy - 数组与矩阵的创建&运算

数组array 一 数组的创建 &#xff08;至少两个数组&#xff09;创建随机整数数组 a 和 b import numpy as np a np.random.randint(10,size20).reshape(4,5) b np.random.randint(10,size20).reshape(4,5) 二 数组常用函数 数组常用函数 函数作用unique&#xff08;&…

Transformer part2

(179条消息) Transformer模型入门详解及代码实现_transformer模型代码-CSDN博客 transformer的encoder和decoder的差别 1. decoder包含两个 Multi-Head Attention 层。 decoder第一个 Multi-Head Attention 层采用了 Masked 操作。 为什么需要Mask处理 如何进行Mask处理 de…

【C#图解教程】第五章 类的基本概念

程序和类 类是一个能储存数据并执行代码的经过封装的数据结构&#xff0c;包含数据成员和函数成员&#xff0c;类内通常会包含逻辑上相关的数据和函数&#xff0c;所以类通常会代表真实世界或概念上的事物。 运行中的C#程序实质上是许多实例之间相互作用&#xff1a; 类的声…

ThingsBoard 前端项目内置部件开发

ThingsBoard 是目前 Github 上最流行的开源物联网平台&#xff08;12.8k Star&#xff09;&#xff0c;可以实现物联网项目的快速开发、管理和扩展&#xff0c;是中小微企业物联网平台的不二之选。 本文介绍如何在 ThingsBoard 前端项目中开发内置的菜单导航部件。 内置相关部…

clickhouse简介

文章目录 1&#xff1a;简介1.1&#xff1a;CH是什么&#xff1f;1.2&#xff1a;CH优势1.3&#xff1a;架构设计 2&#xff1a;CH接口3&#xff1a;CH引擎1&#xff1a;数据库引擎3.1.1:mysql引擎 2&#xff1a;表引擎3.2.1&#xff1a;MergeTree3.2.2&#xff1a;集成引擎1&a…

电子合同签署协议开源版系统开发

电子合同签署协议开源版系统开发 H5TP6mysqlphp 源码开源不加密 以下是电子合同系统可能包含的功能列表&#xff1a; 用户注册和登录&#xff1a;用户可以注册并登录系统&#xff0c;以便创建、签署和管理合同。合同创建&#xff1a;用户可以创建新合同&#xff0c;包括填写合…

Web的基本漏洞--SQL注入漏洞

目录 一、SQL注入介绍 1.SQL注入漏洞原理 2.SQL注入漏洞的类型 3.SQL注入漏洞识别 4.攻击方式 5.SQL盲注 时间盲注 布尔盲注 报错盲注 6.SQL注入漏洞的危害 7.SQL注入漏洞的防范措施 8.SQL注入漏洞的绕过 一、SQL注入介绍 1.SQL注入漏洞原理 Web程序输入的数据传…

使用git rebase合并多次commit

目录 rebase的作用简要概括为&#xff1a;命令&#xff1a;解决冲突&#xff1a;遗留问题&#xff1a; rebase的作用简要概括为&#xff1a; 可以对某一段线性提交历史进行编辑、删除、复制、粘贴&#xff1b;因此&#xff0c;合理使用rebase命令可以使我们的提交历史干净、简…

docker安装php

在安装 php 之前&#xff0c;我们可以先查看一下我们的镜像&#xff1a; docker images 我这里是已经存在 php 镜像了&#xff0c;版本就是 TAG 显示的 8.1.16 如果没有镜像&#xff0c;则执行下面的命令&#xff0c;拉取 php 镜像&#xff1a; docker pull php:latest 请注…

MAYLAND HOME官网上线 | LTD家居家装行业案例分享

​一、公司介绍 在MAYLAND HOME&#xff0c;我们为我们对质量和服务的承诺感到自豪。我们相信我们的成功与客户的满意度直接相关&#xff0c;这就是为什么我们努力超越您的期望&#xff0c;我们承担的每一个项目。无论您是想升级您的家庭还是企业&#xff0c;我们都会在这里帮助…

SpringBoot3 CORS跨域访问

目录 Credentials 问题一 问题二 解决方法一 CrossOrigin&#xff0c;最优的方法 解决方法二 通过Filter 设置HTTP 解决方法三 通过实现WebMvcConfigurer设置HTTP HTTP 协议&#xff0c;需要认真的学习每个细节。 allowCredentials(true) 和 allowed-origins: "*&qu…

MySQL--万文长字探究隔离性实现原理

1 隔离性简介 事务具有原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;、持久性&#xff08;Durability&#xff09;四个特性&#xff0c;简称 ACID&#xff0c;缺一不可。这篇文章旨在讲清楚…

吐血整理 二叉树(链表实现)的基本操作详解!

文章目录 节点设置二叉树的深度优先遍历前序遍历中序遍历后序遍历 二叉树的广度优先遍历层序遍历 节点的个数叶子节点的个数第K层节点的个数值为X的节点树的最大深度翻转二叉树判断两颗二叉树是否相同判断二叉树是否是完全二叉树判断二叉树是否是单值二叉树判断二叉树是否是平衡…

有哪些好用的pdf修改器?思路提供

PDF格式的文档在现代生活中扮演着越来越重要的角色。但是&#xff0c;要编辑或修改PDF文件是一件非常困难的事情&#xff0c;因为PDF文件的格式和内容通常被锁定。为了解决这个问题&#xff0c;出现了PDF修改器这种工具&#xff0c;它可以帮助用户轻松地编辑和修改PDF文件。本文…

RDK X3 Module发布,全新软硬件平台加速实现量产级产品落地

机器人开发是一段美妙的旅程。GEEKROS创始人杨状状是地平线社区的一名开发者&#xff0c;热衷于鼓捣各类机器人&#xff0c;2022年&#xff0c;状状第一时间就拿到了地平线旭日X3派&#xff08;简称旭日X3派&#xff09;&#xff0c;基于TogetheROS™.Bot机器人操作系统&#x…

Win11集成 ChatGPT,任务栏取消分组真的回来了

时隔两月微软如期发布了 Win11 Moments 3 更新&#xff0c;版本号 22621.1778 。 微软这次更新带来了许多质量更新和功能改进。 直观的改动是任务栏&#xff0c;网络图标在连接加密隧道时会上锁&#xff0c;时间显示到秒也重新回归。 日常会用到的 AltTab 任务选项卡被限制到最…

04_Cenos安装Docker

docker安装文档&#xff1a; ubuntu&#xff1a;https://docs.docker.com/engine/install/ubuntu/ centos&#xff1a;https://docs.docker.com/engine/install/centos/ debian&#xff1a;https://docs.docker.com/engine/install/debian/ cenos安装Docker前提&#xff1a; 必…

深入理解Linux虚拟内存管理(二)

系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核&#xff08;一&#xff09; 深入理解 Linux 内核&#xff08;二&#xff09; Linux 设备驱动程序&#xff08;一&#xff09; Linux 设备驱动程序&#xff08;二&#xff09; Linux 设备驱动程序&#xff08;三&#xf…

生态系统NPP及碳源、碳汇模拟、土地利用变化、未来气候变化、空间动态模拟实践技术

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现&#xff0c;“双碳”行动特别是碳中和已经在世界范围形成广泛影响。碳中和可以从碳排放&#xff08;碳源&#xff09;和碳固定&#xff08;碳汇&#xff09;这两个侧面来理解。陆地生态系统在全球碳循环过程中有着重要作…