opengl编程 : 利用鼠标的位置跟踪一条在世界坐标系中的射线
如何用鼠标与三维世界的物体交互呢?
想了一种方法:将鼠标在二维屏幕的位置转化为三维世界坐标系的位置,记该位置为pm(mouse position)。我们在窗口中看到的内容都是基于观察坐标系的,
鼠标的位置可以看作是观察坐标系中,投影可见体的前平面中的一个位置,如何找到这样的一个位置呢?
可以肯定,pm·.z的值就是近平面的值,这点是没有疑问的,因为pm·就在近平面上。
我们假定投影平面和窗口有相同的宽高比,这些不会有失真出现。
接下来找pm·.x和pm·.y
1.将屏幕 0 - window_height-1变换到 1 到 -1
将屏幕 0 - window_width-1变换到 -1 到 1
2.找到投影平面的宽度,和投影平面的高度,可以这样计算 h = tan(Fov)*near , w = ar*h; (ar为宽高比,一般是事先定义好的,Fov为观察角度)
1 到 -1变化为 h 到 -h
-1到 1 变化 为-w 到 w
float scale_h = tanf(Fov)*Near; //投影窗口高度的一半 float scale_w = ar*scale_h; Vector3f<GLfloat> aim = Vector3f<GLfloat>(scale_w*(static_cast<float>(m_mousePos_x) / static_cast<float>(m_windowWidth)*2.f - 1.f), scale_h*(1.f-static_cast<float>(m_mousePos_y) / static_cast<float>(m_windowHeight)*2.f), Near);
如上代码变可以找到2维鼠标在3维投影平面的位置pm`
接下来要将pm`由观察坐标系变化到世界坐标系,通过乘以观察矩阵的逆就ok了,接下来贴出观察矩阵的逆的计算过程
void SetView(const Vector3f<T> & eye, const Vector3f<T> & z_target, const Vector3f<T> & up, Mat4<T>& ViewTranspose) { Vector3f<T> N = z_target; N.Normalize(); Vector3f<T> U = up; U.Normalize(); U = U.Cross(z_target); Vector3f<T> V = N.Cross(U); /*以下四行是坐标系旋转矩阵,将物体先进行坐标系平移,再进行坐标系旋转*/ data[0][0] = U._Vector3f.x; data[0][1] = U._Vector3f.y; data[0][2] = U._Vector3f.z; data[0][3] = 0.0f; data[1][0] = V._Vector3f.x; data[1][1] = V._Vector3f.y; data[1][2] = V._Vector3f.z; data[1][3] = 0.0f; data[2][0] = N._Vector3f.x; data[2][1] = N._Vector3f.y; data[2][2] = N._Vector3f.z; data[2][3] = 0.0f; data[3][0] = 0.0f; data[3][1] = 0.0f; data[3][2] = 0.0f; data[3][3] = 1.0f; Mat4<T> trans; trans.SetTranlate(Vector3f<T>( -eye._Vector3f.x, -eye._Vector3f.y, -eye._Vector3f.z));//坐标系平移矩阵 Mat4<T> transTranspose; transTranspose.SetTranlate(Vector3f<T>(eye._Vector3f.x, eye._Vector3f.y, eye._Vector3f.z));//坐标系平移矩阵的逆 Mat4<T> vi = *this; vi.transpose();//生成坐标系旋转矩阵的逆 ViewTranspose = transTranspose*vi; //观察矩阵的逆 view-1 = (view)-1 = (trans*(*this))-1 = (*this)-1*(trans)-1 *this = *this*trans;//观察矩阵 }
将pm`应用观察矩阵的逆就可以得到鼠标在世界坐标系中的坐标了。
眼睛在世界坐标中的位置已经是知道的了,那么眼睛和鼠标的位置一起就可以构成一条射线,应用这条射线与世界中的物体求交,这样就可以方便交互了.
类似上图的效果,移动鼠标可以实时地显示在哪个方格上。