2012-08-26 101 views
0


我正在繪製大約30-80個紋理平面(正方形) - 背景,球員,敵人,子彈等。
所有飛機移動和縮放,一些+旋轉和一些動畫紋理。

我認爲,CPU或GPU不能太難,但在較慢/較舊的設備上,它的性能相對較低 - 例如在Galaxy ACE上。

請你看看我的代碼,我在做什麼錯或髒?或者什麼可以優化?
謝謝。

這是我onSurfaceCreated,onSurfaceChanged和onDrawFrame:OpenGL ES 2.0 - 性能/最優化需要?

public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { 
    .. 
    // load and prepare all textures 
    .. 

    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 
    GLES20.glEnable(GLES20.GL_CULL_FACE);    
    GLES20.glDisable(GLES20.GL_DEPTH_TEST);  
    GLES20.glEnable(GLES20.GL_TEXTURE_2D);    

    GLES20.glDisable(GL10.GL_DITHER); 
    GLES20.glDisable(GL10.GL_LIGHTING); 
    final float eyeX = 0.0f; final float eyeY = 0.0f; final float eyeZ = 1.5f;  
    final float lookX = 0.0f; final float lookY = 0.0f; final float lookZ = -3.0f; 
    final float upX = 0.0f; final float upY = 1.0f; final float upZ = 0.0f; 
    Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); 

    mProgramHandle = GLES20.glCreateProgram();  

    final String vertexShader = 
    "uniform mat4 u_MVPMatrix;   \n"      
    + "attribute vec4 a_Position;  \n"        
    + "attribute vec2 a_TexCoordinate; \n"  
    + "attribute float a_AlphaValue; \n" 
    + "varying vec2 v_TexCoordinate; \n"    
    + "varying float v_AlphaValue;  \n" 
    + "void main()      \n"         
    + "{        \n"       
    + " v_TexCoordinate = a_TexCoordinate;  \n" 
    + " v_AlphaValue = a_AlphaValue;   \n" 
    + " gl_Position = u_MVPMatrix * a_Position; \n" 
    + "}           \n";   

    final String fragmentShader = 
    "precision lowp float;    \n"   
    + "uniform sampler2D u_Texture;  \n"  
    + "varying vec2 v_TexCoordinate;  \n"  
    + "varying float v_AlphaValue;  \n"    
    + "void main()      \n"  
    + "{         \n" 
    + " gl_FragColor = texture2D(u_Texture, v_TexCoordinate); \n"    
    + " gl_FragColor.a *= v_AlphaValue; \n" 
    + "}         \n";    

    final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);  
    final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);  
    mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, new String[] {"a_Position", "a_TexCoordinate", "a_AlphaValue"}); 

    GLES20.glUseProgram(mProgramHandle); 
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix"); 
    mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix"); 
    mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position"); 
} 

public void onSurfaceChanged(GL10 glUnused, int width, int height) {  
    GLES20.glViewport(0, 0, width, height); 
    float ratio = (float) width/height; 
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 1, 1000); 
} 

public void onDrawFrame(GL10 glUnused) { 
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 
    GLES20.glEnable(GLES20.GL_BLEND); 
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); 
    updateGame(); 

    // all planes are saved in Vector<Mesh> children   
    int size = children.size(); 
    for (int i = 0; i < size; i++) 
    { 
    children.get(i).Draw(renderer); 
    } 
} 



而在 '平面' 對象繪製(渲染):

public void Draw(Renderer renderer) 
{      
    if (!Visible) return; // no visible object, no need draw 
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(renderer.mProgramHandle, "a_TexCoordinate"); 
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBrickDataHandle); 
    mAlphaHandle = GLES20.glGetAttribLocation(renderer.mProgramHandle, "a_AlphaValue");  
    GLES20.glVertexAttrib1f(mAlphaHandle, alpha); 

    // texture animation 
    renderer.mPlaneTextureCoords[(byte)indexAnim].position(0); 
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, renderer.mPlaneTextureCoords[(byte)indexAnim]); 
    indexAnim++; 

    renderer.mPlanePositions.position(0); 
    GLES20.glVertexAttribPointer(Renderer.mPositionHandle, renderer.mPositionDataSize, GLES20.GL_FLOAT, false, 0, renderer.mPlanePositions);   
    GLES20.glEnableVertexAttribArray(Renderer.mPositionHandle);      

    if (angleZ == 0) // no rotating plane -> no need setRotateM 
    { 
    Matrix.setIdentityM(renderer.mModelMatrix, 0); 
    Matrix.translateM(renderer.mModelMatrix, 0, x, y, z); 
    Matrix.scaleM(renderer.mModelMatrix, 0, scaleX, scaleY, 1); 
    } 
    else // rotating plane 
    { 
    float[] mt = new float[16]; 
    Matrix.setIdentityM(mt, 0); 
    Matrix.translateM(mt, 0, x, y, z); 
    Matrix.scaleM(mt, 0, scaleX, scaleY, 1); 
    Matrix.setRotateM(mRotZMatrix, 0, angleZ, 0, 0, 1); 
    Matrix.multiplyMM(renderer.mModelMatrix, 0, mt, 0, mRotZMatrix, 0); 
    } 

    Matrix.multiplyMM(renderer.mMVPMatrix, 0, renderer.mViewMatrix, 0, renderer.mModelMatrix, 0); 
    GLES20.glUniformMatrix4fv(renderer.mMVMatrixHandle, 1, false, renderer.mMVPMatrix, 0);     

    //Matrix.multiplyMM(renderer.mMVPMatrix, 0, renderer.mProjectionMatrix, 0, renderer.mMVPMatrix, 0); 
    Matrix.multiplyMM(renderer.mTemporaryMatrix, 0, renderer.mProjectionMatrix, 0, renderer.mMVPMatrix, 0); // little bit faster (?) 
    System.arraycopy(renderer.mTemporaryMatrix, 0, renderer.mMVPMatrix, 0, 16); 

    GLES20.glUniformMatrix4fv(renderer.mMVPMatrixHandle, 1, false, renderer.mMVPMatrix, 0); // pass in the combined matrix 
    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);   
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6); 
} 

回答

1

如果你在Android SDK(如V16)的新版本運行,就可以使用剖析,找出有問題的地方是:

http://developer.android.com/tools/debugging/debugging-tracing.html

但乍一看有一對夫婦的事情,我可以看到:

  1. 另一個響應強調,您所呼叫glGetAttribLocation您繪製調用裏面,你不需要這個你畫都必須這樣做。一旦設置了「程序」,就可以獲得這些引用,只要該程序不會改變(即不更改着色器),它們也不會改變。同樣撥打電話glEnableVertexAttribArray

  2. 考慮使用紋理圖集。每次調用glBindTexture都可能導致VRAM中的狀態改變,這是一種緩慢的操作。紋理圖集只是一個包含全部(或多個)或您的紋理(例如精靈)的單個圖像。當您指定紋理座標時,只需指定介於0和1之間的值,即代表圖集中單個精靈的位置。如果你想使用這種方法,你將不得不「包裝」你的地圖集,以免浪費空間。有幾個工具可以做到這一點(例如TexturePacker)。這意味着更少的(可能只有一個)電話glBindTexture

  3. 你正在通過你的MVP矩陣兩次glUniformMatrix4fv這是不必要的。更改已被髮送後,當着色器在調用執行以glDrawArrays

  4. 我最近不會有任何影響(即初始設置操作將被覆蓋)爲基體僅用於發送到着色器中的矩陣發現setRotateM非常緩慢。周圍有替代品,我需要找到!

  5. 您最近的System.arrayCopy是不必要的。您可以鏈接矩陣乘法而不需要臨時文件。矩陣。型號*查看= MV,然後MV *投影= MVP

如果您還沒有你也應該看看這個教程:

http://www.learnopengles.com/android-lesson-one-getting-started/

,如果你決定往下走第三方遊戲引擎的路線,IMO libgdx是迄今爲止最好的:

http://libgdx.badlogicgames.com/

它是免費的,開源的,具有很強的焦點性能。說了我也決定建立我自己的,因爲我不需要libgdx提供的功能的廣度,但我不得不說,我寫的每一行代碼使我停下來質疑這個決定;)

祝你好運。

+0

非常感謝您的回覆。我修復了你寫的所有錯誤/錯誤,除了第2點。 - 至少目前爲止, 也許現在重製當前項目已經太晚了...所以,我尋找TexturePacker,我會考慮這個改變:-) – Commanche

0

你看之前使用的遊戲引擎?其中不少代碼能夠以相當少的代碼處理這類任務,而壓力= P

開始學習遊戲引擎需要多一點時間,但會爲您節省數百幾小時後。專爲遊戲而設計,即使在較舊的設備上,它們也能夠在不犧牲性能的情況下處理大量物體。

這不是一個直接的解決你的問題,但也許它可以幫助你以後^。^ 這裏是遊戲引擎的Android大規模列表 http://mobilegameengines.com/android/game_engines

如果你喜歡的開源遊戲引擎,你可能會喜歡這些,我只有使用其中一些的經驗,但我發現AndEngine是最簡單的開始,它絕對強大到足以處理30-80個對象。 http://ntt.cc/2011/05/08/8-open-source-android-game-engines.html

+0

感謝您的回覆。所以,我是初學者,我正在學習它:-)我從一個簡單的2D遊戲開始。我認爲,我不需要遊戲引擎,至少現在,也許有一些下一個(更復雜)的項目:-) – Commanche

2

我不認爲你想在你的循環中調用glGet *這麼多次,因爲它可能是一個緩慢的操作。

你能在對象內本地緩存屬性位置嗎?或者我想知道爲什麼你甚至爲每個對象設置每個對象的屬性位置,當他們都使用相同的着色器時。

+0

謝謝你的回覆。你是對的...我修正了它 - 現在在onSurfaceCreated中設置位置屬性。現在速度更快,謝謝。 – Commanche