Games101作业5

1.实现Renderer.cpp 中的 Render():为每个像素生成光线

这里你需要为每个像素生成一条对应的光 线,然后调用函数 castRay() 来得到颜色,最后将颜色存储在帧缓冲区的相 应像素中。

我们要做的就是将屏幕空间下的坐标最后转换到世界空间的坐标

这里一开始是处于屏幕空间坐标下的,如下图,这里假设原点在左上角,opengl原点在左下角,dx原点在左上角,那么首先想到的是将i,j分别加0.5取得像素中心坐标

接着将坐标变换到NDC空间,NDC空间是一个长宽高取值范围为[-1,1]的立方体,超过这个范围的顶点,会被GPU剪裁。:在DirectX里面,NDC的z方向取值范围是[0,1]

DX下的NDC空间如下图,要转换到NDC空间下,首先要用x,y分别除以屏幕的宽度贺高度。然后NDC空间需要将坐标轴原点变回到屏幕中间位置。

 i方向即宽方向,[0,1]->[-1,1],因为变化是线性的,很容易得到 i = 2*i-1。

 j方向即高方向,[0,1]->[1,-1],因为变化是线性的,很容易得到 i = -2*i+1

最后要将坐标转换到世界空间,要解决两个问题:

①横纵方向的长度并不是1:1的;

②物体本身并不是在[-1,1]的,[-1,1]是缩放后的范围。

解决办法:

①imageAspectRatio即宽高比,是原本scene的宽高比,所以要想恢复原始的比例需要用 宽 * 宽高比,即 x * imageAspectRatio。

②scale为一半可看角度(fov/2)的tan值,即下图tan(α/2),它代表了原本图像屏幕高度与图像到X-Y平面距离的比值,又由代码已给出的 Vector3f dir = Vector3f(x, y, -1) ,可以知道原本的图像屏幕距离X-Y平面为1,所以scale即为原本的图像高度,而现在的图像高度为1,所以令x,y同时乘以scale即可得到原始世界坐标下的坐标。

综上所述,最后直接给出代码计算

void Renderer::Render(const Scene& scene)
{std::vector<Vector3f> framebuffer(scene.width * scene.height);//float scale = std::tan(deg2rad(scene.fov * 0.5f));//宽高比float imageAspectRatio = (float)scene.width / (float)scene.height;// Use this variable as the eye position to start your rays.Vector3f eye_pos(0);int m = 0;for (int j = 0; j < scene.height; ++j){for (int i = 0; i < scene.width; ++i){// generate primary ray directionfloat x = (2 * (((float)i + 0.5) / scene.width) - 1)* imageAspectRatio * scale;float y = (1.0 - 2 * ((float)j + 0.5) / 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*    //vector = op,说明scene在z=-1,故znear距离人眼距离=1   Vector3f dir = normalize(Vector3f(x, y, -1)); // Don't forget to normalize this direction!framebuffer[m++] = castRay(eye_pos, dir, scene, 0);}UpdateProgress(j / (float)scene.height);}// 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] = (char)(255 * clamp(0, 1, framebuffer[i].x));color[1] = (char)(255 * clamp(0, 1, framebuffer[i].y));color[2] = (char)(255 * clamp(0, 1, framebuffer[i].z));fwrite(color, 1, 3, fp);}fclose(fp);
}

到这一步输出的结果:

window下查看ppm图片貌似需要用到第三方软件,这里给出我用的一个网站:

在线查看 PPM 文件的免费在线工具 - ImageToStl

2.Triangle.hpp 中的 rayTriangleIntersect():实现视射线与三角形相交

主要就是根据这个公式分别带入不同的参数就可以

origin是相机的位置,dir是射出的方向

bool rayTriangleIntersect(const Vector3f& v0, const Vector3f& v1, const Vector3f& v2, const Vector3f& orig,const Vector3f& dir, float& tnear, float& u, float& v)
{// TODO: Implement this function that tests whether the triangle// that's specified bt v0, v1 and v2 intersects with the ray (whose// origin is *orig* and direction is *dir*)// Also don't forget to update tnear, u and v.Vector3f E1 = v1 - v0, E2 = v2 - v0 ;Vector3f S = orig - v0,S1 = crossProduct(dir, E2), S2 = crossProduct(S, E1);if (dotProduct(S1, E1) <= 0) return false;tnear = dotProduct(S2, E2) / dotProduct(S1, E1);u = dotProduct(S1, S) / dotProduct(S1, E1);v = dotProduct(S2, dir) / dotProduct(S1, E1);if (tnear >= 0 && u >= 0 && v >= 0 && (1 - u - v) >= 0) return true;return false;
}

最后的结果

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Innosetup 调用c# dll 和 c# dll的函数导出

目标需求&#xff0c;基于现在安装包脚本。需要在用户安装和卸载成功时。进行数据记录,所以需要调用c#dll 主要涉及到的知识点 需要理解脚本的文件使用机制脚本的文件dll加载&#xff0c;和dll的调用c# dll的制作&#xff0c;和工具的使用 下面具体介绍 脚本的文件dll加载&…

鸿蒙应用开发 Web 组件抽奖

1 概述 相信大家都遇到过这样的场景&#xff0c;有时候我们点击应用的页面&#xff0c;会跳转到一个类似浏览器加载的页面&#xff0c;加载完成后&#xff0c;才显示这个页面的具体内容&#xff0c;这个加载和显示网页的过程通常都是浏览器的任务。 ArkUI 为我们提供了 Web 组…

小米汽车 SU7 技术发布会-智能驾驶猜想,真的“吊打”特斯拉?

核心主题 本人AI数据工程师&#xff0c;看完小米汽车 SU7 技术发布会&#xff0c;主谈智能驾驶猜想。 小米汽车披露&#xff1a;智能驾驶要2024年跻身第一梯队 发布会前沿致敬经典&#xff0c;挺好的毕竟礼多人不怪。 见面道辛苦&#xff0c;必定是江湖。 见面致经典&#…

hyperf console 执行

一、原理描述 hyperf中&#xff0c;不难发现比如自定义控制器中获取参数&#xff0c;hyperf.php中容器获取&#xff0c;传入的都是接口&#xff0c;而不是实体类。 这是因为框架中的配置文件有设置对应抽象类的子类&#xff0c;框架加载的时候将其作为数组&#xff0c;使用的…

《Linux系统与网络管理》复习题库---简答题

1、简述这些分区的名字以及各自的作用。 答&#xff1a; /boot 存放内核镜像的地方&#xff0c;这个文件夹独立分区的意义在于降低不能开机的风险。 /根目录&#xff0c;一般采用 etx3 文件系统&#xff0c;分区的容量一定要大于安装软件包的容量。 /usr 多数软件的默认安装的地…

ssm基于vue框架的点餐系统的设计与实现+vue论文

基于vue框架的点餐系统的设计与实现 摘要 当下&#xff0c;正处于信息化的时代&#xff0c;许多行业顺应时代的变化&#xff0c;结合使用计算机技术向数字化、信息化建设迈进。传统的点餐信息管理模式&#xff0c;采用人工登记的方式保存相关数据&#xff0c;这种以人力为主的…

私有部署ELK,搭建自己的日志中心(六)-- 引入kafka对采集日志进行削峰填谷

一、背景 首先&#xff0c;要说明一点&#xff0c;elk日志中心&#xff0c;是可以缺少kafka组件的。 其次&#xff0c;如果是研发环境下&#xff0c;机器资源紧张的情况下&#xff0c;也是可不部署kafka。 最后&#xff0c;因为kafka的部署是可以独立的&#xff0c;所以本文将…

Scrapy使用案例——爬取豆瓣Top 250电影数据

文章目录 什么是Scrapy&#xff1f;创建Scrapy项目编写Scrapy Spider创建Item类配置数据存储运行Scrapy爬虫处理常见问题结论Python技术资源分享1、Python所有方向的学习路线2、学习软件3、入门学习视频4、实战案例5、清华编程大佬出品《漫画看学Python》6、Python副业兼职与全…

2023年03月22日_谷歌Bard开放公测的解读

文章目录 定位谷歌的求生欲Bard的演示翻车 2023年3月22日 面对OpenAI和微软的步步紧逼 谷歌这次终于呢不再坐以待毙了 昨天 谷歌正式宣布开放旗下Bard的公测 作为跟ChatGPT的正面竞争 首先呢面向英国和美国地区启动 目前这两个国家的用户呢 都可以在Bard.google.com 上…

【网络安全】网络隔离设备

一、网络和终端隔离产品 网络和终端隔离产品分为终端隔离产品和网络隔离产品两大类。终端隔离产品一般指隔离卡或者隔离计算机。网络隔离产品根据产品形态和功能上的不同&#xff0c;该类产品可以分为协议转换产品、网闸和网络单向导入产品三种。 图1为终端隔离产品的一个典型…

提升客户体验!十大热门客户服务软件解决方案推荐

现代企业深切认识到客户关系对于成功至关重要。如今&#xff0c;顾客越来越偏向于个性化和情境化服务的企业。根据Forrester的研究&#xff0c;将优先考虑建立更好客户关系以实现长期增长将是2023年业务成功的关键。 为了评估和改善客户关系&#xff0c;您需要一个系统化的方式…

自激振荡电路笔记 电弧打火机

三极管相关 三极管的形象描述 二极管 简单求解&#xff08;理想&#xff09; 优先导通&#xff08;理想&#xff09; 恒压降 稳压管&#xff08;二极管plus&#xff09; 基础工作模块 理想稳压管的工作特性 晶体管之三极管(“两个二极管的组合” ) 电弧打火机电路 1.闭合开…