0


我正在绘制大约 30 - 80 个带纹理的平面(正方形) - 背景、玩家、敌人、子弹等。
所有平面都移动和缩放,有些 + 旋转,有些有动画纹理。

我认为,对于 CPU 或 GPU 来说,这并不太难,但在较慢/较旧的设备上,它的性能相对较低——例如在 Galaxy ACE 上。

拜托,你能看看我的代码,我在做什么错或脏吗?或者可以优化什么?
谢谢你。

这是我的 onSurfaceCreated、onSurfaceChanged 和 onDrawFrame:

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);  
}   
4

3 回答 3

2

我认为您不想在绘图循环中多次调用 glGet*,因为它可能是一个缓慢的操作。

您可以在对象内本地缓存属性位置吗?或者我想知道为什么当每个对象都使用相同的着色器时,你甚至要为每个对象设置属性位置。

于 2012-08-26T15:57:32.817 回答
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/

如果你决定走 3rd 方游戏引擎的路线,IMO libgdx 是迄今为止最好的:

http://libgdx.badlogicgames.com/

它是免费的、开源的,并且非常注重性能。话虽如此,我也决定自己构建,因为我不需要 libgdx 提供的广泛功能,但我不得不说,我编写的每一行代码都让我停下来质疑这个决定;)

祝你好运。

于 2012-10-30T07:26:23.583 回答
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

于 2012-08-26T15:43:39.143 回答