Games101Homework【6】Acceleration structure(Including framework analysis)
Code Analysis:
friend:
C++中友元(友元函数和友元类)的用法和功能_friend class a<b>-CSDN博客
[C++:不如Coding](11):友元函数与友元类_哔哩哔哩_bilibili
Here is a simple explanation:
By using the mechanism of classes, data hiding and encapsulation are achieved. Data members of a class are usually defined as private, while member functions are generally defined as public, thus providing an interface for communication between the class and the outside world. However, sometimes it is necessary to define functions that are not part of the class but need frequent access to the class's data members. In such cases, these functions can be defined as friend functions of the class. In addition to friend functions, there are also friend classes, both of which are collectively referred to as friends. The purpose of friends is to improve the efficiency of the program (by reducing the time overhead of type checking and security checks, etc.). However, they undermine the encapsulation and hiding of the class, allowing non-member functions to access the class's private members.
Why use friends: You don't have to write a public method for a special case separately (for example, for a man and a woman, there is a marry method that is generally called only once during the lifecycle of these two classes. If you give the man or woman class a public method, marry, it is unnecessary and would make the class overly complex).
Operator overloading:
C++运算符重载_哔哩哔哩_bilibili
std::Move:
The functionality of std::move
is to convert a left-value into an r-value reference, and return that r-value reference, allowing the value to be used via the r-value reference for move semantics (move constructor or move assignment operator).
std::move()与移动构造函数_std::move的作用-CSDN博客
Architecture:
Let's look at the picture first:
The logical architecture is exceptionally clear now, and I've placed the source code (with comments) in another blog.
Games101Homework【6】Code Part-CSDN博客
Principle:
Checking if a ray intersects with a plane.:
Determine the entry point and exit point:
BVH Core Algorithm (Recursive):
Code:
Render():
Transform the manually added vectors into a new Ray object:
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 directionfloat 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*Ray ray(eye_pos, normalize(Vector3f(x, y, -1)));// Don't forget to normalize this direction!framebuffer[m++] =scene.castRay(ray,scene.maxDepth);}UpdateProgress(j / (float)scene.height);}UpdateProgress(1.f);// save framebuffer to fileFILE* 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():
Calculate intersection information:
/*** 获取射线与三角形的交点信息* * @param ray 射线对象,包含射线的起点和方向* @return Intersection 结构体,包含交点是否发生、交点坐标、交点到射线起点的距离、* 对应的物体指针、交点处的法向量和材质信息*/
inline Intersection Triangle::getIntersection(Ray ray)
{Intersection inter; // 初始化交点信息结构体// 如果射线方向与三角形法向量的点积大于0,则射线方向与三角形面向反,不产生交点if (dotProduct(ray.direction, normal) > 0)return inter;double u, v, t_tmp = 0;// 计算pvec,这是进行交点计算的一部分Vector3f pvec = crossProduct(ray.direction, e2);// 计算行列式值det,用于后续交点计算double det = dotProduct(e1, pvec);// 如果行列式的绝对值小于EPSILON,表示方向向量几乎平行,不产生交点if (fabs(det) < EPSILON)return inter;// 计算行列式的倒数,用于简化后续计算double det_inv = 1. / det;// 计算tvec,这是计算u参数的一部分Vector3f tvec = ray.origin - v0;// 计算参数u,如果u不在0到1之间,则交点不在三角形上u = dotProduct(tvec, pvec) * det_inv;if (u < 0 || u > 1)return inter;// 计算qvec,用于计算v参数Vector3f qvec = crossProduct(tvec, e1);// 计算参数v,如果v不在0到1之间,或u+v不在0到1之间,则交点不在三角形上v = dotProduct(ray.direction, qvec) * det_inv;if (v < 0 || u + v > 1)return inter;// 计算临时距离参数t_tmp,用于进一步判断交点是否成立t_tmp = dotProduct(e2, qvec) * det_inv;// 判断t_tmp是否小于0,若小于0,则交点在射线的起点之后,不成立if(t_tmp<0){return inter;}// 如果以上所有条件都满足,则更新交点信息为有效交点inter.happened = true;inter.coords = ray(t_tmp); // 计算交点坐标inter.distance = t_tmp; // 保存交点到射线起点的距离inter.obj = this; // 保存对应的三角形对象指针inter.normal = normal; // 保存交点处的法向量inter.m = m; // 保存材质信息return inter;
}
IntersectP():
"Solve equations to calculate tEnter and tExit. Based on the direction of the ray, if it is emitted in the non-positive direction, then the smaller negative t is the exit point, and the larger one is the entry point (dirIsNeg).
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 intersectsVector3f tEnter,tExit;tEnter= (pMin-ray.origin)*invDir;tExit = (pMax-ray.origin)*invDir;if(!dirIsNeg[0]){std::swap(tEnter.x,tExit.x);}if(!dirIsNeg[1]){std::swap(tEnter.y,tExit.y);}if(!dirIsNeg[2]){std::swap(tEnter.z,tExit.z);}float tenter,texit;tenter=std::max(tEnter.x,std::max(tEnter.y,tEnter.z));texit=std::min(tExit.x,std::min(tExit.y,tExit.z));return tenter<=texit&&texit>=0;}
getIntersection():
Implementing the core algorithm:
Intersection BVHAccel::getIntersection(BVHBuildNode* node, const Ray& ray) const
{Intersection isect;// TODO Traverse the BVH to find intersectionif(!node->bounds.IntersectP(ray,ray.direction_inv,std::array<int,3>{ray.direction.x>0,ray.direction.y>0,ray.direction.z>0})) return isect;if((!node->left)&&(!node->right)){return node->object->getIntersection(ray);}auto hit1=getIntersection(node->left,ray);auto hit2=getIntersection(node->right,ray);return hit1.distance<hit2.distance?hit1:hit2;
}
Result:
cool!
相关文章:

Games101Homework【6】Acceleration structure(Including framework analysis)
Code Analysis: friend: C中友元(友元函数和友元类)的用法和功能_friend class a<b>-CSDN博客 [C:不如Coding](11):友元函数与友元类_哔哩哔哩_bilibili Here is a simple…...
应用运维文档1
统一nginx接入配置指南 Nginx配置规范 1:不带微服务编码上下文至后端,以metadata-ui为例 location段配置信息,location配置中维护微服务编码上下文信息 # app_code: metadata-ui 流水线名称: metadata-ui location ~ ^/metadata-ui/(?P.*) {set $app_code metadata-ui;p…...

手机如何在线制作gif?轻松一键在线操作
现在大家都喜欢使用手机来拍摄记录有趣的事物,但是时间长了手机里的视频越来越多导致手机存储空间不够了,这些视频又不想删除时应该怎么办呢?这个很简单,下面就给大家分享一款不用下载手机就能操作的视频转gif网站-GIF中文网&…...

ChatGPT 在做什么,为什么有效?
原文:What Is ChatGPT Doing … and Why Does It Work? 译者:飞龙 协议:CC BY-NC-SA 4.0 序言 这本简短的书试图从第一原理解释 ChatGPT 是如何工作的。在某种程度上,这是关于技术的故事。但它也是关于科学的故事。以及关于哲学…...

Linux实验2 初步使用shell
一:实验目的 学习Linux下的文件系统结构,了解最基本的Linux下的shell命令操作,例如ls, cd, cat等各种指令操作。 学习vim编辑器的使用方式,学习如何使用ssh连接远程服务器。 二:实验内容 1.请指出下面每…...

甘特图/横道图制作技巧 - 任务组
在甘特图中通过合理的任务分组可以让项目更加清晰,修改也更方便。 列如下面的甘特图一眼不太容易看清楚整体的进度。或者需要把所有的任务整体的延迟或者提前只能这样一个一个的任务调整,就比较麻烦。 通过给任务分组,看这上面整体的进度就…...

Web题记
反序列化补充知识: private变量会被序列化为:\x00类名\x00变量名 protected变量会被序列化为: \x00\*\x00变量名 public变量会被序列化为:变量名web254 这个逻辑不难,自己刚看的时候还奇怪是不是自己哪里想错了,因为…...
学习java第三十六天
Spring 官网列出的 Spring 的 6 个特征: 核心技术 :依赖注入(DI),AOP,事件(events),资源,i18n,验证,数据绑定,类型转换,SpEL。 测试 :模拟对象,…...
0205矩阵分块法-矩阵及其运算-线性代数
文章目录 1 分块矩阵的定义2 分块矩阵的运算(性质)3 按列分块与按行分块 结语 1 分块矩阵的定义 将矩阵A用若干条纵线和横线分成许多个小矩阵,每一个小矩阵称为A的子快,以子块为元素的形式上的矩阵称为分块矩阵。 2 分块矩阵的运算…...

1、java语法入门(找工作版)
文章目录 一、Java简介二、Java常量与变量1、标识符2、关键字3、变量4、类的命名规则5、数据类型6、基本数据类型字面值7、变量的定义与初始化8、ASCII码和Unicode编码9、转义字符10、类型转换11、常量 三、Java运算符1、算术运算符2、赋值运算符3、关系运算符4、逻辑运算符5、…...

arm的状态寄存器
目录 一、arm 的 PSRs二、CPSR2.1 CPSR_cxsf 三、SPSR四、APSR 一、arm 的 PSRs arm 中有很多程序状态寄存器(Program Status Registers,PSRs)用于存储处理器的状态信息,包括 CPSR\SPSR\FPSR\APSR 等: CPSRÿ…...
2024 蓝桥打卡Day34
20240406蓝桥杯备赛 1、学习蓝桥云课省赛冲刺课 【1-手写与思维】【2-递归与递推】2、学习蓝桥云课Java省赛无忧班 【1-语言基础】3、代码练习字符串排序大小写转换 (ccfcsp之前要是学了我就能上200了 啊啊啊啊 错过啊)斐波那契数列 递归解法纸张尺寸问题…...

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第九套
华为海思校园招聘-芯片-数字 IC 方向 题目分享(有参考答案)——第九套 部分题目分享,完整版获取(WX:didadidadidida313,加我备注:CSDN huawei数字芯片题目,谢绝白嫖哈) 单选 1&…...
如何创建虚拟环境打包py文件
Python 项目通常依赖于特定的库和版本。不同的项目可能依赖于相同库的不同版本,这可能导致冲突。使用虚拟环境,你可以为每个项目创建一个独立的 Python 环境,每个环境都有自己的库和版本,从而避免了依赖冲突。 采用虚拟环境打包P…...

CSS 学习笔记 总结
CSS 布局方式 • 表格布局 • 元素定位 • 浮动布局(注意浮动的负效应) • flex布局 • grid布局(感兴趣的可以看下菜鸟教程) 居中设置 元素水平居中 • 设置宽度后,margin设置为auto • 父容器设置text-alig…...
基于Swin Transformers的乳腺癌组织病理学图像多分类
乳腺癌的非侵入性诊断程序涉及体检和成像技术,如乳房X光检查、超声检查和磁共振成像。成像程序对于更全面地评估癌症区域和识别癌症亚型的敏感性较低。 CNN表现出固有的归纳偏差,并且对于图像中感兴趣对象的平移、旋转和位置有所不同。因此,…...

MySQL主从的介绍与应用
mysql主从 文章目录 mysql主从1. 主从简介1.1 主从作用1.2 主从形式 2. 主从复制原理3. 主从复制配置3.1 mysql安装(两台主机安装一致,下面只演示一台主机操作)3.2 mysql主从配置3.2.1 确保从数据库与主数据库里的数据一样3.2.2 在主数据库里…...
pytest中文使用文档----12缓存:记录执行的状态
1. cacheprovider插件 1.1. --lf, --last-failed:只执行上一轮失败的用例1.2. --ff, --failed-first:先执行上一轮失败的用例,再执行其它的1.3. --nf, --new-first:先执行新加的或修改的用例,再执行其它的1.4. --cache…...

【代码随想录】哈希表
文章目录 242.有效的字母异位词349. 两个数组的交集202. 快乐数1. 两数之和454. 四数相加 II383. 赎金信15. 三数之和18. 四数之和 242.有效的字母异位词 class Solution {public boolean isAnagram(String s, String t) {if(snull || tnull || s.length()!t.length()){return …...

绘图工具 draw.io / diagrams.net 免费在线图表编辑器
拓展阅读 常见免费开源绘图工具 OmniGraffle 创建精确、美观图形的工具 UML-架构图入门介绍 starUML UML 绘制工具 starUML 入门介绍 PlantUML 是绘制 uml 的一个开源项目 UML 等常见图绘制工具 绘图工具 draw.io / diagrams.net 免费在线图表编辑器 绘图工具 excalidr…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...