首先上结果(不会在博客园传视频、具体流程是鼠标点击屏幕上的任意一个点、向此处投射一条射线):
实现的方法:
首先认清楚什么是一条射线、由于我们不是真的要画一条无限长度的线、那么用线段的起始和终止(当然是在世界坐标系里的起点和终点)就能代表这条射线、具体的shader可以用基本的MVPshader。
这个Ray类只是简单的用起点和终点画一条线而已,其中的 t 可以用来和别的表面求交点、所以暂时保留
具体的、我们使用GLFW做窗口系统、先给GLFW注册一个点击事件函数、响应鼠标左键的单击、并且拿到像素坐标:
(mouseX,mouseY)就是鼠标点击处的像素坐标!(左上角xy都最小,右下角xy都最大)
这里开始就比较有意思了、
首先:正着来的变换流程:
模型--》世界--》观察变换(view)--》视锥体投影--》glViewPort转像素坐标
那么反着来、就需要先把(mouseX,mouseY)这种像素坐标转换到 [-1,1]的范围内:
mouseX,mouseY在窗口左上角时为(0,0),可以代入这个公式里、发现 x = -1, y = 1,回忆 opengl NDC相关的知识、左上角确实是 (-1,1)!这个公式的正确性可以简单体会一下
关键在于 z 值的理解!z可以取 -1 或者 1、取 -1 代表我们鼠标点击的那一下是点到了【近平面】上、取 1 表示点击到了【远平面】上!
这里看图(鼠标画的确实不好看、将就一下!):
我们在屏幕上点了一下鼠标、要发射一条射线的话、需要确定起点和终点、起点一般就是我们的相机、而终点就是图上画的两个红色的 X 号、
相机和红色 X 之间的连线就是射线!我们取 z = -1 表示是近平面是那个红X、取 z = 1表示要取远平面的那个红X,其实两者和眼睛的连线是共线的,想取别的 z、只要在【-1,1】范围内、都是可以的、取远平面只是效果好点!
但取远平面能把线拉的长一点、方便观察结果!
我们现在已经完成了像素--》NDC的转换、
回顾正着变换的方程:
Position(NDC) = P*V*Position(世界);
那么(简单移项):
Positon(世界) = 逆(P*V) * Position(NDC)
所以我们有:
这样就能把屏幕转世界了
最后、new一个Ray对象(起点是相机位置、终点是逆变换到世界系的点)、放到全局的一个容器里、每次render时遍历容器(这里使用多态去处理、I_Drawable就是个接口):
后面就可以用 Ray 去做很多别的操作了!
完整工程下载:
链接:https://pan.baidu.com/s/1GFq0DIjHJMpG_u1U2ljiiA
提取码:s2m5
标签:鼠标,opengl,--,像素,射线,点击,坐标,逆变换 From: https://www.cnblogs.com/gs590/p/16851336.html