Unity屏幕空间位置变换到世界空间位置的方法

本文详细介绍了如何从屏幕空间的二维浮点数位置反推出世界空间的三维位置。首先,世界空间位置经过观察空间和投影空间变换,再进行透视除法和屏幕映射。接着,通过线性深度计算观察空间的Z分量,并利用屏幕空间位置计算观察空间的XY坐标。最后,通过矩阵乘法将观察空间位置转换回世界空间。这一过程涉及深度图采样、投影参数解析及矩阵变换等关键步骤。
摘要由CSDN通过智能技术生成

屏幕空间像素的位置,是一个二维的浮点数,而世界空间的位置,则是三维的浮点数。实现的基本思路很简单,是世界空间位置变换到屏幕空间位置的逆过程,只是稍微有些区别。

简单的说,世界空间位置变换到屏幕空间位置的步骤是这样的:

世界空间变换到观察空间,观察空间变换到投影空间,然后裁剪空间

float4 viewPos=mul(UNITY_MATRIX_V, float4(worldPos, 1.0));

float4 projectionPos=mul(UNITY_MATRIX_P, viewPos);

第二步,裁剪空间变换到屏幕空间位置

float4 projectionPos——>float2 screenPos

这里也可以分为两小步,透视除法和屏幕映射

  1. 透视除法,实际是将视椎体压*成为一个立方体。projectionPos.xyz/projectionPos.w;
  2. 屏幕映射:[-1,1]——>[0,1]——>屏幕的像素位置

如果我们从屏幕空间位置反推世界空间位置的话,需要知道裁剪空间或观察空间的位置,然后直接乘逆矩阵变换到世界空间即可。

但是如果要得到裁剪空间的位置,我们缺少w的信息,只有屏幕空间的位置xy,线性深度z(unity从深度贴图的直接取出的深度为非线性的)。

1.计算观察空间的Z分量

深度图采样,然后线性0-1,这时候得到的值是屏幕空间的线性深度Z。

观察空间的Z计算即,观察空间的近裁剪屏幕的位置+近裁剪平面与远面之间的距离的线性深度。

float zdepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv.xy);
float linearDepth=Linear01Depth(depth);
float viewPosZ=_ProjectionParams.y+(_ProjectionParams.z-_ProjectionParams.y)*linearDepth;

_ProjectionParams在Unity中的format为:

float4 _ProjectionParams;
// x = 1 or -1 (-1 if projection is flipped)
// y = near plane
// z = far plane
// w = 1/far plane

2.计算观察空间Z为camPosZ处视椎体切面的高度和宽度

float height = 2 * camPosZ / unity_CameraProjection._m11;                 
float width = _ScreenParams.x / _ScreenParams.y * height;  

unity_CameraProjection是摄像机的投影矩阵,具体的内容可以看Unity的API文档,unity_CameraProjection._m11的内容是:

unity_CameraProjection._m11= 2.0F * near / (top - bottom);

这里的near就是计算得到的camPosZ,top-bottom即height。

知道高度和屏幕宽高的比例后,就可以计算宽度

// x = width
// y = height
// z = 1 + 1.0/width
// w = 1 + 1.0/height
float4 _ScreenParams;

3.根据高度和宽度,以及屏幕空间位置UV,得到观察空间的XY坐标

float camPosX = width * uv.x - width / 2;  
float camPosY = height * uv.y - height / 2; 

在屏幕空间,原点位于左下角。但是在观察空间的视椎体切面上,原点位于屏幕的中心。

最后,矩阵乘法变换观察空间到世界空间

 float3 worldPos=mul(unity_CameraToWorld, camPos).xyz;  
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值