当前位置: 首页 > news >正文

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

本文主要介绍将屏幕上的二维坐标转换为三维空间中的一个点,该点位于 近 平面上(即 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-space
	glm::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 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 /= view_coords.w;// convert to non-homogeneous coordinates, get real view-space coordinates
	// 4. World spatial coordinates
	glm::mat4 V_inv = glm::inverse(viewMatrix);// to turn view-space to world-space
	glm::vec3 world_coords = glm::vec3(V_inv * view_coords);
	
	return world_coords;
}

相关文章:

  • macOS homebrew - 切换源
  • 当前有哪些学习资料可以帮助我学习整机性能方面的知识吗
  • Android中的layout_gravity与gravity属性
  • Canary Capital 向 SEC 递交首个 SUI ETF 申请文件
  • 如何用AI轻松制作PPT,提升工作效率和演讲质量
  • 【MySQL】函数
  • Wi-Fi NAN 架构(Wi-Fi Aware Specification v4.0,第二章:2.1~2.2)
  • Vue3组合式函数(滚动监测 useScroll)
  • 配置银河麒麟V10高级服务器操作系统安装vmware tools。在您的计算机上尚未找到用于此虚拟机的 VMwareTools。安装将无法继续。
  • Java 大视界 -- 基于 Java 的大数据分布式存储系统的数据备份与恢复策略(139)
  • Qt 关键技术点总结与实践经验
  • docker登陆问题
  • Docker启动mysql容器并绑定卷,容器自动退出
  • Java JAR包的`META-INF`目录下可以放置多种配置文件的整理
  • es-将知识库中的数据转换为向量存储到es并进行相似性检索
  • 科普类——双目立体视觉与 RGBD 相机的简单对比
  • Qt按钮控件常用的API
  • qt 线程
  • Redis数据类型与场景应用解析
  • DeepSeek 3FS 与 JuiceFS:架构与特性比较
  • 赛力斯拟赴港上市:去年扭亏为盈净利59亿元,三年内实现百万销量目标
  • 国家发改委答澎湃:将指导限购城市针对长期摇号家庭和无车家庭等重点群体定向增发购车指标
  • 朝鲜证实出兵俄罗斯协助收复库尔斯克
  • 读科学发展的壮丽史诗,也读普通人的传奇
  • 在县中,我看到“走出去”的渴望与“留下来”的惯性
  • 新华时评:坚定不移办好自己的事,着力抓好“四稳”