七、OpenGL中觀察方式與矩陣的關(guān)系

目前在OpenGL中,矩陣的變換主要涉及兩種觀察方式:

  • 觀察者不動(dòng),物體動(dòng)
  • 觀察者動(dòng),物體不動(dòng)

兩種方式涉及步驟大致總結(jié)如下:

  • ChangeSize函數(shù)
    設(shè)置投影方式,得到投影矩陣,并往矩陣堆棧中壓入一個(gè)單元矩陣(單元矩陣的壓入可省略)
    //創(chuàng)建投影矩陣,并將它載入投影矩陣堆棧中
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //調(diào)用頂部載入單元矩陣
    modelViewMatrix.LoadIdentity();
  • SetupRC函數(shù)
    設(shè)置觀察者的位置
  • SpecialKeys函數(shù)
    決定物體/觀察者圍繞旋轉(zhuǎn)的坐標(biāo)軸
  • RenderScene函數(shù)
    完成矩陣的相應(yīng)變換:入棧、相乘、出棧

下面我們來分別說說兩種方式的區(qū)別

觀察者不動(dòng),物體動(dòng)

觀察者不動(dòng),物體動(dòng)

05_OpenGL 點(diǎn)/線/線段/線環(huán)/金字塔/六邊形/圓柱的副本(觀察者不動(dòng),物體動(dòng)-objectFrame)的代碼中

  • 設(shè)置觀察者的位置
    ==> GLFrame中默認(rèn)的方向是z軸的負(fù)方向 -- (0.0f, 0.0f, -1.0f)
    ==> 參數(shù):表示離屏幕之間的距離。 負(fù)數(shù),是往屏幕后面移動(dòng);正數(shù),往屏幕前面移動(dòng)
cameraFrame.MoveForward(-15.0f);
  • 在SpecialKeys函數(shù)中,進(jìn)行旋轉(zhuǎn)是物體

例如,按上鍵位,物體圍繞x軸旋轉(zhuǎn) -5度

objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
  • RenderScene函數(shù)中,同時(shí)涉及觀察者矩陣和物體矩陣的變換
    因?yàn)橛^察者設(shè)置位置時(shí),往屏幕后面平移了15個(gè)像素點(diǎn),所以觀察者發(fā)生了變化
    在我們選中特殊鍵位移動(dòng)圖形時(shí),物體進(jìn)行了旋轉(zhuǎn),所以物體也發(fā)生了變化
    因此最后所需的mvp矩陣,需要按照壓棧cameraFrame- 壓棧objectFrame - 投影矩陣這個(gè)順序進(jìn)行矩陣變換,這個(gè)順序是OpenGL規(guī)定的,且順序是不能交換的,因?yàn)榫仃囅喑瞬粷M足交換律, 即 矩陣A * 矩陣B != 矩陣B * 矩陣A
    //壓棧
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);

    //矩陣乘以矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后簡(jiǎn)存儲(chǔ)在堆棧的頂部
    modelViewMatrix.MultMatrix(mCamera);
    
    M3DMatrix44f mObjectFrame;
    //只要使用 GetMatrix 函數(shù)就可以獲取矩陣堆棧頂部的值,這個(gè)函數(shù)可以進(jìn)行2次重載。用來使用GLShaderManager 的使用。或者是獲取頂部矩陣的頂點(diǎn)副本數(shù)據(jù)
    objectFrame.GetMatrix(mObjectFrame);
    
    //矩陣乘以矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后簡(jiǎn)存儲(chǔ)在堆棧的頂部
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);

其中矩陣堆棧的變化過程如下:


矩陣堆棧的變化過程
  • PushMatrix()函數(shù),根據(jù)源碼分析可知:在沒有任何參數(shù)的情況下,矩陣堆棧會(huì)將棧頂單元矩陣拷貝一份,并將拷貝的單元矩陣入棧


    PushMatrix函數(shù)源碼

觀察者動(dòng),物體不動(dòng)

觀察者動(dòng),物體不動(dòng)

在Demo05_OpenGL 點(diǎn)/線/線段/線環(huán)/金字塔/六邊形/圓柱的副本(觀察者動(dòng),物體不動(dòng)-cameraFrame)代碼中

  • 設(shè)置觀察者的位置
    此時(shí)的objectFrame是指觀察者,并不是物體
objectFrame.MoveForward(15.0f);
  • 在SpecialKeys函數(shù)中,進(jìn)行旋轉(zhuǎn)是觀察者
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
  • RenderScene函數(shù)中,僅涉及觀察者的矩陣變換
    ==> 設(shè)置觀察者位置時(shí),觀察者平移了15個(gè)像素點(diǎn)
    ==> 特殊鍵位觸發(fā)時(shí),觀察者繞著相應(yīng)的軸旋轉(zhuǎn)了一定的弧度
    ==> 所以objectFrame不僅記錄了往前移動(dòng)的狀態(tài),還記錄了旋轉(zhuǎn)的轉(zhuǎn)臺(tái),所以只需要將objectFrame載入矩陣堆棧即可, 即 把往前的變化、旋轉(zhuǎn)的變化都 放入 模型矩陣堆棧中
modelViewMatrix.PushMatrix(objectFrame);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);

其中矩陣堆棧的變化過程如下:


矩陣堆棧的變化過程

觀察者矩陣中包含了觀察者的所有變換,會(huì)直接在變換管道中完成矩陣相乘,最后通過變換管道得到mvp矩陣。

總結(jié)
其實(shí)選擇哪種觀察方式,還是需要結(jié)合需求,個(gè)人建議,哪種方便用哪個(gè)

  • 在觀察者不動(dòng),物體動(dòng)時(shí),觀察者也并非是一動(dòng)不動(dòng),需要調(diào)整一個(gè)好的觀察位置
  • 觀察者動(dòng),主要?jiǎng)拥氖荲_local,其實(shí)就是通過moveForward方法設(shè)置的觀察者位置
  • 物體動(dòng),主要?jiǎng)拥氖莔vp

疑問

  • 在觀察者不動(dòng),物體動(dòng)時(shí),為什么不能直接這樣寫modelViewMatrix.PushMatrix(cameraFrame)?

我們從PushMatrix(cameraFrame)的源碼分析可知,如圖所示,傳入push函數(shù)的frame在 PushMatrix方法中獲取的是GetMatrix,而我們需要的是GetCameraMatrix,所以不能直接將cameraFrame直接push到矩陣堆棧中

源碼分析

``

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容