當前位置:編程學習大全網 - 網絡軟體 - OpenGLES 透視變換與屏幕UV坐標

OpenGLES 透視變換與屏幕UV坐標

壹、從需求說起

本人在做3D貼紙的時候,遇到這樣的壹個需求,在3D貼紙需要和圖像進行混合。做遠小近大的3D效果,需要將二維的貼紙經過透視變換繪制到屏幕上,如果要添加混合效果,則必須知道變換後的坐標,如果坐標對不上,則會導致混合後的貼紙繪制到屏幕上可能會出現錯亂、重疊的情況,因此如何計算重疊部分的準確坐標是實現混合的關鍵。為此,重新拾起已經被遺忘了的數學知識,將透視變換過程重新推導壹遍,以便更好地理解透視變換以及如何轉換到屏幕的空間坐標的。

二、透視變換推導

1、透視投影公式

下圖給出了壹個空間點(x, y, z)到壹般的投影參考點(xv, yv, zv)的投影路徑。該投影線與觀察平面交於坐標位置(xp, yp, zvp), 其中zvp是觀察平面上選擇的位於z軸上的點。

由此我們可以計算得到坐標位置的參數方程如下:

當投影參考點在Z軸上時,xv = yv = 0,此時有:

因此,我們可以建立壹個變換矩陣將壹個空間位置轉為齊次坐標位置,使得矩陣僅包含透視參數而不包含坐標值。然後觀察坐標系的透視投影變換分兩步實現。先用透視變換矩陣計算齊次坐標:

Ph 是齊次點(xh, yh, zh, h) 的列矩陣表示, 而P是坐標(x, y, z, 1)的列矩陣表示,在實際當中,透視矩陣需要跟觀察矩陣(ViewMatrix)合並,然後將組合矩陣應用於場景的世界坐標描述以生成齊次坐標。

為了防止z軸除以齊次參數h後出現扭曲,我們需要通過為z變換設定矩陣元素從而對透視投影zp的坐標進行規範化。有多種方法選擇矩陣元素。下面是壹種可能形成透視投影矩陣的方法:

5、對稱的視錐體

從投影參考點到裁剪窗口中心平穿過觀察體的線就會說透視投影棱臺的中心線。棱臺中心線與觀察平面相交於坐標(xv, yv, zvp)位置,用窗口尺寸表示裁剪窗口的對角位置,可得:

整體如下圖所示:

可以求得裁剪窗口高度:

6、斜透視投影棱臺

如果透視投影觀察體中心線並不垂直於觀察平面,則得到壹個斜棱臺(oblique frustum)。

為了方便計算,將投影參考點(xv, yv, zv) = (0, 0, 0),可得到錯切變換矩陣的元素:

如果將觀察平面放在近裁剪平面處,則透視投影矩陣可以進壹步簡化。將裁剪窗口中心移到觀察平面坐標位置(0, 0)處,需要選擇的錯切參數值滿足:

當投影參考點位於觀察坐標原點切近裁剪平面與觀察平面重合時,透視投影矩陣可以簡化為:

將透視矩陣和錯切矩陣綜合,就可以得到下面的將場景坐標位置轉換成齊次正交坐標的斜透視投影矩陣。該變換的投影參考點是觀察坐標原點,而近裁剪平面是觀察平面。

7、規範化透視投影變換坐標

矩陣將觀察坐標系中的對角位置變換到透視投影齊次坐標。使用齊次參數h 除齊次坐標,可得實際的正交投影坐標。該透視投影將棱臺觀察體中所有點變換成矩形平行管道觀察體中的位置,變換過程的最後壹步是將該平行管道映射到規範化觀察體(normalized view volume)中,其實也就是設備標準化坐標系(NDC)中的坐標。

轉換過程遵循評語投影的規範化過程。從棱臺觀察體變換而來的矩形平行管道映射到對稱左手參考系的規範化立方體中。完成規範化的縮放矩陣是:

將透視矩陣與縮放矩陣綜合得到規範化矩陣:

將該規範化透視矩陣進行壹般化,可以得到以下形式:

如果透視投影觀察體壹開始就指定為對稱棱臺,則可用裁剪窗口的視場角和尺寸來表達規範化透視變換的元素。將投影參考點位於原點且觀察平面在近裁剪平面位置時,可以得到:

三、Android OpenGLES 的三維觀察函數

1、觀察變換函數

在Android中,妳可以使用Matrix.setLookAtM方法來設置觀察變換矩陣,方法原型如下:

在OpenGL中的方法跟Android中的OpenGLES 不壹樣。OpenGL建模觀察模式用下列語句來設定的:

觀察參數用GLU函數指定,該函數如下:

其中(x0, y0, z0) 跟Android中的方法setLookAtM的(eyeX, eyeY, eyeZ) 點均表示觀察參考點在世界坐標系的位置。而(xref, yref,zref) 和 (centerX, centerY, centerZ) 表示參考點的坐標,(Vx, Vy, Vz) 和 (upX, upY, upZ) 表示向上向量。默認情況下 gluLookAt的參數是 P0 = (0, 0, 0), Pref = (0,0, -1), V = (0, 1, 0);

2、對稱透視投影棱臺

OpenGL中對稱透視投影棱臺觀察體用gluPerspective表示,原型如下:

在Android的OpenGLES 中也存在類似的方法:

其中 theta 和 fovy 表示視場角,0~180度可選。aspect表示長寬比。far 和near 表示觀察參考點到遠近裁剪平面的距離。

3、通用透視投影函數

在OpenGL中,通用棱臺壹般使用glFrustum函數來實現:

當選擇 xwmin = - xwmax 且 ywmin = - ywmax 時,表示的是壹個對稱棱臺。

在Android的OpenGLES中,可以使用類似的方法:

四、空間坐標投影到觀察平面上的UV坐標計算。

好了,至此,我們討論了透視投影矩陣變換的整個過程,以及OpenGL 和OpenGLES 設置投影矩陣的方法。那麽,如何求得空間坐標經過透視投影矩陣的變換後,得到屏幕的UV坐標呢?

假設在棱臺(frustum)中的壹點的坐標為(x, y, z),經過投影變換後的坐標為(x', y', z')。則我們可以得到以下計算公式:

新得到的坐標(x', y', z', w) 是經過透視投影變換後的坐標,該坐標就是前面第7小節規範化透視投影變換坐標中討論的透視投影齊次坐標。由於OpenGL的觀察平面就是近裁剪平面,因此該坐標就是坐標(x,y,z)經過透視變換後在近裁剪平面上的三維坐標。其中w記錄了深度信息。當設置為對稱棱臺投影後,矩陣的實際值就是前面計算得到的對稱棱臺規範化的透視投影矩陣:

那麽換算得到的新坐標是投影齊次坐標,那麽接下來如何轉換成屏幕UV坐標呢?我們只需要將得到的新坐標進行歸壹化為NDC坐標系,然後將其轉成UV坐標的表達形式即可。

1、轉成NDC坐標系

這裏將所有坐標均除以w值,即可得到NDC坐標,此時的w將被規整為-1 ~ 1 之間。

2、換算成屏幕UV坐標

根據前面計算得到的NDC坐標,可以換算成屏幕的UV坐標。由於NDC坐標的範圍時-1 ~ 1 的立方體,而屏幕UV坐標則是0~1的平面。如何計算? 其實很簡單,只需要從NDC坐標中縮小到原來的壹般然後平移到UV屏幕中間(0.5, 0.5),即可求得UV坐標。

五、OpenGLES 中計算透視變換到裁剪平面上的uv坐標

看到前面的壹大堆計算,估計很多人都會頭暈眼花的。其實妳完全可以不了解前面的推導過程,在OpenGL 和OpenGLES 中經過透視投影矩陣變換後的屏幕uv坐標甚至是壹件非常簡單的事情,變換過程如下:

通過將棱臺(frustum)中的坐標,與總變換mvpMatrix的乘積,得到壹個vec4的變量,該變量就是gl_Position的值。gl_Position代表著總變換後的空間位置。也就是我們所說的齊次坐標。然後將其轉成NDC坐標,重新構建壹個新的屏幕UV坐標即可。

六、最後說壹下3D貼紙需求實現思路

實現3D貼紙並將貼紙與圖像按照自定義的方式進行混合的整體過程實現如下:

1、根據人臉關鍵點坐標反推算出正臉的坐標(考慮歪頭、轉臉的情況,如果人臉關鍵點檢測得到的是三維空間點另外計算)

2、根據正臉的坐標計算出貼紙處於屏幕空間四個頂點的UV坐標

3、根據計算出的貼紙處於屏幕空間的UV坐標,反推算出貼紙實際所處平面的空間坐標(假設未做歪頭等動作時的坐標)

4、根據得到的貼紙實際空間的坐標,經過平移、旋轉後,計算出投影變換後的綜合矩陣。

5、在glsl中計算總最終的位置:

6、將得到的最終的空間坐標vPosition傳遞給Fagment Shader,將坐標轉換成屏幕的uv坐標

7、獲取圖像與貼紙重疊部分的texture進行混合

  • 上一篇:真金和純金有什麽區別
  • 下一篇:基因測序從天價降到幾十元,測序儀靠什麽做到了這壹點
  • copyright 2024編程學習大全網