【Unity】屏幕空间位置变换到世界空间位置的方法
屏幕空間像素的位置,是一個(gè)二維的浮點(diǎn)數(shù),而世界空間的位置,則是三維的浮點(diǎn)數(shù)。實(shí)現(xiàn)的基本思路很簡(jiǎn)單,是世界空間位置變換到屏幕空間位置的逆過(guò)程,只是稍微有些區(qū)別。如果對(duì)圖形渲染管線中的坐標(biāo)變換沒(méi)有弄清楚,或者習(xí)慣了Unity中直接調(diào)用封裝好的函數(shù),確實(shí)有些麻煩。
簡(jiǎn)單的說(shuō),世界空間位置變換到屏幕空間位置的步驟是這樣的:
第一步,世界空間位置變換到裁剪空間
float4 projectionPos=mul(UNITY_MATRIX_VP, float4(pos, 1.0));
這里也可以分為兩小步,世界空間變換到觀察空間,觀察空間變換到投影空間,也就是裁剪空間
float4 viewPos=mul(UNITY_MATRIX_V, float4(worldPos, 1.0));
float4 projectionPos=mul(UNITY_MATRIX_P, viewPos);
第二步,裁剪空間變換到屏幕空間位置
float4 projectionPos——>float2 screenPos
這里也可以分為兩小步,透視除法和屏幕映射
透視除法,實(shí)際是將視椎體壓平成為一個(gè)立方體。
projectionPos.xyz/projectionPos.w;
屏幕映射
[-1,1]——>[0,1]——>屏幕的像素位置
如果我們從屏幕空間位置反推世界空間位置的話,需要知道裁剪空間或觀察空間的位置,然后直接乘逆矩陣變換到世界空間即可。
但是如果要得到裁剪空間的位置,我們?nèi)鄙賥的信息,只有屏幕空間的位置xy,線性深度z(unity從深度貼圖的直接取出的深度為非線性的)。
因此,我們需要通過(guò)別的方式。根據(jù)攝像機(jī)的參數(shù)設(shè)置來(lái)計(jì)算得到觀察空間的像素位置。
1.計(jì)算觀察空間的Z分量
深度圖采樣,然后線性0-1,這時(shí)候得到的值是屏幕空間的線性深度Z。
觀察空間的Z計(jì)算即,觀察空間的近裁減屏幕的位置+近裁剪平面與遠(yuǎn)裁剪平面之間的距離*線性深度。
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.計(jì)算觀察空間Z為camPosZ處視椎體切面的高度和寬度
float height = 2 * camPosZ / unity_CameraProjection._m11; float width = _ScreenParams.x / _ScreenParams.y * height;
unity_CameraProjection是攝像機(jī)的投影矩陣,具體的內(nèi)容可以看Unity的API文檔,unity_CameraProjection._m11的內(nèi)容是:
unity_CameraProjection._m11= 2.0F * near / (top - bottom);
這里的near就是計(jì)算得到的camPosZ,top-bottom即height。
知道高度和屏幕寬高的比例后,就可以計(jì)算寬度
// x = width // y = height // z = 1 + 1.0/width // w = 1 + 1.0/height float4 _ScreenParams;
3.根據(jù)高度和寬度,以及屏幕空間位置UV,得到觀察空間的XY坐標(biāo)
float camPosX = width * uv.x - width / 2; float camPosY = height * uv.y - height / 2;
這里是一個(gè)平移的操作,在屏幕空間,原點(diǎn)位于左下角。但是在觀察空間的視椎體切面上,原點(diǎn)位于屏幕的中心。所以原來(lái)位于屏幕坐標(biāo)系的坐標(biāo)(x,y),在平面中的坐標(biāo)為(x-0.5,y-0.5)。
4.在熟悉了原理之后,以上步驟可以簡(jiǎn)單用以下的矩陣運(yùn)算實(shí)現(xiàn):
float zdepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv.xy); float4 clipPos = float4(i.uv.xy, depth, 1.0); clipPos.xyz = 2.0f * clipPos.xyz - 1.0f; float4 camPos = mul(unity_CameraInvProjection, clipPos); camPos.xyz /= camPos.w; camPos.z *= -1;
5.最后,矩陣乘法變換觀察空間到世界空間
float3 worldPos=mul(unity_CameraToWorld, camPos).xyz;
總結(jié)
以上是生活随笔為你收集整理的【Unity】屏幕空间位置变换到世界空间位置的方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Kevin专栏---自定义安装对话框的界
- 下一篇: 服务器上安装VMWare ESXi6.0