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

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.lryc.cn/news/270596.html

相关文章:

  • Golang解决跨域问题【OPTIONS预处理请求】
  • 复试 || 就业day05(2023.12.31)算法篇
  • Spring-4-代理
  • 设计模式:抽象工厂模式(讲故事易懂)
  • C语言中的Strict Aliasing Rule
  • 单字符检测模型charnet使用方法,极简
  • Erlang、RabbitMQ下载与安装教程(windows超详细)
  • 2023年终总结丨很苦,很酷!
  • 鸿蒙 DevEco Studio 3.1 入门指南
  • ubuntu多用户环境dockerbug,卸载重装docker流程
  • 微信小程序开发系列-09自定义组件样式特性
  • 数据结构 模拟实现LinkedList单向不循环链表
  • 2023-12-24 LeetCode每日一题(收集足够苹果的最小花园周长)
  • Oracle 19c OCP 1z0 082考场真题解析第17题
  • 掌握这十几个Python库才是爬虫界的天花板,没有你搞不定的网站!实战案例:Python全网最强电影搜索工具,自动生成播放链接
  • 模型 KANO卡诺模型
  • 启明智显开源项目分享|基于Model 3c芯片的86中控面板ZX3D95CM20S-V11项目软硬件全开源
  • Kind创建k8s - JAVA操作控制
  • Qt sender()函数
  • Java开发框架和中间件面试题(6)
  • 附录E SQL入门之SQL保留字
  • thinkphp6.0升级到8.0
  • 机器学习(一) -- 概述
  • SpringBoot定时监听RocketMQ的NameServer
  • 电子招标采购系统源码之从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理
  • 各部门请注意,VELO维乐潮流骑士尼莫出街啦,快来加入吧!
  • Flutter配置Android和IOS允许http访问
  • [设计模式 Go实现] 创建型~抽象工厂模式
  • 移动端开发框架mui代码在安卓模拟器上运行(HbuilderX连接到模拟器)
  • upload-labs Pass-03(黑名单验证,特殊后缀)问题纠正