目标:将屏幕上(不是屏幕空间!)的2D像素坐标映射为3D世界的一条线
需要将像素从光栅空间->NDC空间->屏幕空间->相机空间->世界空间
拿到像素的左上角顶点坐标,加0.5得到像素中心坐标, 之后将x,y分别除以width,height,映射到【0,1】区间内
即:(x + 0.5f) / width; (y + 0.5f) / height;
即:x = 2 * x - 1; y = 1 - 2 * y;
注:在光栅空间中,y轴向下;而屏幕空间的y轴向上,因此需要用1-…
这里需要引入相机的物理属性 (宽高比和视场角) ,将2D坐标拉伸为3D的相机坐标
屏幕空间的【-1,1】区间是一个正方形(因为x,y都处于这个区间中),但是屏幕大多是长方形的(如1920x1080),因此需要对x坐标进行拉伸;同时还要根据xy原始的大小对其进行放大
即: x = x * radio * sacle; y = y * scale;
将上一步得到的坐标(x,y,-1)乘以 世界到相机的旋转矩阵的逆矩阵,即可求得在世界空间的坐标
但是因为这里的相机位于原点处,且方向看向-z,因此不需要做任何处理
之后调用castRay()函数就可得到这一像素在世界空间发出的光线
1for (int j = 0; j < scene.height; ++j)
2 {
3 for (int i = 0; i < scene.width; ++i)
4 {
5 // generate primary ray direction
6 float x = i;
7 float y = j;
8 // TODO: Find the x and y positions of the current pixel to get the direction
9 // vector that passes through it.
10 // Also, don't forget to multiply both of them with the variable *scale*, and
11 // x (horizontal) variable with the *imageAspectRatio*
12
13 // Rasterized Space -> NDC Space
14 float x_ndc = (x + 0.5f) / scene.width;
15 float y_ndc = (y + 0.5f) / scene.height;
16
17 // NDC Space -> Screen Space
18 float x_screen = 2 * x_ndc - 1;
19 float y_screen = 1 - y_ndc * 2;
20
21 // Screen Space -> Camera Space
22 float x_camera = x_screen * imageAspectRatio * scale;
23 float y_camera = y_screen * scale;
24
25 // camera Space -> World Space
26 Vector3f dir = Vector3f(x_camera, y_camera, -1); // Don't forget to normalize this direction!
27 dir = normalize(dir);
28 framebuffer[m++] = castRay(eye_pos, dir, scene, 0);
29 }
- 射线方程:P = O + t*D
- 三角形内部点:P = V_0 + u*E_1 + vE*_2
之后可以解得t,u,v的值,u,v是 三角形内部的重心坐标 ,t(tNear)是光线撞上三角形所用的最短的时间
判断条件:(u,v< 0)或(u + v >1)则交点位于三角形之外,t<0则说明三角形在光线后面,这三种情况都意味着光线未能与三角形相交
1bool rayTriangleIntersect(const Vector3f& v0, const Vector3f& v1, const Vector3f& v2, const Vector3f& orig,
2const Vector3f& dir, float& tnear, float& u, float& v)
3{
4 // TODO: Implement this function that tests whether the triangle
5 // that's specified bt v0, v1 and v2 intersects with the ray (whose
6 // origin is *orig* and direction is *dir*)
7 // Also don't forget to update tnear, u and v.
8 Vector3f e1 = v1 - v0, e2 = v2 - v0, s = orig - v0;
9 Vector3f s1 = crossProduct(dir, e2);
10
11 float S1dotE1 = dotProduct(s1, e1);
12 if (std::abs(S1dotE1) < 0.0001f) return false;
13 float invS1dotE1 = 1 / S1dotE1;
14
15 u = dotProduct(s1, s) * invS1dotE1;
16 if (u < 0.0f || u > 1.0f) return false;
17
18 Vector3f s2 = crossProduct(s, e1);
19 v = dotProduct(s2, dir) * invS1dotE1;
20 if (v < 0.0f || v > 1.0f) return false;
21
22 tnear = dotProduct(s2, e2) * invS1dotE1;
23 if (tnear >= .0f) return true;
24
25 return false;
26}
原文:5

