基于視錐體(平截體)的OpenGL ES性能優(yōu)化

教程

OpenGLES入門教程1-Tutorial01-GLKit
OpenGLES入門教程2-Tutorial02-shader入門
OpenGLES入門教程3-Tutorial03-三維變換
OpenGLES入門教程4-Tutorial04-GLKit進階
OpenGLES進階教程1-Tutorial05-地球月亮
OpenGLES進階教程2-Tutorial06-光線
OpenGLES進階教程3-Tutorial07-粒子效果
OpenGLES進階教程4-Tutorial08-幀緩存
OpenGLES進階教程5-Tutorial09-碰碰車
這一次的是性能優(yōu)化。

概要

渲染的優(yōu)化不是僅僅提高渲染的速度,超過60Hz的渲染速度沒有任何意義,用戶永遠看不到這些信息。同時在考慮用電消耗的情況下,30Hz的刷新率能延長電池的使用時間。
以下的渲染優(yōu)化策略總是管用的:

  • 減少I/O
  • 渲染更少的幾何對象
  • 減少內存訪問

效果展示

核心思路

通過減少渲染的幾何對象,在不影響顯示效果的前提下,盡可能減少需要繪制的圖元。
在一個場景中,很多物體是處于平截體外部,這些物體是用戶永遠看不到的對象。

具體細節(jié)

a.測試點是否在平截體內

計算眼睛到當前測試點的向量,提取這個向量關于平截體X、Y、Z軸的分量,分別進行判斷。


  • 1、計算眼睛到當前測試點的向量。
    // eye到point的向量
    const GLKVector3 eyeToPoint = GLKVector3Subtract(frustumPtr->eyePosition, point);
  • 2、測試Z軸分量,這個分量要在區(qū)間[nearDistance, farDistance]。如果是,繼續(xù)步驟3。
    // z軸分量
    const GLfloat pointZComponent = GLKVector3DotProduct(eyeToPoint, frustumPtr->zUnitVector);
    
    if(pointZComponent > frustumPtr->farDistance || pointZComponent < frustumPtr->nearDistance)
    {
        result = AGLKFrustumOut;
    }
  • 3、Y軸分量要小于被測點所在的平截體高度,高度的可以通過Z軸分量*視角/2的正切值計算。如果在區(qū)間內,繼續(xù)步驟4。
        // y軸分量
        const GLfloat pointYComponent =
        GLKVector3DotProduct(eyeToPoint,
                             frustumPtr->yUnitVector);
        const GLfloat frustumHeightAtZ = pointZComponent * frustumPtr->tangentOfHalfFieldOfView;
        
        if(pointYComponent > frustumHeightAtZ || pointYComponent < -frustumHeightAtZ)
        {
            result = AGLKFrustumOut;
        }
  • 4、X軸分量要小于被測點鎖在的平截體的寬度,寬度可以通過平截體高度值 * 寬高比。
          //X軸分量
            const GLfloat pointXComponent =
            GLKVector3DotProduct(eyeToPoint,
                                 frustumPtr->xUnitVector);
            const GLfloat frustumWidthAtZ = frustumHeightAtZ *
            frustumPtr->aspectRatio;
            
            if(pointXComponent > frustumWidthAtZ ||
               pointXComponent < -frustumWidthAtZ)
            {
                result = AGLKFrustumOut;
            }

b.判斷球體是否在平截體內

測試球體會測試點更復雜,同樣是對比X/Y/Z軸分量,在判斷的范圍加上半徑的距離。
但是,考慮下面的情況


按照上面的判斷,球體是在平截體之外,但是實際上是相交的。
解決方案

把半徑乘以特定的因子。

如下圖,考慮球體被外切情況,得出相應的放大因子。


  • 1、Y軸因子
sphereFactorY = 1.0f/cosf(halfFieldOfViewRad);
  • 2、X軸因子
    const GLfloat angleX = atanf(frustumPtr->tangentOfHalfFieldOfView * aspectRatio);
    frustumPtr->sphereFactorX = 1.0f/cosf(angleX);

擴展

  • 場景圖(scene graph)輔助剔除
    用樹形數(shù)據(jù)結的幾何對象層次組織。樹形結構有一個根元素。根元素是子元素的父,子元素可能是其他元素的父。參考Cocoa的視圖層次結構,2DUIView實例的場景圖。同樣的概念也使用與3D對象的層次結構。如果父元素在平截體外部,根據(jù)定義所有它的子元素也在平截體外部,沒有必要再單獨測試每個子元素。
    關鍵詞:Ochre 八叉樹。

  • 減少緩存復制
    為GPU提供一個頂點屬性緩存后,用CPU處理另一個。在所有渲染指令發(fā)送完后,通過glBindBuffer()函數(shù)來切換緩存。(蘋果公司官網(wǎng)有例子,OpenGLESApplicationDesign.html)

  • 減少狀態(tài)變換
    OpenGL ES上下文存儲了大量的用于控制渲染運算的信息。信息緩存可能在CPU控制的內存,也可能在GPU的寄存器。
    調用glEnable(GL_DEPTH_TEST)多次會浪費時間更新上下文的狀態(tài),即使值是相同的。

  • OES
    OES擴展是OpenGL ES標準的維護者,提出的一個非標準的擴展。

思考

為什么FPS會在20FPS和30FPS之間擺動?
繪制 和 顯示 并不一樣。
通過CADisplayLink(hardware generated),繪制的速率可能是60FPS。
如果繪制的時間超過1/60s,理論上幀率最多為30FPS。
想象一條1s的線段,分隔成60小段,每個小段的起點都可以作為繪制的起點。
如果繪制的時間超過1/60s,那么繪制的終點會延伸到第二個小段。
這樣,一條1s的線段,最多有30個繪制的時間段。

Since CADisplayLink is hardware generated the only thing you can do with it is divide the time, that's what the frameInterval is there to do.
frameInterval = 1 gets you 60 fps
frameInterval = 2 gets you 30 fps
frameInterval = 3 gets you 20 fps
I use a lot frameInterval = 5 for menus for example, it still gives me 12fps (about the minimum for reasonable simple animation) and the battery consumption reduces drastically.

你能得到FPS,但是它不代表真正的性能,每幀持續(xù)時間是一個更佳選擇。FPS不能線性評判性能表現(xiàn)。

For example, if your FPS goes from 30 to 20, then that's a pretty significant decrease in frame performance time (33 ms to 50 ms)
However if your FPS goes from 2000 to 400, that's a miniscule difference in real time (only 2ms difference).

最后,即使你自己通過自定義線程(不采用CADisplayLink),把繪制時間的空缺填補,實際上繪制的速率并不會變快。

總結

主要講解的是數(shù)學部分的知識,OpenGL ES的部分沒有引入新的技術點。
工作原因,以后更新會慢一些。能看到這里,你也是喜歡技術的,謝謝支持。來一波關注和喜歡如何 -> 我會加油更新。
附上源碼

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容