3D UI場景中,把XY平面的尺寸映射爲屏幕像素的數學模型推導

概述及目錄(版權全部,請勿轉載,歡迎讀者提出錯誤)

  以前用kanzi的3D UI引擎和cocos-2d的時候都有遇到過這個問題,就如何把3D場景中的XY平面的尺寸映射爲與屏幕像素一一對應的,即XY平面上的一個單位對應平面上的一個像素。這個在3D UI開發過程當中彷佛並不是必須,或者說不多有人這樣用,由於在遊戲場景中,UI能夠處於場景的任何位置,並不侷限於XY平面內。編程

  本次的分享總結所述的3D UI應用場景並不是在遊戲中,而是注重在GUI應用上(相似QT等),即便用3D繪圖技術實現的一套相似2D UI同樣效果的引擎,因爲UI系統是3D的,故能實現3D的動畫效果。把3D場景中的XY平面的尺寸映射爲平面像素一一對應的優勢,是能保持並延續咱們在2D開發時候的習慣,方便精準地控制UI控件在整個屏幕上的位置佈局。函數

  本文的重點是「3D UI場景中把XY平面的尺寸映射爲屏幕像素」,所以須要您有以下的基本知識:佈局

  一、基本3D數理知識;動畫

  二、Opengl相關知識;spa

  三、對3D計算機圖形學中「攝像機」概念有所瞭解;code

  本文包括以下內容:orm

glm 3D數學庫簡介

  什麼是3D數學庫?blog

  所謂3D數學庫,簡單地說就是把在3D計算機編程中經常使用到的數據類型、數學函數、3D處理公式及方法等統一集中起來,方便咱們在處理3D場景時使用。教程

  glm 3D數學庫是Opengl官網推薦使用的,包含了幾乎全部咱們在處理3D場景是須要的數學函數。遊戲

  glm的使用也很是簡單,glm提供的源碼所有都是頭文件,咱們只需把glm的頭文件引用到本身須要使用的工程中便可。

  以下實例代碼中,咱們經過glm建立了一個4x4的矩陣,並對該矩陣進行了平移變換(詳細的glm使用介紹,你們能夠參考glm官網的教程或文檔)。

//示例代碼 1.0 http://www.cnblogs.com/feng-sc/
#include <glm/glm.hpp> //注意: glm的工程路徑須要本身配置 #include <glm/gtc/matrix_transform.hpp> int main() { glm::mat4 matrix(1.0); matrix = glm::translate(matrix, glm::vec3(100.0f, 0.0f, 0.0f)); return 0; }

   做爲簡介,glm的介紹就到此結束。

透視視錐體介紹

  所謂的透視不是你所想的眼睛能看穿牆的意思,別多想了!簡單點,透視就是表示物體近大遠小的效果的意思。

  以下圖所示,透視視錐體梯體幾何圖形,它相似於人的眼睛所能看到的範圍,在梯體以外的物體將不可見。

  在3D數學裏,用什麼表示這個透視視錐體呢?沒錯,是矩陣!

  使用glm函數庫能簡單地生成透視視錐體的矩陣,以下實例代碼:

// 示例代碼1.0: www.cnblogs.com/feng-sc/
// fovyInRadians : 弧度表示下圖中FOV
// aspect : 視錐體寬與高的比例,能夠理解爲繪圖區域的寬高比
// zNear : 近平面離攝像機的距離
// zFar :遠平面離攝像機的距離
glm::mat4 projection = glm::perspective(fovyInRadians, aspect, zNear, zFar); 

(透視視錐體)

  上訴實例代碼中,projection又被成爲透視矩陣,全部3D世界裏的物體,通過與projection矩陣相乘後,最終獲得的物體將呈現以下兩種特色:

  一、遠小近大的效果;

  二、處於透視視錐外的物體將被忽略;

使用glm函數庫生成攝像機矩陣

  本段咱們先以一段代碼起頭,以下:

// 示例代碼1.0: www.cnblogs.com/feng-sc/
glm::mat4 view = glm::lookAt(m_position, m_target, m_up);

  lookAt函數獲得的結果是一個視圖矩陣。有人把視圖矩陣稱爲攝像機,也有人把視圖矩陣和透視投影矩陣合在一塊兒稱爲攝像機,我喜歡後者。

  結合投影矩陣,咱們總結一下,攝像機分別由以下參數決定:

  一、透視投影矩陣projection決定了攝像機的視野範圍,包括視覺張角FOV、近平面、遠平面;

  二、視圖矩陣決定了攝像機的位置、觀察方向;

  最後投影矩陣與視圖矩陣將共同決定咱們整個場景的顯示效果。

// 示例代碼1.0 www.cnblogs.com/feng-sc/
glm::mat4 projection = glm::perspective(fovyInRadians, aspect, zNear, zFar);
glm::mat4 view = glm::lookAt(m_position, m_target, m_up);
glm::mat4 vpMat = projection * view

 

 分析如何調整攝像機和透視視錐體,使的3D場景中的XY平面的尺寸與屏幕像素對應;

  OK,終於來到了本文標題討論的問題點,3D UI場景中把XY平面的尺寸映射爲屏幕像素。

  其實到如今爲止,咱們問題的解決方案也清晰了,如何實現「3D UI場景中把XY平面的尺寸映射爲屏幕像素」 呢?是的,就是調整攝像機的位置、遠/近平面、攝像機視角,使XY平面的單位尺寸剛好與平面像素的單位對應便可。

  那麼如今剩下的問題是:如何調整攝像機,使得咱們的XY平面剛好與平面像素對應呢?

  在咱們繼續以前,咱們先來了解一個概念:齊次座標。

  百度百科解釋說:齊次座標就是將一個本來是n維的向量用一個n+1維向量來表示。例如,二維點(x,y)的齊次座標表示爲(hx,hy,h)(h能夠是任意值)。

  咱們能夠理解爲,任何三維的點(hx,hy,h),在二維平面上的投影點均爲(x,y)。

(透視視錐體側面平面圖)

 

  上圖爲透視視錐體側面平面圖,其中GI爲透視視錐體的近平面,BF爲遠平面,LS和TZ分別爲視錐體的兩個不一樣位置的截面。

  從2D平截視錐體看,透視視錐體GBFI範圍內的三維物體最後均被投影到GI平面上。由齊次座標概念可知,點B、U、M在GI平面上的投影均爲點M,同理點F、W、P在GI平面上的投影均爲點I。

  咱們:

   假設TZ平面爲XY平面且與屏幕像素對應,屏幕高度像素爲h,角∠BAF = FOV (FOV爲攝像機張角)

   故,UW = h,UV = h/2;

   故,

       

    即,由屏幕寬度和攝像機張角,要使XY平面與屏幕像素對應,咱們求得攝像機位置點距離XY屏幕距離長度爲AV。

  下面的代碼設置爲屏幕左上角爲原點是,攝像機的設置。

// 示例代碼1.0 www.cnblogs.com/feng-sc/
float fov = 60;
glm::perspective(glm::radians<float>(fov), (float)width / (float)height, 0.1f, 10000.0f);
float z = height / (2 * tan(((float)(fov / 2.0)* glm::pi<float>()) / 180.0));
glm::vec3 positon((float)width / 2.0f, (float)height / 2.0f, -z);
glm::vec3 target((float)width / 2.0f, (float)height / 2.0f, 0.0f);
glm::vec3 up(0.0f, -1.0f, 0.0f);
m_view = glm::lookAt(positon target, up);
相關文章
相關標籤/搜索