OpenGL 将屏幕上的二维坐标转换为三维空间中的一个点

embedded/2025/3/19 19:48:18/

本文主要介绍将屏幕上的二维坐标转换为三维空间中的一个点,该点位于 近 平面上(即 Z 坐标为 -1)。

一、步骤概述

  1. 屏幕坐标到标准化设备坐标 (NDC): 将屏幕坐标 (x, y) 转换为 NDC 坐标系。
  2. NDC 到相机空间: 使用逆投影矩阵将 NDC 坐标转换到相机空间。
  3. 相机空间到世界空间: 使用逆视图矩阵将相机空间坐标转换到世界空间。

二、详细步骤

1. 屏幕坐标到标准化设备坐标 (NDC)

首先,假设 screenX, screenY 是屏幕空间中的像素坐标,screenW, screenH 是屏幕的宽度和高度。我们可以将屏幕坐标转换为标准化设备坐标:

float ndc_x = (2.0f * screenX) / screenW - 1.0f;  // 将x坐标映射到 [-1, 1]
float ndc_y = 1.0f - (2.0f * screenY) / screenH;  // 将y坐标映射到 [-1, 1],y轴翻转
  • screenXscreenY: 屏幕空间坐标
  • screenWscreenH: 屏幕的宽度和高度
  • ndc_xndc_y: 转换后的 NDC 坐标,范围为 [-1, 1]

2. 从 NDC 到相机空间

假设 z 值为 -1,即该点在近平面上的位置。我们需要通过逆投影矩阵将 NDC 坐标转换到相机空间。

逆投影矩阵是投影矩阵的反向操作。如果我们有一个标准的投影矩阵 P,你可以用它的逆矩阵 P^-1 来将 NDC 坐标恢复到相机空间。假设 z 值为 -1,NDC 坐标为 (ndc_x, ndc_y),那么可以通过以下方式得到相机空间中的坐标:

// 2. Crop spatial coordinates
glm::vec4 clip_coords(ndc_x, ndc_y, -1.0f, 1.0f);// z = -1 => near-plane
// 3. View space coordinates
glm::mat4 P_inv = glm::inverse(projectionMatrix);// to turn clip-space to view-space
glm::vec4 view_coords = P_inv * clip_coords;

得到的 view_coords 是相机空间中的坐标,通常需要进行透视除法,即将 x, y, z 坐标通过 w 分量进行归一化:

view_coords /= view_coords.w;// convert to non-homogeneous coordinates, get real view-space coordinates

3. 从相机空间到世界空间

最后,使用逆视图矩阵将相机空间坐标转换为世界空间坐标。V_inv 是视图矩阵的逆矩阵,转换公式如下:

	glm::mat4 V_inv = glm::inverse(viewMatrix);// to turn view-space to world-spaceglm::vec3 world_coords = glm::vec3(V_inv * view_coords);

最终代码实现如下:

glm::vec3 mapTo3DXZPlane(int screenX, int screenY, int screenW, int screenH, const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) {// 1. Normalized Device Coordinates (NDC:[-1,1], bottom-left=(-1,-1), top-right=(1,1))float ndc_x = (2.0f * screenX) / screenW - 1.0f;// Screen[0,screenW] map to NDC[-1,1]float ndc_y = 1.0f - (2.0f * screenY) / screenH;// Screen[0,screenH] map to NDC[1,-1] (openGL Y is up, screen Y is down)// 2. Crop spatial coordinatesglm::vec4 clip_coords(ndc_x, ndc_y, -1.0f, 1.0f);// z = -1 => near-plane// 3. View space coordinatesglm::mat4 P_inv = glm::inverse(projectionMatrix);// to turn clip-space to view-spaceglm::vec4 view_coords = P_inv * clip_coords;view_coords /= view_coords.w;// convert to non-homogeneous coordinates, get real view-space coordinates// 4. World spatial coordinatesglm::mat4 V_inv = glm::inverse(viewMatrix);// to turn view-space to world-spaceglm::vec3 world_coords = glm::vec3(V_inv * view_coords);return world_coords;
}


http://www.ppmy.cn/embedded/173933.html

相关文章

实验篇| Nginx环境搭建-安全配置

在前面的文章里,阿祥详细介绍了在 Windows 系统中安装 Nginx 服务器的具体操作步骤,感兴趣的朋友可以参考:实验篇 | Nginx 反向代理 - 7 层代理 。完成 Nginx 的安装只是搭建 Web 服务的第一步,为了保障服务器的稳定运行以及数据安…

Python爬虫-爬取汽车之家燃油车月销量榜数据

前言 本文是该专栏的第48篇,后面会持续分享python爬虫干货知识,记得关注。 在本文中,笔者已整理18篇汽车平台相关的爬虫项目案例。对此感兴趣的同学,可以直接翻阅查看。 而本文,笔者将以汽车之家平台为例子。基于Python爬虫,实现批量爬取全部“燃油车”的月销量数据。废…

【面试中的分布式定时任务】

定时任务与分布式定时任务框架XXL-JOB详解 一、为什么需要定时任务? 定时任务在业务场景中非常常见,主要用于以下场景: 时间驱动处理: • 整点发送优惠券 • 每天更新收益 • 每天刷新标签数据和人群数据 批量处理数据&#xf…

微服务架构: SpringCloud实战案例

### 微服务架构: SpringCloud实战案例 一、什么是微服务架构 微服务架构是一种构建单个应用程序作为一组小服务的方法,这些服务都在其自己的进程中运行。每个服务都围绕业务能力构建,并通过轻量级通信机制,如HTTP资源API,与其他服…

git commit 发现pod有大文件如何处理

1、 取消提交 Pods(如果已经提交但未推送) git reset --soft HEAD~12、移除 Pods 目录的 Git 跟踪 git rm -r --cached Pods这个命令不会删除本地 Pods/ 目录,只是让 Git 停止跟踪它。 3、添加 .gitignore 编辑 .gitignore 文件&#xff…

如何用AI制作PPT,轻松实现高效演示

如何用AI制作PPT,轻松实现高效演示!在今天这个快节奏的时代,我们的工作方式越来越依赖智能工具。而当涉及到演示文稿时,传统的PPT制作方式往往繁琐且耗时。很多人一提到制作PPT就头大,特别是在内容需要多次修改、调整布…

Linux的Shell编程

一、什么是Shell 1、为什么要学习Shell Linux运维工程师在进行服务器集群管理时,需要编写Shell程序来进行服务器管理。 对于JavaEE和Python程序员来说,工作的需要。Boss会要求你编写一些Shell脚本进行程序或者是服务器的维护,比如编写一个…

微信小程序面试内容整理-常用组件

在微信小程序中,常用组件是开发小程序时必不可少的 UI 元素,它们负责页面的显示和用户交互。微信小程序提供了丰富的内置组件,可以帮助开发者快速构建各种常见功能。 1. 视图容器组件 这些组件用于布局和容器的创建,帮助组织页面的结构和元素。 ● <view>