GAMES101作业6
声明:使用的是vs2022版,以下内容如有问题,感谢各位大佬指正!
作业要求:
将专注于使用光线追踪来渲染图像。在光线追踪中最重要的操作之一就是找到光线与物体的交点。一旦找到光线与物体的交点,就可以执行着色并返回像素颜色。在场景中的物体数量不大时,该做法可以取得良好的结果,但当物体数量增多、模型变得更加复杂,该做法将会变得非常低效。因此,我们需要加速结构来加速求交过程。在本次练习中,我们重点关注物体划分算法 Bounding Volume Hierarchy (BVH)。本练习要求你实现 Ray-Bounding Volume 求交与 BVH 查找。
工作框架:
└─>Renderer.cpp→生成主光线
└─>Triangle.hpp→实现Möller-Trumbore 算法
└─>Bounds3.hpp→光线与AABB相交检测
└─>BVH.cpp→BVH空间划分
作业效果:

💡我们需要做的:
关键词:Möller-Trumbore 算法;光线追踪;AABB;BVH;
1.在Renderer.cpp中修改Render函数:
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));
//调用scene.castRay函数来追踪光线
framebuffer[m++] = scene.castRay(Ray(eye_pos, dir), 0);//在作业5里的castRay函数放到scene里了
}
UpdateProgress(j / (float)scene.height);
}
UpdateProgress(1.f);
2.在Triangle.hpp中修改Triangle::getIntersection : 函数:
inline Intersection Triangle::getIntersection(Ray ray)
{
Intersection inter;
//光线方向与三角形法向量点积为正,表示光线从背面入射,不相交
if (dotProduct(ray.direction, normal) > 0)
return inter;
//若det≈0,说明光线与三角形平面平行或重合,无交点。
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
u = dotProduct(tvec, pvec) * det_inv;
// u超出[0,1],交点在三角形外
if (u < 0 || u > 1)
return inter;
Vector3f qvec = crossProduct(tvec, e1);
//重心坐标v
v = dotProduct(ray.direction, qvec) * det_inv;
//v超出范围或u+v>1,交点在三角形外
if (v < 0 || u + v > 1)
return inter;
//计算光线交点
t_tmp = dotProduct(e2, qvec) * det_inv;
// TODO find ray triangle intersection
// 交点在光线反方向,无效
if (t_tmp < 0)
return inter;
inter.happened = true;
inter.coords = ray(t_tmp); //计算交点坐标
inter.normal = normal; //三角形法向量
inter.distance = t_tmp; //交点距离
inter.obj = this; //相交物件指针
inter.m = m; //材质信息
return inter;
}
3.在Bounds3.hpp中修改inline bool Bounds3::IntersectP 函数:
//光线与轴对齐包围盒相交检测算法(AABB)
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
Vector3f t1 = (pMin - ray.origin) * invDir;
Vector3f t2 = (pMax - ray.origin) * invDir;
Vector3f tMin = Vector3f::Min(t1, t2); //每组平面的最小t值(进入时间)
Vector3f tMax = Vector3f::Max(t1, t2); //每组平面的最大t值(离开时间)
float tEnter = 0.0;
float tExit = 0.0;
tEnter = std::max(tMin.x, std::max(tMin.y, tMin.z)); // 所有进入时间的最大值
tExit = std::min(tMax.x, std::min(tMax.y, tMax.z)); // 所有离开时间的最小值
//相交条件
return tEnter < tExit && tExit >= 0;
}
4.在BVH.cpp中修改Intersection BVHAccel::getIntersection函数:
//BVH的光线追踪算法
Intersection BVHAccel::getIntersection(BVHBuildNode* node, const Ray& ray) const
{
// TODO Traverse the BVH to find intersection
Intersection intersection;
// 若节点为空或光线与当前包围盒不相交,直接返回
if (node == nullptr || !node->bounds.IntersectP(ray, ray.direction_inv, { 0,0,0 }))
return intersection;
//与叶子节点中的物件(三角形)求交
if (node->left == nullptr && node->right == nullptr)
{
return node->object->getIntersection(ray); //这里调用的是obj子类:Triangle的getIntersection,即到叶子节点的包围盒开始与三角形求交
}
Intersection hit1 = getIntersection(node->left, ray); //检查左子树
Intersection hit2 = getIntersection(node->right, ray); //检查右子树
//返回距离最近的交点
return hit1.distance < hit2.distance ? hit1 : hit2;
}
【提高项】:SAH

浙公网安备 33010602011771号