前言
由于上个月CSDN无故告诉我我的原创文章侵权(原创也侵权?),且我多日内多次申诉无效,于是我没有再更新自己的博客。今天我上CSDN的时候自己的文章(没有任何更改,莫名其妙就不侵权了?)又突然通过了,想着还是把这个系列更新完吧,不能半途而废。
本篇继续更新作业5相关内容
作业5相关链接
作业5简述
- 使用光线追踪渲染图像
作业5相关知识笔记
- Whitted-Style Ray Tracing(Soft shadows、Glossy reflection、Indirect illumination)
- 克拉默法则
- Axis-Aligned Bounding Box(AABB)
作业5思路
1.main函数梳理
可以看到main函数中新建了1280*960的场景以及定义两个sphere、一个mesh以及它们的材质颜色和两个光源。至于它们怎么实现的,分别写在了对应的c++文件中。
关于std::move(),我觉得知乎上这篇讲右值引用很好,或者参照《C++Premier》进行理解。
2.实现Reder()
首先要实现光线的生成,注意这里要对应到每个像素。而原Reder()中对应i,j为每个单位高度/宽度,我们要将i,j转化到单位像素上去。
原来scene内width应为(0,width-1),height应为(height -1,0)(从左上角开始遍历),而且在上面我们将scene进行了压缩到了[-1,1]的范围空间,所以这里i,j也要进行压缩,还原时也要乘上相应系数。查看原理
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 = 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 direction
float x;
float y;
// 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*
x = (((i + 0.5) / ((float)scene.width) * 2)-1) * imageAspectRatio * scale;
y = (1 - (j + 0.5) / (float)scene.height * 2 )* scale ;
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 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] = (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);
}
3.实现 rayTriangleIntersect()
这个公式课程中已经推导过了。
值得注意的是,在判断条件那里,如果用1-u-v >=0 ,会出现蓝点 ,当你打印出来蓝点坐标时,会发现其正好为最大的负值浮点数,这是因为u,v正好在三角形交界与射线交点处。所以这里我更改了判断条件。
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;
Vector3f E2 = v2 - v0;
Vector3f S = orig - v0;
Vector3f S1 = crossProduct(dir,E2);
Vector3f S2 = crossProduct(S,E1);
float temp = dotProduct(E1,S1);
if(temp == 0 || temp <0)
return false;
u = dotProduct(S1,S)/temp;
v = dotProduct(dir,S2)/temp;
tnear = dotProduct(S2,E2)/temp;
if(u >= 0 && v >= 0 && tnear >= 0 && (1 - u -v) >= -__FLT_EPSILON__)
{
return true;
}
else{
//if(u >= 0 && v >= 0 && tnear >= 0 &&(1 - u -v) < 0)
//std::cout << u << v << tnear << std::endl;
return false;
}
}
结果
如果不做特殊处理,会出现蓝点: