日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

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

發(fā)布時(shí)間:2023/12/15 综合教程 25 生活家
生活随笔 收集整理的這篇文章主要介紹了 【Unity】屏幕空间位置变换到世界空间位置的方法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

屏幕空間像素的位置,是一個(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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。