很多人用OpenGL繪圖會(huì)遇到一個(gè)問(wèn)題即屏幕坐標(biāo)向OpenGL坐標(biāo)轉(zhuǎn)換,在網(wǎng)上流傳著如下類似的代碼:
GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); winX = (float)x;
上述代碼并不保險(xiǎn),只針對(duì)一種特殊情況才好使,即glViewport(0, 0, screenWidth, screenHeight),screenWidth、screenHeight分別是客戶區(qū)的寬和高,視口左下角坐標(biāo)恰好是(0,0),并且未經(jīng)過(guò)任何模型變換。 從屏幕坐標(biāo)向OpenGL坐標(biāo)要經(jīng)過(guò)兩步,第一步是屏幕坐標(biāo)向視景體坐標(biāo)轉(zhuǎn)換,第二步是視景體坐標(biāo)向OpenGL坐標(biāo)轉(zhuǎn)換。上述代碼中winX = (float)x; winY = viewport[3] - (float)y;反映第一步,gluUnProject是第二步。一般說(shuō)來(lái),gluUnProject的轉(zhuǎn)換是不會(huì)出問(wèn)題的。 如何進(jìn)行正確的轉(zhuǎn)換呢?首先,在glGetIntegerv之前添上模型變換的代碼,和繪圖時(shí)使用的模型變換代碼一樣,另外必須保證平移,縮放,旋轉(zhuǎn)的順序和繪圖時(shí)的一樣。其次,屏幕坐標(biāo)向視景體坐標(biāo)轉(zhuǎn)換有兩種方式(注意!在多視口情況下,活動(dòng)視應(yīng)當(dāng)最后繪制,它將作為當(dāng)前的視口,保證glGetIntegerv等取值函數(shù)能得到正確的值)。①winx = x – viewport[0]; winy = screenHeight – viewport[1] - y; viewport[0] = viewport[1] = 0;②winx = x; winy = screenHeight – y;第一種比較直觀,前兩句是將屏幕坐標(biāo)轉(zhuǎn)換為視景體內(nèi)的坐標(biāo),后兩句將視景體的左下角點(diǎn)坐標(biāo)改為(0,0),因?yàn)樵谠O(shè)置裁剪視口時(shí),使用glViewport設(shè)置視口的左下角點(diǎn)坐標(biāo)不一定是(0,0),而在視景體內(nèi)的點(diǎn)其視景體坐標(biāo)與左下角點(diǎn)是相對(duì)的,即把視景體坐標(biāo)看作是坐標(biāo)系原點(diǎn)。第二種方式比較簡(jiǎn)略,但是同樣的道理,只不過(guò)是glUnproject函數(shù)對(duì)winx和winy又做了一次轉(zhuǎn)換。 好了,現(xiàn)在給出完整的代碼,如下: GLint viewport[4]; glPushMatrix(); glGetIntegerv(GL_VIEWPORT, viewport); // 得到的是最后一個(gè)設(shè)置視口的參數(shù) glPopMatrix(); winX = x; |
|