青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

投影與相機空間

http://sighingnow.github.io/graphics/projection_and_camera.html

投影與相機空間

 Published On August 14, 2015

計算機屏幕是2維的,OpenGL渲染的3D場景必須以2D形式的圖像投影到屏幕上。

透視投影

透視投影能較好的使二維投影顯示立體感,因為人眼觀看物體符合透視原理。首先,將所有頂點從眼坐標(照相機坐標)轉換到裁剪坐標系下。然后,這些裁剪坐標通過透視除法,即除以裁剪坐標中w分量,轉換到歸一化設備坐標系(NDC)。在透視投影中,在眼坐標下截頭椎體(a truncated pyramid frustum)內的3D點被映射到NDC下一個立方體中;x坐標從[l,r]映射到[-1,1],y坐標從[b,t]映射到[-1,1],z坐標從[n,f]映射到[-1,1]。

世界坐標和眼坐標系使用右手坐標系,而NDC使用左手坐標系。這就是說,眼坐標系下,在原點處的照相機朝著-Z軸看去,但是在NDC中它朝著+Z軸看去。如下圖所示:

相機坐標系與設備坐標系

由幾何關系,可以推導出對稱視錐(常見的都是對稱視錐,也符合人眼看物理的規律)的投影變換矩陣如下:

透視投影變換矩陣

其中,n為眼睛與近平面的距離(near),f為眼睛與遠平面的距離(far),r為設備的寬度,t為設備的高度。

如何定義視界角度為alpha,定義設備的寬高比為 ar = width/height, 那么,投影矩陣也可以表述為:

透視投影變換矩陣

對應的代碼實現:

PipeLine & PipeLine::PerspectiveProject(float ar, float alpha, float znear, float zfar) {     mat4x4f PrespectiveM = {         1.0f/(tanf(alpha/2.0)*ar), 0.0f                  , 0.0f                      , 0.0f,         0.0f                     , 1.0f/(tanf(alpha/2.0)), 0.0f                      , 0.0f,         0.0f                     , 0.0f                  , (-znear-zfar)/(znear-zfar), (2*zfar*znear)/(znear-zfar),         0.0f                     , 0.0f                  , 1.0f                      , 0.0f     };     mulmatf(PrespectiveM, M, M, 4, 4, 4);     return *this; } 

投影變換對應的矩陣稱為投影(projection)矩陣

正交投影

構造正交投影(Orithographic Projection)的矩陣簡單很多。所有的是眼坐標下xe, ye 和ze,都被線性的映射到NDC中。我們需要做的就是講長方體視景體縮放為規范視見體,然后移動到原點。如下圖所示:

正交投影

如果視錐是對稱的話,投影矩陣為:

正交投影變換矩陣

相機空間

我們可以將相機放在三維空間的任意位置,然后將世界坐標系中的點轉換到相機坐標系中,然后投影到設備屏幕上。理論上可以生成這樣的變化矩陣,實現把一個位于3D空間的對象投影到坐落在世界坐標系任意位置的相機正前方的2D平面上。

三維相機的一個示意圖:

相機示意圖

與UVN相關的概念包括:

  • 相機位置,或者叫做視點(eyepoint): 觀察參考點 (View Reference Point)
  • 相機鏡頭方向,通過觀察平面的法向量指定: 觀察平面法向量VPN (View Plane Normal)
  • 相機頂部正朝向: VUV (View Up Vector)

相機平移變換

移動相機是非常簡單的。如果相機位于(x,y,z),那么平移變換就是(-x,-y,-y)。原因很明顯——相機在世界坐標系下用向量(x,y,z)做平移變換,所以想要相機回到原點,那么我們就需要使用此向量的相反向量進行平移。變換矩陣如下所示:

相機移動變換矩陣

相機旋轉變換

下一步是將相機轉向世界坐標系中指定的位置。我們想要找到在相機定義的新坐標系下頂點的位置。“UVN相機”是眾多指定相機方向的辦法中的一個。相機被下列的矩陣所定義:

  • N: 由相機指向它的目標的向量。在一些3D的文獻中也被稱為’look at’。這個向量對應于Z軸。
  • V: 直立時,這個向量相對于相機是豎直向上的。這個向量對應于Y軸。
  • U: 這個向量從相機指向其右側。它對應于X軸。

為了把一個位置從世界坐標系空間轉換到被UVN向量定義的相機坐標系空間,我們需要在位置和UVN向量之間進行一個點乘運算。我們可以把UVN系統看作是相機的基,從而可以方便的把一個向量在世界坐標和相機坐標進行轉換(將世界坐標變換到相機坐標)。得到的相機旋轉變換矩陣:

相機轉動變換矩陣

下來討論這個變換矩陣的推導過程。對于一個相機,我們容易知道它在三維坐標(世界坐標系)中的以下三個參數:

  • pos: 相機的位置坐標。
  • target: 相機正前方的目標點的坐標。
  • up: 相機的正上方(頭頂)的方向向量。(一般為(0.0f, 1.0f, 0.0f),與人平視屏幕時的頭頂方向一致)。

根據這三個參數,注意到相機坐標系是右手坐標系,根據向量叉積的性質,容易求出:

N = norm(target - pos) U = norm(up * N) V = norm(N * U) 

當相機在屏幕中定位時,它首先會進行朝向的確定——旋轉,然后進行位置的確定——平移。因此,當進行相機變換的時候,將世界坐標系中的坐標變換到相機坐標系中的坐標時,應該進行一個相機定位的逆定位。先做逆平移變換,再做逆旋轉變換。

關于相機變換矩陣的推導,參考了博文[推導相機變換矩陣][http://blog.csdn.net/popy007/article/details/5120158]。

相機變換對應的矩陣稱為視圖(view)矩陣,也稱為觀察矩陣

數學運算庫 glm 中包含了一個lookUp函數,可以根據postargetup三個向量來直接計算出相機變換矩陣:

glm::mat4 View = glm::lookAt(     glm::vec3(4,3,3), // Camera is at (4,3,3), in World Space     glm::vec3(0,0,0), // and looks at the origin     glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down) ); 

攝像機控制

通過相機變換矩陣,我們可以利用矩陣乘法將世界坐標系中的坐標變換到相機坐標系中。通過修改pos, target 和 up 參數,我們可以在程序中動態完成相機的控制。但是這樣仍然不能很好的用于人機交互,通常使用的第一人稱相機,通過鍵盤WASD等鍵和鼠標來控制虛擬相機更加方便,因此需要改進我們的相機控制。要想構造適合人機交互的相機類,必須明確我們需要實現的目標。第一人稱相機的目標包括:鍵盤來移動相機,是相機前后左右移動,通過鼠標來控制相機繞xy軸轉動角度,通過鼠標滾輪來實現縮放。

第一人稱相機旋轉示意圖:

第一人稱相機旋轉示意圖圖

可以將相機在空間的旋轉、移動等變換都分解到 U、V、N 方向上進行,三個為了更好地表達對攝像機的控制,實現一個Camera類,代碼實現:

// implements for class Camera Camera::Camera(vec3f pos, vec3f target, vec3f up): POS(pos), TARGET(target), UP(up) {     // initial camera.     POS = pos; TARGET = target; UP = up;     this->UpdateUVN(); }  Camera & Camera::Translate(float du, float dv, float dn) {     vec3f delta(du*U.x + dv*V.x + dn*N.x, du*U.y + dv*V.y + dn*N.y, du*U.z + dv*V.z + dn*N.z);     POS = POS + delta;     TARGET = TARGET + delta;     return this->UpdateUVN(); }  Camera & Camera::Rotate(float roll, float pitch, float yaw) {     vec3f uu, vv, nn;      uu = U, vv = V;     U = uu * cosf(roll) - vv * sinf(roll);     V = uu * sinf(roll) + vv * cosf(roll);      vv = V, nn = N;     V = vv * cosf(pitch) - nn * sinf(pitch);     N = vv * sinf(pitch) + nn * cosf(pitch);      // nn = N, uu = U;     N = nn * cosf(yaw) - uu * sinf(yaw);     U = nn * sinf(yaw) + uu * cosf(yaw);      // update target and up.     TARGET = POS + N; UP = V;      return *this; }  Camera & Camera::UpdateUVN() {     // calculate the axis value of camera coordinate system.     N = (TARGET - POS).Normalize();     U = (UP * N).Normalize();     V = (U * N).Normalize();     return *this; }  mat4x4f & Camera::TransformM() {     memset(M, 0x00, sizeof(M));     M[0][0] = M[1][1] = M[2][2] = M[3][3] = 1.0f;     // calculate translation transform.     mat4x4f TranslateM = {         1.0f, 0.0f, 0.0f, -POS.x,         0.0f, 1.0f, 0.0f, -POS.y,         0.0f, 0.0f, 1.0f, -POS.z,         0.0f, 0.0f, 0.0f, 1.0f     };     mulmatf(TranslateM, M, M, 4, 4, 4);     // calculate rotation transform.     mat4x4f RotateM = {         U.x , U.y , U.z , 0.0f,         V.x , V.y , V.z , 0.0f,         N.x , N.y , N.z , 0.0f,         0.0f, 0.0f, 0.0f, 1.0f     };     mulmatf(RotateM, M, M, 4, 4, 4);      return this->M; } 

方向鍵控制六個方向上的移動:

static void SpecialKeys(int key, int, int) {     switch (key) {     case GLUT_KEY_LEFT: camera.Translate(-STEP_VAL); break;     case GLUT_KEY_RIGHT: camera.Translate(STEP_VAL); break;     case GLUT_KEY_UP: camera.Translate(0.0f, STEP_VAL); break;     case GLUT_KEY_DOWN: camera.Translate(0.0f, -STEP_VAL); break;     case GLUT_KEY_PAGE_UP: camera.Translate(0.0f, 0.0f, STEP_VAL); break;     case GLUT_KEY_PAGE_DOWN: camera.Translate(0.0f, 0.0f, -STEP_VAL); break;     default: printf("Unknown Special Key: %d\n", key); break;     } } 

鼠標拖拽:

glutMotionFunc(MotionFunc); glutMouseFunc(MouseFunc);  static void MotionFunc(int x, int y) {     if(mstate) {         camera.Rotate(0.0f, ToRadian((_y-y)*Camera::MOUSE_SENSITIVITY), ToRadian((_x-x)*Camera::MOUSE_SENSITIVITY));         _x = x; _y = y; // update     } }  static void MouseFunc(int button, int state, int x, int y) {     if(button == GLUT_LEFT_BUTTON) {         if(state == GLUT_DOWN) {             _x = x, _y = y; mstate = true;         }         else {             mstate = false;         }     } } 

MVP變換矩陣

M、V、P 分別指模型(model),視圖(view)和投影(projection)。MVP矩陣是模型、視圖、以及投影變換三者結合起來的變換矩陣。變換順序為:模型 -> 視圖 -> 投影。變換方程表達:

MVP = model * view * projection  MVPTransform = model * view * projection * origin 

在實際編程中,可以使用glm庫來方便地實現這些操作:

    // Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units     glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);     // Camera matrix     glm::mat4 View       = glm::lookAt(         glm::vec3(4,3,3), // Camera is at (4,3,3), in World Space         glm::vec3(0,0,0), // and looks at the origin         glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)     );     // Model matrix : an identity matrix (model will be at the origin)     glm::mat4 Model      = glm::mat4(1.0f);  // Changes for each model !     // Our ModelViewProjection : multiplication of our 3 matrices     glm::mat4 MVP        = Projection * View * Model; // Remember, matrix multiplication is the other way around 

深度緩沖(Z-Buffer)

在OpenGL繪圖過程中,我們會遇到這樣的問題:一些理應被遮擋的面,因為繪制次序靠后,竟然變成可見的了。我們將用深度緩沖(Z-Buffer)算法解決它。

該問題的解決方案是:在緩沖中存儲每個片段的深度(即“Z”值);并且每次繪制片段之前要比較當前與先前片段的深度值,看誰離攝像機更近。

我們可以自己實現深度緩沖,但讓硬件自動完成更簡單:

// Enable depth test glEnable(GL_DEPTH_TEST); // Accept fragment if it closer to the camera than the former one glDepthFunc(GL_LESS); 

問題解決了。

參考

  1. 深入投影變換
  2. OpenGL學習腳印: 投影矩陣的推導
  3. 推導相機變換矩陣

posted on 2018-01-08 11:31 zmj 閱讀(1585) 評論(0)  編輯 收藏 引用

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品欧美专区| 欧美激情1区| 91久久精品www人人做人人爽| 亚洲欧美一区二区激情| 亚洲视频每日更新| 亚洲一区亚洲二区| 欧美一区午夜视频在线观看| 欧美自拍偷拍| 欧美freesex交免费视频| 亚洲国产福利在线| 一本色道婷婷久久欧美| 亚洲综合国产激情另类一区| 欧美在线日韩| 免费观看成人鲁鲁鲁鲁鲁视频| 欧美国产日本韩| 国产精品国产三级国产专播品爱网 | 韩国福利一区| 亚洲国产你懂的| 一本一本大道香蕉久在线精品| 亚洲视频欧美视频| 久久精品盗摄| 亚洲精品国产精品乱码不99 | 在线观看一区二区视频| 亚洲免费久久| 欧美在线视频不卡| 亚洲国产日韩精品| 欧美一区二区三区免费观看| 欧美激情一区二区三区蜜桃视频| 国产精品美女久久久久av超清| 黄色日韩网站| 亚洲免费影视| 亚洲黄一区二区| 久久精品理论片| 国产精品久久久久久久久久免费看| 一区二区三区在线视频观看| 亚洲在线一区二区| 亚洲电影视频在线| 久久精品国语| 国产日韩欧美中文在线播放| 一区二区三区四区五区精品视频| 久久综合色影院| 欧美一区二区精品久久911| 欧美日韩一区二区三区在线看 | 麻豆精品网站| 国产日韩av一区二区| 一区二区三区 在线观看视| 久久嫩草精品久久久久| 亚洲深夜福利网站| 欧美—级a级欧美特级ar全黄| 极品中文字幕一区| 久久精品国产清高在天天线| 亚洲一区二区高清视频| 欧美午夜一区二区三区免费大片 | 国产一区二区久久久| 亚洲一区高清| 日韩亚洲欧美精品| 欧美久久视频| 日韩午夜激情| 欧美成人小视频| 久久狠狠婷婷| 午夜免费久久久久| 欧美先锋影音| 亚洲制服av| 正在播放亚洲| 欧美日韩在线视频观看| 99精品热视频| 日韩一级二级三级| 国产精品v欧美精品v日韩精品| 中国av一区| 夜夜嗨av一区二区三区| 国产精品www| 亚洲欧美欧美一区二区三区| 亚洲一级在线观看| 国产喷白浆一区二区三区| 久久国产精品久久精品国产| 午夜在线电影亚洲一区| 国产一区二区三区黄视频| 久久另类ts人妖一区二区| 久久综合给合久久狠狠色| 亚洲国产小视频| 亚洲精品免费在线播放| 欧美午夜一区二区三区免费大片 | 麻豆国产精品777777在线| 亚洲欧洲日本mm| 亚洲美女视频网| 国产毛片精品视频| 蜜桃av久久久亚洲精品| 欧美日韩在线免费| 性18欧美另类| 久久久久久一区二区三区| 亚洲精品国产精品国自产观看浪潮 | 在线不卡欧美| 亚洲九九九在线观看| 国产视频一区在线观看| 欧美成人综合网站| 国产精品久久亚洲7777| 免费一级欧美片在线播放| 欧美久久久久久| 久久精品中文字幕免费mv| 欧美二区在线播放| 久久xxxx| 欧美日韩在线高清| 另类春色校园亚洲| 欧美性猛交99久久久久99按摩| 免费成人av资源网| 国产精品久久久久久久久搜平片| 欧美大片国产精品| 国产一区亚洲| 亚洲欧美制服另类日韩| 一本一道久久综合狠狠老精东影业| 先锋影音国产一区| 亚洲视频播放| 欧美成人午夜影院| 久久亚洲一区| 国产嫩草一区二区三区在线观看| 亚洲国产福利在线| 樱花yy私人影院亚洲| 久久一区二区三区国产精品| 久久人人97超碰精品888| 亚洲欧美激情四射在线日 | 一区二区三区国产精华| 91久久夜色精品国产网站| 午夜精品一区二区三区电影天堂 | 99国内精品久久| 亚洲精品一区二区三| 久久免费黄色| 久久午夜电影网| 国产欧美日韩综合一区在线播放 | 欧美成人午夜剧场免费观看| 狼狼综合久久久久综合网| 国产深夜精品福利| 亚洲欧美精品在线观看| 亚洲欧美激情一区二区| 欧美视频在线免费| 日韩亚洲视频| 亚洲天堂av在线免费| 欧美全黄视频| 妖精成人www高清在线观看| 亚洲无人区一区| 欧美日韩一区二区三区四区在线观看 | 国产一区二区三区自拍| 亚洲欧美成人网| 欧美在线播放高清精品| 国产乱码精品一区二区三区忘忧草 | 欧美亚一区二区| 中日韩高清电影网| 亚洲欧美日韩系列| 国产目拍亚洲精品99久久精品| 性感少妇一区| 欧美精品一区二区三区高清aⅴ| 亚洲国语精品自产拍在线观看| 最近中文字幕日韩精品 | 国产视频在线观看一区二区三区| 欧美一区二区私人影院日本 | 久久精品麻豆| 亚洲成人自拍视频| 欧美高清在线视频观看不卡| 亚洲人线精品午夜| 国产日韩精品在线| 亚洲最新视频在线播放| 午夜精品电影| 亚洲成人资源| 欧美性jizz18性欧美| 午夜影院日韩| 91久久黄色| 久久精品国产77777蜜臀| 在线精品观看| 欧美深夜影院| 久久日韩粉嫩一区二区三区| 亚洲人成在线播放| 午夜久久一区| 亚洲青涩在线| 国产视频亚洲精品| 欧美精品黄色| 欧美一区免费| 日韩视频免费大全中文字幕| 久久黄色网页| 一区二区日韩欧美| 在线观看亚洲精品| 国产精品护士白丝一区av| 久久网站热最新地址| 亚洲无线一线二线三线区别av| 模特精品裸拍一区| 午夜精品久久久久| 日韩视频免费在线观看| 国产一区二区三区精品久久久| 欧美精品日韩一本| 久久久精彩视频| 亚洲愉拍自拍另类高清精品| 欧美激情偷拍| 另类尿喷潮videofree| 午夜日韩激情| 这里只有精品视频| 亚洲精品黄色| 影音先锋欧美精品| 国产色综合久久| 国产精品日韩在线| 欧美日韩另类在线| 欧美电影在线观看| 免费h精品视频在线播放|