作业要求:
1.为每个像素生成一条对应的光线;
2.用Moller-Trumbore 算法来判断光线与三角形是否相交;
第一步:
调用 Render(scene) 函数。在遍历所有像素的循环里,生成对应的光线。
为每个像素生成对应一条对应光线,我这里使用的自己推导的算法,常规的通用方法见Ray-Tracing: Generating Camera Rays
void Renderer::Render(const Scene& scene)//scene代指屏幕,其上有像素点。接下来的推导将其看成投影变换中的近平面会便于理解。
{
std::vector<Vector3f> framebuffer(scene.width * scene.height);
float scale = std::tan(deg2rad(scene.fov * 0.5f));//相机一半视场角的tan值
float imageAspectRatio = scene.width / (float)scene.height;//宽高比
Vector3f eye_pos(0);//原点即相机位置
int m = 0;
for (int j = 0; j < scene.height; ++j)
{
for (int i = 0; i < scene.width; ++i)
{
float x;
float y;
float height = scale * 1.0;//“1.0”即为zNear
float width = height * imageAspectRatio;//先将scene放缩
//scene默认左上角为原点,屏幕空间坐标默认左下角为原点
y = -(j - scene.height / 2 + 0.5);//所以y轴方向相反
x = i - scene.width / 2 + 0.5;//x轴方向不变
y *= height/(scene.height*1.0);
x *= width/(scene.width*1.0);//将x,y放缩
Vector3f dir = Vector3f(x, y, -1);//“-1”意味着scene在z轴方向离相机距离为1
dir = normalize(dir);//方向向量模应为1
framebuffer[m++] = castRay(eye_pos, dir, scene, 0);
}
UpdateProgress(j / (float)scene.height);
}
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);
}
第二步:
利用Moller-Trumbore 算法来判断光线与三角形是否相交。
根本思想其实就是先求出光线与三角形所在的平面的交点,再判断该点是否在三角形内。
这里直接利用闫老师给出的公式
bool rayTriangleIntersect(const Vector3f& v0, const Vector3f& v1, const Vector3f& v2, const Vector3f& orig,
const Vector3f& dir, float& tnear, float& u, float& v)
{
Vector3f E1 = v1-v0, E2 = v2-v0, S = orig-v0;
Vector3f 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;
}
最后得到的结果在build文件中查看