如何在给定视图空间深度值和 ndc xy 的情况下恢复视图空间位置

2023-12-08

我正在编写一个延迟着色器,并试图将我的 gbuffer 包装得更紧密。但是,我似乎无法正确计算给定视图空间深度的视图位置

// depth -> (gl_ModelViewMatrix * vec4(pos.xyz, 1)).z; where pos is the model space position
// fov -> field of view in radians (0.62831855, 0.47123888)
// p -> ndc position, x, y [-1, 1]
vec3 getPosition(float depth, vec2 fov, vec2 p)
{
    vec3 pos;
    pos.x = -depth * tan( HALF_PI - fov.x/2.0 ) * (p.x);
    pos.y = -depth * tan( HALF_PI - fov.y/2.0 ) * (p.y);
    pos.z = depth;
    return pos;
}

计算出的位置是错误的。我知道这一点是因为我仍在 gbuffer 中存储正确的位置并使用它进行测试。


透视投影中恢复视图空间位置的3种解决方案

投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。它从视图(眼睛)空间变换到剪辑空间,并且剪辑空间中的坐标除以w剪辑坐标的组成部分。 NDC 的范围为 (-1,-1,-1) 到 (1,1,1)。

在透视投影中,投影矩阵描述了从针孔相机看到的世界上的 3D 点到视口的 2D 点的映射。
相机平截头体(截棱锥体)中的眼睛空间坐标被映射到立方体(标准化设备坐标)。

透视投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0               0
0              2*n/(t-b)      0               0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)    0

它跟随:

aspect = w / h
tanFov = tan( fov_y * 0.5 );

prjMat[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect)
prjMat[1][1] = 2*n/(t-b) = 1.0 / tanFov

在透视投影中,Z 分量由以下公式计算有理函数:

z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye

深度 (gl_FragCoord.z and gl_FragDepth) 计算如下:

z_ndc = clip_space_pos.z / clip_space_pos.w;
depth = (((farZ-nearZ) * z_ndc) + nearZ + farZ) / 2.0;

1. 视野和纵横比

由于投影矩阵是由视场和纵横比定义的,因此可以利用视场和纵横比来恢复视口位置。假设它是对称透视投影并且标准化设备坐标,则深度以及近平面和远平面是已知的。

恢复视图空间中的 Z 距离:

z_ndc = 2.0 * depth - 1.0;
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));

通过 XY 标准化设备坐标恢复视图空间位置:

ndc_x, ndc_y = xy normalized device coordinates in range from (-1, -1) to (1, 1):

viewPos.x = z_eye * ndc_x * aspect * tanFov;
viewPos.y = z_eye * ndc_y * tanFov;
viewPos.z = -z_eye; 

2. 投影矩阵

由视场和纵横比定义的投影参数存储在投影矩阵中。因此,可以通过对称透视投影的投影矩阵的值来恢复视口位置。

注意投影矩阵、视场和纵横比之间的关系:

prjMat[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect);
prjMat[1][1] = 2*n/(t-b) = 1.0 / tanFov;

prjMat[2][2] = -(f+n)/(f-n)
prjMat[3][2] = -2*f*n/(f-n)

恢复视图空间中的 Z 距离:

A     = prj_mat[2][2];
B     = prj_mat[3][2];
z_ndc = 2.0 * depth - 1.0;
z_eye = B / (A + z_ndc);

通过 XY 标准化设备坐标恢复视图空间位置:

viewPos.x = z_eye * ndc_x / prjMat[0][0];
viewPos.y = z_eye * ndc_y / prjMat[1][1];
viewPos.z = -z_eye; 

3. 逆投影矩阵

当然,可以通过逆投影矩阵来恢复视口位置。

mat4 inversePrjMat = inverse( prjMat );
vec4 viewPosH      = inversePrjMat * vec3( ndc_x, ndc_y, 2.0 * depth - 1.0, 1.0 )
vec3 viewPos       = viewPos.xyz / viewPos.w;


另请参阅以下问题的答案:

  • 如何在现代 OpenGL 中使用片段着色器中的 gl_FragCoord.z 线性渲染深度?
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在给定视图空间深度值和 ndc xy 的情况下恢复视图空间位置 的相关文章

随机推荐

  • 元素的最大尺寸

    我正在使用高度为的画布元素600 to 1000像素和宽度为几十或几十万像素 然而 在一定数量的像素 显然未知 之后 画布不再显示我用 JS 绘制的形状 有谁知道有没有限制 在 Chrome 12 和 Firefox 4 中进行了测试 更新
  • 如何将字符串或类传递给方法来创建实例

    我将使用以下方法 它通过向其传递类型来工作 例如obj addComponent MyClass 这很好用 我尝试修改type参数通过添加 string到它 但它现在给我错误说 不能将 new 与类型缺少调用或构造签名的表达式一起使用 无论
  • 您指定的指纹已被此项目或其他项目中的 Android OAuth2 客户端 ID 使用

    我注意到 android studio 中的 gradle 视图签名报告中显示的 SHA1 编号与我最初的不同 我想可能是一年前换电脑造成的 我的游戏应用程序仍然能够访问排行榜和成就 当我看到我的 Google API 仪表板时 我注意到
  • 有什么方法可以在悬停时仅对图像的一部分进行着色吗?

    我喜欢用 HTML CSS 甚至 jQuery 编写简单的图像绘制代码 假设我有一个原始图像 我想让它着色 但仅限于悬停的部分 或光标所在的 10x10px 正方形或圆形图像 我应用了一些滤镜来使用 CSS 使其灰度化 但我不知道如何仅对悬
  • 从其他对象属性(动态)计算的 Javascript 对象属性

    我正在尝试创建一个 javascript 对象来计算其上设置的属性的各种值 我已经编译了这个简单的例子来说明我想要实现的目标 JSFIDDLE var obj obj a 2 obj b 5 obj avg obj a obj b 2 ob
  • 如何在 uint64_t 中移位 >= 32 位?

    下面的代码会触发一个gcc警告 海湾合作委员会4 2 1 include
  • Java 非法类修饰符异常代码 0x209

    我对遗留代码库有疑问 我想开始用 1 6 类格式编译它 但是有一个问题只有当我尝试运行编译后的代码时才会显现出来 我得到以下异常 java lang ClassFormatError 类 FooBar 0x209 中存在非法类修饰符 谷歌搜
  • Android:用固定长宽比的相机拍摄图像后裁剪图像

    我试图在拍摄后裁剪图像 我的代码如下 private void doTakePhotoAction Intent intent new Intent MediaStore ACTION IMAGE CAPTURE intent putExt
  • 从 HttpServletRequest 获取 AsyncContext

    我正在使用Spring的OncePerRequestFilter压倒性的shouldNotFilterAsyncDispatch方法返回 false 这样它就可以处理异步请求 在过滤器中 我尝试执行以下操作 if isAsyncDispat
  • 如何使用 R 对于大型数据集有效地检查点是否在多边形中?

    我是 R 新手 对于我当前的项目 我必须绘制与特定事件相关的热图 此类事件大约有 200 万个观测值 每个观测值都有一个长坐标和纬度坐标 另外 我将地图数据转换为数据框 该数据框包含71个区 每个区都定义有一组坐标 我需要决定事件的哪个观察
  • 是否可以在 Web API 中使用 ASP.NET 应用程序缓存?

    例如 在 ASP NET 页面中 您可以执行类似的操作 Cache Add 并通过访问它Cache key 在这种情况下 缓存是System Web Caching Cache object 无论如何 是否可以在 Web API 控制器中执
  • ASP.NET Web 应用程序构建输出 - 如何包含所有部署文件?

    当我建立我的ASP NETWeb 应用程序我得到一个 dll 文件 其中包含网站的代码 这很棒 但是该网站还需要所有 aspx 文件和朋友 并且这些文件需要放置在正确的目录结构中 我怎样才能将这一切作为每次构建的结果都放在一个目录中 尝试从
  • 多行上的元素右对齐

    我想对齐lidiv 右侧的元素 我可以通过浮动来做到这一点ul向右 然而 我有很多li元素 因此根据 div 的宽度 其中一些会移动到下一行 问题是li元素左对齐 将浮动放在右侧li可以解决这个问题 但它会颠倒菜单项的顺序 请看下文 row
  • 如何在spring session项目中修改或自定义sessionId?

    我的项目使用Spring Boot和Spring Session 现在我想在redis中的会话数据持久化之前修改或自定义sessionId 我该怎么办 谢谢 也许您需要阅读文档 Spring Session 与 Spring Boot 配合
  • 配置 JBoss 使用 JNDI 时出现问题

    我正在尝试在 JBoss 上运行的应用程序中使用 JNDI 将连接绑定到数据库 我做了以下事情 我创建了数据源文件oracle ds xml用相关的 xml 元素填充它
  • 网站图标未显示,我的图标不好

    如果我从另一个网站复制一个图标并进行测试 我就可以使用图标 但我自己的在 IE8 Chrome 中不起作用 我的图标是由 Visual Studio 创建的 32x32 24 位图标 我似乎总是无法使图标正常工作 我应该使用什么 我以为我可
  • 在 vb.net 中声明/打开 Excel 文件

    我已经尝试在 vb net 中声明或打开 Excel 工作表一段时间了 我已经读过vb net 中的 Excel 文件和其他链接 但它不起作用 我添加了 Microsoft Excel 12 0 对象库 包括我 Imports Micros
  • iTextSharp 和 Xamarin

    我正在尝试在 Xamarin 应用程序中使用 iTextSharp dll 但无法编译 因为我收到了此错误 Error Exception while loading assemblies System IO FileNotFoundExc
  • ControlTemplate Storyboard颜色动画问题

    我对彩色动画有疑问 这是我的来源
  • 如何在给定视图空间深度值和 ndc xy 的情况下恢复视图空间位置

    我正在编写一个延迟着色器 并试图将我的 gbuffer 包装得更紧密 但是 我似乎无法正确计算给定视图空间深度的视图位置 depth gt gl ModelViewMatrix vec4 pos xyz 1 z where pos is t