OpenGL with QtWidgets:屏幕坐标转世界坐标

(本文是LearnOpenGL的学习笔记, 教程中文翻译地址https://learnopengl-cn.github.io/(备用地址https://learnopengl-cn.readthedocs.io/zh/latest/),写于 2022-04-04)

0.前言

在之前的图形绘制操作中,都是将模型顶点坐标转换为屏幕坐标进行显示。但在进行如人机交互时,可能需要将屏幕坐标转换到世界坐标,比如点击物体进行选中,如果采用射线拾取法,就需要将屏幕坐标系的点转到世界坐标系去。

1.知识点

先复习下顶点的坐标转换流程,图1来自LearnOpenGL,图2来自OpenGL编程指南

 

顶点坐标通过模型矩阵、视图矩阵、投影矩阵转换到裁剪空间。 转换到裁剪空间后经过GPU的裁剪处理就可以得到最终需要被渲染的物体顶点坐标了,接下来GPU会做透视除法(xyz都除以w)将顶点转换到标准化设备坐标(Normalized Device Coordinate, NDC)中,透视除法将裁剪空间中顶点的4个分量都除以w分量,就从裁剪空间转换到了NDC了,NDC是一个长宽高取值范围为[-1,1]的立方体。将顶点坐标都转换到NDC后,下一步就是屏幕映射,这个就取决于最终要渲染到的窗体分辨率。

现在要做的就是将上面的步骤反过来走一遍。

先是将屏幕坐标转为NDC坐标:

因为屏幕只有一个xy平面,所以z值任取[-1,1]一点。(两个不同z值的点连成一条线,和场景中的物体做相交检测后,可以获取到离屏幕最近的一个面的z值)

NDC到裁剪空间,加一个为1的w分量作为齐次坐标。

剩下就是裁剪坐标到世界坐标,直接用mvp转换矩阵的逆矩阵计算。 

2.代码实现

github链接(MyRayPick类):https://github.com/gongjianbo/OpenGLwithQtWidgets

float ndc_x = 2.0f * pos.x() / width() - 1.0f;
float ndc_y = 1.0f - (2.0f * pos.y() / height());
float ndc_z = 1.0f;

//view视图矩阵和projection投影矩阵取渲染时的值
QVector3D ndc_ray = QVector3D(ndc_x, ndc_y, ndc_z);
QVector4D clip_ray = QVector4D(ndc_ray, 1.0f);
QVector4D eye_ray = projection.inverted() * clip_ray;
QVector4D world_ray = view.inverted() * eye_ray;
//转笛卡尔坐标
if(world_ray.w() != 0.0f){
    world_ray /= world_ray.w();
}

3.参考

LearnOpenGL:坐标系统 - LearnOpenGL CN

书籍:《OpenGL编程指南》(原书第九版)第五章

博客:[OpenGL]射线拾取RayPicking---(1)生成射线_HELLO_IHAD的博客-CSDN博客

博客:屏幕坐标转世界坐标与射线生成 - 知乎 

博客:Clip Space、NDC、Screen Space - 简书

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值