我有一个使用模型,视图和投影矩阵渲染三角形网格的管道。
我正在尝试实现一个光线跟踪器,该射线跟踪器通过变换的逆投影来投影射线的原点和方向,从而挑选出我单击的对象。
当我在顶点着色器中只有一个模型(没有视图或投影)时,
Vector4f ray_origin = model.inverse() * Vector4f(xworld, yworld, 0, 1);
Vector4f ray_direction = model.inverse() * Vector4f(0, 0, -1, 0);
,一切正常。但是,我添加了一个视图和投影矩阵,然后将代码更改为
Vector4f ray_origin = model.inverse() * view.inverse() * projection.inverse() * Vector4f(xworld, yworld, 0, 1);
Vector4f ray_direction = model.inverse() * view.inverse() * projection.inverse() * Vector4f(0, 0, -1, 0);
,什么都没有了。我在做什么错了?
答案 0 :(得分:2)
如果使用透视投影,则建议在归一化设备空间中,通过近平面上的一个点和远平面上的另一个点定义射线。近平面的z坐标为-1,远平面的z坐标为1。x和y坐标必须是屏幕上[-1,1]范围内的“单击”位置。左边是(-1,-1),右上角的坐标是(1,1)。窗口或鼠标坐标可以线性映射到NDC的x和y坐标:
float x_ndc = 2.0 * mouse_x/window_width - 1.0;
flaot y_ndc = 1.0 - 2.0 * mouse_y/window_height; // flipped
Vector4f p_near_ndc = Vector4f(x_ndc, y_ndc, -1, 1); // z near = -1
Vector4f p_far_ndc = Vector4f(x_ndc, y_ndc, 1, 1); // z far = 1
归一化设备空间中的一个点可以通过逆投影矩阵,然后是逆视图矩阵,最后是逆模型矩阵转换为模型空间:
Vector4f p_near_h = model.inverse() * view.inverse() * projection.inverse() * p_near_ndc;
Vector4f p_far_h = model.inverse() * view.inverse() * projection.inverse() * p_far_ndc;
这之后的点是Homogeneous coordinates,可以由Perspective divide转换为Cartesian coordinate:
Vector3f p0 = p_near_h.head<3>() / p_near_h.w();
Vector3f p1 = p_far_h.head<3>() / p_far_h.w();
由点r
和归一化方向d
定义的模型空间中的“射线”最终为:
Vector3f r = p0;
Vector3f d = (p1 - p0).normalized()