2013-07-10 32 views
5

Tôi đã phát triển bản đồ bằng cách sử dụng OpenGL-ES trên Android. Nó được hiển thị bản đồ của tôi tốt, và tôi vừa thêm xử lý sự kiện cảm ứng để tôi có thể di chuyển và ném nó xung quanh, mà cũng làm việc.Cách tăng tốc kết xuất bằng OpenGL (ES) 2 Android

Tuy nhiên, nó có thời gian trễ khoảng 1 giây. Tôi muốn việc panning hình ảnh rõ ràng là mượt mà nhất có thể.

Tôi có khá nhiều dữ liệu vectơ mà tôi đang hiển thị, nhưng vẫn phải có lựa chọn thay thế để làm cho tương tác mượt mà hơn, tôi có 17000 đa giác (lô đất hoặc lô đất) và khoảng 1500 dòng (đường trung tâm đường), cả hai đều được tải sẵn vào danh sách giữ FloatBuffers khi ứng dụng khởi chạy. Khi tôi đi đến hoạt động bản đồ của tôi, trình kết xuất lặp lại thông qua các danh sách này, Như bạn sẽ thấy trong mã bên dưới.

Tôi thực sự đánh giá cao một số gợi ý về cách tôi có thể tăng tốc độ.

(Chỉ cần trên lưu ý khác, xin vui lòng bỏ qua các máy dò quy mô và bất kỳ mã luân chuyển, họ không làm việc, tất cả tôi đang tập trung vào ngay bây giờ là panning bản đồ.)

enter image description here

package com.ANDRRA1.utilities; 

import android.content.Context; 
import android.opengl.GLSurfaceView; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.GestureDetector; 
import android.view.ScaleGestureDetector; 
import android.view.animation.DecelerateInterpolator; 
import android.view.animation.Interpolator; 

public class CustomGLView extends GLSurfaceView { 

    public vboCustomGLRenderer mGLRenderer; 

    public CustomGLView(Context context){ 
     super(context); 
    } 

    public CustomGLView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
    } 

    // Hides superclass method. 
    public void setRenderer(vboCustomGLRenderer renderer) 
    { 
     mGLRenderer = renderer; 
     super.setRenderer(renderer); 

     super.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 
    } 

    private static final int INVALID_POINTER_ID = -1; 

    private float mPosX; 
    private float mPosY; 

    private float mLastTouchX; 
    private float mLastTouchY; 
    private float mLastGestureX; 
    private float mLastGestureY; 
    private int mActivePointerId = INVALID_POINTER_ID; 
    private int mActivePointerId2 = INVALID_POINTER_ID; 
    float oL1X1, oL1Y1, oL1X2, oL1Y2; 

    private ScaleGestureDetector mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); 
    private GestureDetector mGestureDetector = new GestureDetector(getContext(), new GestureListener()); 

    private float mScaleFactor = 1.f; 

    //The following variable control the fling gesture 
    private Interpolator animateInterpolator; 
    private long startTime; 
    private long endTime; 
    private float totalAnimDx; 
    private float totalAnimDy; 
    private float lastAnimDx; 
    private float lastAnimDy; 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     // Let the ScaleGestureDetector inspect all events. 
     mScaleDetector.onTouchEvent(ev); 
     mGestureDetector.onTouchEvent(ev); 

     final int action = ev.getAction(); 
     switch (action & MotionEvent.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: { 

       if (!mScaleDetector.isInProgress()) { 
        final float x = ev.getX(); 
        final float y = ev.getY(); 

        mLastTouchX = x; 
        mLastTouchY = y; 
        mActivePointerId = ev.getPointerId(0); 
       } 
       break; 
      } 
      case MotionEvent.ACTION_POINTER_DOWN: { 
       if (mScaleDetector.isInProgress()) { 
        mActivePointerId2 = ev.getPointerId(1); 

        mLastGestureX = mScaleDetector.getFocusX(); 
        mLastGestureY = mScaleDetector.getFocusY(); 

        oL1X1 = ev.getX(ev.findPointerIndex(mActivePointerId)); 
        oL1Y1 = ev.getY(ev.findPointerIndex(mActivePointerId)); 
        oL1X2 = ev.getX(ev.findPointerIndex(mActivePointerId2)); 
        oL1Y2 = ev.getY(ev.findPointerIndex(mActivePointerId2)); 
       } 
       break; 
      } 

      case MotionEvent.ACTION_MOVE: { 

       // Only move if the ScaleGestureDetector isn't processing a gesture. 
       if (!mScaleDetector.isInProgress()) { 
        final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
        final float x = ev.getX(pointerIndex); 
        final float y = ev.getY(pointerIndex); 

        final float dx = x - mLastTouchX; 
        final float dy = y - mLastTouchY; 

        mPosX += dx; 
        mPosY += dy; 

        mGLRenderer.setEye(dx, dy); 
        requestRender(); 

        mLastTouchX = x; 
        mLastTouchY = y; 
       } 
       else{ 
        final float gx = mScaleDetector.getFocusX(); 
        final float gy = mScaleDetector.getFocusY(); 

        final float gdx = gx - mLastGestureX; 
        final float gdy = gy - mLastGestureY; 

        mPosX += gdx; 
        mPosY += gdy; 

        mLastGestureX = gx; 
        mLastGestureY = gy; 
       } 

       break; 
      } 

      case MotionEvent.ACTION_UP: { 
       mActivePointerId = INVALID_POINTER_ID; 

       break; 
      } 
      case MotionEvent.ACTION_CANCEL: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 
      case MotionEvent.ACTION_POINTER_UP: { 

       final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
         >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
       final int pointerId = ev.getPointerId(pointerIndex); 
       if (pointerId == mActivePointerId) { 
        // This was our active pointer going up. Choose a new 
        // active pointer and adjust accordingly. 
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
        mLastTouchX = ev.getX(newPointerIndex); 
        mLastTouchY = ev.getY(newPointerIndex); 
        mActivePointerId = ev.getPointerId(newPointerIndex); 
       } 
       else{ 
        final int tempPointerIndex = ev.findPointerIndex(mActivePointerId); 
        mLastTouchX = ev.getX(tempPointerIndex); 
        mLastTouchY = ev.getY(tempPointerIndex); 
       } 

       break; 
      } 
     } 

     return true; 
    } 

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
     @Override 
     public boolean onScale(ScaleGestureDetector detector) { 
      mScaleFactor *= detector.getScaleFactor(); 

      // Don't let the object get too small or too large. 
      mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10000.0f)); 

      //invalidate(); 
      return true; 
     } 
    } 

    private class GestureListener extends GestureDetector.SimpleOnGestureListener { 
     @Override 
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 

      if (e1 == null || e2 == null){ 
       return false; 
      } 
      final float distanceTimeFactor = 0.4f; 
      final float totalDx = (distanceTimeFactor * velocityX/2); 
      final float totalDy = (distanceTimeFactor * velocityY/2); 

      onAnimateMove(totalDx, totalDy, (long) (1000 * distanceTimeFactor)); 
      return true; 
     } 
    } 

    public void onAnimateMove(float dx, float dy, long duration) { 
     animateInterpolator = new DecelerateInterpolator(); 
     startTime = System.currentTimeMillis(); 
     endTime = startTime + duration; 
     totalAnimDx = dx; 
     totalAnimDy = dy; 
     lastAnimDx = 0; 
     lastAnimDy = 0; 

     post(new Runnable() { 
      @Override 
      public void run() { 
       onAnimateStep(); 
      } 
     }); 
    } 

    private void onAnimateStep() { 
     long curTime = System.currentTimeMillis(); 
     float percentTime = (float) (curTime - startTime)/(float) (endTime - startTime); 
     float percentDistance = animateInterpolator.getInterpolation(percentTime); 
     float curDx = percentDistance * totalAnimDx; 
     float curDy = percentDistance * totalAnimDy; 

     float diffCurDx = curDx - lastAnimDx; 
     float diffCurDy = curDy - lastAnimDy; 
     lastAnimDx = curDx; 
     lastAnimDy = curDy; 

     doAnimation(diffCurDx, diffCurDy); 

     if (percentTime < 1.0f) { 
      post(new Runnable() { 
       @Override 
       public void run() { 
        onAnimateStep(); 
       } 
      }); 
     } 
    } 

    public void doAnimation(float diffDx, float diffDy) { 
     mPosX += diffDx; 
     mPosY += diffDy; 

     mGLRenderer.setEye(diffDx, diffDy); 
     requestRender(); 
    } 

    public float angleBetween2Lines(float L1X1, float L1Y1, float L1X2, float L1Y2, float L2X1, float L2Y1, float L2X2, float L2Y2) 
    { 
     float angle1 = (float) Math.atan2(L1Y1 - L1Y2, L1X1 - L1X2); 
     float angle2 = (float) Math.atan2(L2Y1 - L2Y2, L2X1 - L2X2); 

     float angleDelta = findAngleDelta((float)Math.toDegrees(angle1), (float)Math.toDegrees(angle2)); 
     return -angleDelta; 
    } 

    private float findAngleDelta(float angle1, float angle2) 
    { 
     return angle1 - angle2; 
    } 
} 

.

package com.ANDRRA1.utilities; 

import java.nio.FloatBuffer; 
import java.util.ListIterator; 

import javax.microedition.khronos.egl.EGLConfig; 
import javax.microedition.khronos.opengles.GL10; 

import android.opengl.GLES20; 
import android.opengl.GLSurfaceView; 
import android.opengl.Matrix; 

public class vboCustomGLRenderer implements GLSurfaceView.Renderer { 

    /** 
    * Store the model matrix. This matrix is used to move models from object space (where each model can be thought 
    * of being located at the center of the universe) to world space. 
    */ 
    private float[] mModelMatrix = new float[16]; 

    /** 
    * Store the view matrix. This can be thought of as our camera. This matrix transforms world space to eye space; 
    * it positions things relative to our eye. 
    */ 
    private float[] mViewMatrix = new float[16]; 

    /** Store the projection matrix. This is used to project the scene onto a 2D viewport. */ 
    private float[] mProjectionMatrix = new float[16]; 

    /** Allocate storage for the final combined matrix. This will be passed into the shader program. */ 
    private float[] mMVPMatrix = new float[16]; 

    /** This will be used to pass in the transformation matrix. */ 
    private int mMVPMatrixHandle; 

    /** This will be used to pass in model position information. */ 
    private int mPositionHandle; 

    /** This will be used to pass in model color information. */ 
    private int mColorUniformLocation; 

    /** How many bytes per float. */ 
    private final int mBytesPerFloat = 4; 

    /** Offset of the position data. */ 
    private final int mPositionOffset = 0; 

    /** Size of the position data in elements. */ 
    private final int mPositionDataSize = 3; 

    /** How many elements per vertex for double values. */ 
    private final int mPositionFloatStrideBytes = mPositionDataSize * mBytesPerFloat; 

    // geometry types 
    private final byte wkbPoint = 1; 
    private final byte wkbLineString = 2; 
    private final byte wkbPolygon = 3; 
    //private final byte wkbMultiPoint = 4; 
    //private final byte wkbMultiLineString = 5; 
    //private final byte wkbMultiPolygon = 6; 
    //private final byte wkbGeometryCollection = 7; 

    // Big Endian 
    final int wkbXDR = 0; 
    // Little Endian 
    final int wkbNDR = 1; 


    float count = 0; 

    // Position the eye behind the origin. 
    public volatile float eyeX = default_settings.mbrMinX + ((default_settings.mbrMaxX - default_settings.mbrMinX)/2); 
    public volatile float eyeY = default_settings.mbrMinY + ((default_settings.mbrMaxY - default_settings.mbrMinY)/2); 

    // Position the eye behind the origin. 
    //final float eyeZ = 1.5f; 
    public volatile float eyeZ = 1.5f; 

    // We are looking toward the distance 
    public volatile float lookX = eyeX; 
    public volatile float lookY = eyeY; 
    public volatile float lookZ = 0.0f; 

    // Set our up vector. This is where our head would be pointing were we holding the camera. 
    public volatile float upX = 0.0f; 
    public volatile float upY = 1.0f; 
    public volatile float upZ = 0.0f; 


    public vboCustomGLRenderer() { 
    } 

    public void setEye(float x, float y){ 

     eyeX -= (x/screen_vs_map_horz_ratio); 
     lookX = eyeX; 
     eyeY += (y/screen_vs_map_vert_ratio); 
     lookY = eyeY; 

     // Set the camera position (View matrix) 
     Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); 
    } 

    @Override 
    public void onSurfaceCreated(GL10 unused, EGLConfig config) { 


     Thread.currentThread().setPriority(Thread.MIN_PRIORITY); 

     // Set the background frame color 
     //White 
     GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 

     // Set the view matrix. This matrix can be said to represent the camera position. 
     // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and 
     // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose. 
     Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); 

     final String vertexShader = 
      "uniform mat4 u_MVPMatrix;  \n"  // A constant representing the combined model/view/projection matrix. 

      + "attribute vec4 a_Position;  \n"  // Per-vertex position information we will pass in. 
      + "attribute vec4 a_Color;  \n"  // Per-vertex color information we will pass in.    

      + "varying vec4 v_Color;   \n"  // This will be passed into the fragment shader. 

      + "void main()     \n"  // The entry point for our vertex shader. 
      + "{        \n" 
      + " v_Color = a_Color;   \n"  // Pass the color through to the fragment shader. 
                // It will be interpolated across the triangle. 
      + " gl_Position = u_MVPMatrix \n"  // gl_Position is a special variable used to store the final position. 
      + "    * a_Position; \n"  // Multiply the vertex by the matrix to get the final point in                 
      + "}        \n"; // normalized screen coordinates. 

     final String fragmentShader = 
       "precision mediump float;  \n"  // Set the default precision to medium. We don't need as high of a 
                 // precision in the fragment shader.     
       + "uniform vec4 u_Color;   \n"  // This is the color from the vertex shader interpolated across the 
                 // triangle per fragment.    
       + "void main()     \n"  // The entry point for our fragment shader. 
       + "{        \n" 
       + " gl_FragColor = u_Color;  \n"  // Pass the color directly through the pipeline.   
       + "}        \n";             

     // Load in the vertex shader. 
     int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); 

     if (vertexShaderHandle != 0) 
     { 
      // Pass in the shader source. 
      GLES20.glShaderSource(vertexShaderHandle, vertexShader); 

      // Compile the shader. 
      GLES20.glCompileShader(vertexShaderHandle); 

      // Get the compilation status. 
      final int[] compileStatus = new int[1]; 
      GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 

      // If the compilation failed, delete the shader. 
      if (compileStatus[0] == 0) 
      {    
       GLES20.glDeleteShader(vertexShaderHandle); 
       vertexShaderHandle = 0; 
      } 
     } 

     if (vertexShaderHandle == 0) 
     { 
      throw new RuntimeException("Error creating vertex shader."); 
     } 

     // Load in the fragment shader shader. 
     int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); 

     if (fragmentShaderHandle != 0) 
     { 
      // Pass in the shader source. 
      GLES20.glShaderSource(fragmentShaderHandle, fragmentShader); 

      // Compile the shader. 
      GLES20.glCompileShader(fragmentShaderHandle); 

      // Get the compilation status. 
      final int[] compileStatus = new int[1]; 
      GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 

      // If the compilation failed, delete the shader. 
      if (compileStatus[0] == 0) 
      {    
       GLES20.glDeleteShader(fragmentShaderHandle); 
       fragmentShaderHandle = 0; 
      } 
     } 

     if (fragmentShaderHandle == 0) 
     { 
      throw new RuntimeException("Error creating fragment shader."); 
     } 

     // Create a program object and store the handle to it. 
     int programHandle = GLES20.glCreateProgram(); 

     if (programHandle != 0) 
     { 
      // Bind the vertex shader to the program. 
      GLES20.glAttachShader(programHandle, vertexShaderHandle);   

      // Bind the fragment shader to the program. 
      GLES20.glAttachShader(programHandle, fragmentShaderHandle); 

      // Bind attributes 
      GLES20.glBindAttribLocation(programHandle, 0, "a_Position"); 
      GLES20.glBindAttribLocation(programHandle, 1, "a_Color"); 

      // Link the two shaders together into a program. 
      GLES20.glLinkProgram(programHandle); 

      // Get the link status. 
      final int[] linkStatus = new int[1]; 
      GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0); 

      // If the link failed, delete the program. 
      if (linkStatus[0] == 0) 
      {    
       GLES20.glDeleteProgram(programHandle); 
       programHandle = 0; 
      } 
     } 

     if (programHandle == 0) 
     { 
      throw new RuntimeException("Error creating program."); 
     } 

     // Set program handles. These will later be used to pass in values to the program. 
     mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix"); 
     mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position"); 
     mColorUniformLocation = GLES20.glGetUniformLocation(programHandle, "u_Color"); 

     // Tell OpenGL to use this program when rendering. 
     GLES20.glUseProgram(programHandle); 

    } 

    static float mWidth = 0; 
    static float mHeight = 0; 
    static float mLeft = 0; 
    static float mRight = 0; 
    static float mTop = 0; 
    static float mBottom = 0; 
    static float mRatio = 0; 
    float screen_width_height_ratio; 
    float screen_height_width_ratio; 
    final float near = 1.5f; 
    final float far = 10.0f; 

    double screen_vs_map_horz_ratio = 0; 
    double screen_vs_map_vert_ratio = 0; 

    @Override 
    public void onSurfaceChanged(GL10 unused, int width, int height) { 

     // Adjust the viewport based on geometry changes, 
     // such as screen rotation 
     // Set the OpenGL viewport to the same size as the surface. 
     GLES20.glViewport(0, 0, width, height); 
     //Log.d("","onSurfaceChanged"); 

     screen_width_height_ratio = (float) width/height; 
     screen_height_width_ratio = (float) height/width; 

     //Initialize 
     if (mRatio == 0){ 
      mWidth = (float) width; 
      mHeight = (float) height; 

      //map height to width ratio 
      float map_extents_width = default_settings.mbrMaxX - default_settings.mbrMinX; 
      float map_extents_height = default_settings.mbrMaxY - default_settings.mbrMinY; 
      float map_width_height_ratio = map_extents_width/map_extents_height; 
      //float map_height_width_ratio = map_extents_height/map_extents_width; 
      if (screen_width_height_ratio > map_width_height_ratio){ 
       mRight = (screen_width_height_ratio * map_extents_height)/2; 
       mLeft = -mRight; 
       mTop = map_extents_height/2; 
       mBottom = -mTop; 
      } 
      else{ 
       mRight = map_extents_width/2; 
       mLeft = -mRight; 
       mTop = (screen_height_width_ratio * map_extents_width)/2; 
       mBottom = -mTop; 
      } 

      mRatio = screen_width_height_ratio; 
     } 

     if (screen_width_height_ratio != mRatio){ 
      final float wRatio = width/mWidth; 
      final float oldWidth = mRight - mLeft; 
      final float newWidth = wRatio * oldWidth; 
      final float widthDiff = (newWidth - oldWidth)/2; 
      mLeft = mLeft - widthDiff; 
      mRight = mRight + widthDiff; 

      final float hRatio = height/mHeight; 
      final float oldHeight = mTop - mBottom; 
      final float newHeight = hRatio * oldHeight; 
      final float heightDiff = (newHeight - oldHeight)/2; 
      mBottom = mBottom - heightDiff; 
      mTop = mTop + heightDiff; 

      mWidth = (float) width; 
      mHeight = (float) height; 

      mRatio = screen_width_height_ratio; 
     } 

     screen_vs_map_horz_ratio = (mWidth/(mRight-mLeft)); 
     screen_vs_map_vert_ratio = (mHeight/(mTop-mBottom)); 

     Matrix.frustumM(mProjectionMatrix, 0, mLeft, mRight, mBottom, mTop, near, far); 
    } 

    @Override 
    public void onDrawFrame(GL10 unused) { 

     GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); 

     //The following lists hold the vector data in FloatBuffers pre-loaded from when then application starts 
     ListIterator<mapLayer> orgNonAssetCatLayersList_it = default_settings.orgNonAssetCatMappableLayers.listIterator(); 
     while (orgNonAssetCatLayersList_it.hasNext()) { 
      mapLayer MapLayer = orgNonAssetCatLayersList_it.next(); 

      ListIterator<FloatBuffer> mapLayerObjectList_it = MapLayer.objFloatBuffer.listIterator(); 
      ListIterator<Byte> mapLayerObjectTypeList_it = MapLayer.objTypeArray.listIterator(); 
      while (mapLayerObjectTypeList_it.hasNext()) { 

       switch (mapLayerObjectTypeList_it.next()) { 
        case wkbPoint: 
         break; 
        case wkbLineString: 
         Matrix.setIdentityM(mModelMatrix, 0); 
         //Matrix.rotateM(mModelMatrix, 0, 0, 0.0f, 0.0f, 1.0f); 
         drawLineString(mapLayerObjectList_it.next(), MapLayer.lineStringObjColor); 
         break; 
        case wkbPolygon: 
         Matrix.setIdentityM(mModelMatrix, 0); 
         //Matrix.rotateM(mModelMatrix, 0, 0, 0.0f, 0.0f, 1.0f); 
         drawPolygon(mapLayerObjectList_it.next(), MapLayer.polygonObjColor); 
         break; 
       } 
      } 
     } 
    } 

    private void drawLineString(final FloatBuffer geometryBuffer, final float[] colorArray) 
    { 
     // Pass in the position information 
     geometryBuffer.position(mPositionOffset); 
     GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mPositionFloatStrideBytes, geometryBuffer); 

     GLES20.glEnableVertexAttribArray(mPositionHandle); 

     GLES20.glUniform4f(mColorUniformLocation, colorArray[0], colorArray[1], colorArray[2], 1f); 

     // This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix 
     // (which currently contains model * view). 
     Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); 

     // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix 
     // (which now contains model * view * projection). 
     Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); 

     GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); 

     GLES20.glLineWidth(2.0f); 
     GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, geometryBuffer.capacity()/mPositionDataSize); 
    } 

    private void drawPolygon(final FloatBuffer geometryBuffer, final float[] colorArray) 
    { 
     // Pass in the position information 
     geometryBuffer.position(mPositionOffset); 
     GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mPositionFloatStrideBytes, geometryBuffer); 

     GLES20.glEnableVertexAttribArray(mPositionHandle); 

     GLES20.glUniform4f(mColorUniformLocation, colorArray[0], colorArray[1], colorArray[2], 1f); 

     // This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix 
     // (which currently contains model * view). 
     Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); 

     // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix 
     // (which now contains model * view * projection). 
     Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); 

     GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); 

     GLES20.glLineWidth(1.0f); 
     GLES20.glDrawArrays(GLES20.GL_LINE_LOOP, 0, geometryBuffer.capacity()/mPositionDataSize); 
    } 
} 
+0

Xin chào Hank. Đã đọc câu hỏi của bạn và xem bạn đính kèm hình ảnh và rất quan tâm. Im bắt buộc ngay bây giờ với sự cố hiển thị bản đồ văn phòng nhỏ với hai tầng. Dường như với tôi rằng bạn đính kèm nó chính xác những gì tôi cần, gây ra như tôi hiểu bạn bản đồ là zoomable và xoay. Tôi chỉ tìm kiếm một nơi để bắt đầu - bất kỳ trang web, sách, công nghệ nào về hiển thị bản đồ. Nếu bạn có thông tin, đoạn mã và có thể chỉ cho tôi vào hướng rithg tôi sẽ rất thích ứng. Thx trước. –

Trả lời

5

Những câu trả lời khác ở đây đã nơi rất tốt và hiển thị để xem xét và điều cần được cải thiện. Tôi nghi ngờ sự chậm lại là từ gọi drawPolygon và drawLine hàng nghìn lần trên mỗi khung vẽ (nếu bạn có hàng nghìn đa giác và đường kẻ), và mỗi phương thức gọi phương thức OpenGL nhiều lần cho mỗi lần gọi phương thức. Bạn thực sự muốn thực hiện các cuộc gọi này để bạn vẽ tất cả các đa giác và tất cả các dòng trong các cuộc gọi vẽ riêng lẻ.

Thật khó để xác định thời gian chính xác, OpenGL sẽ thực hiện các cuộc gọi và thậm chí cả trình theo dõi Android cho kết quả không chính xác, từ trải nghiệm của tôi. Những gì bạn có thể làm là thử loại bỏ và thay đổi mã giữa các lần chạy, thời gian lặp lại toàn bộ vòng lặp và xem mọi thứ thay đổi như thế nào.

Thử xóa Thread.currentThread(). SetPriority (Thread.MIN_PRIORITY) ;, và tái kỹ sư ứng dụng để đưa dữ liệu của bạn vào đối tượng bộ đệm đỉnh, ràng buộc với GL_STATIC_DRAW. Vẽ tất cả các dòng với một cuộc gọi vẽ duy nhất. Để tránh thay đổi trạng thái và phá vỡ các cuộc gọi vẽ, bạn có thể đặt màu vào làm thuộc tính thay vì đồng bộ. Bạn cũng có thể tính toán và vượt qua trong ma trận thống nhất một lần cho mỗi tổng thể vẽ thay vì mỗi dòng.

+0

Và nếu bạn không muốn thay đổi các VBO sau khi tạo chúng , GL_STATIC_DRAW cũng hoạt động. –

+0

Tôi đã đặt tất cả FloatBuffers của tôi thành hai FloatBuffers đơn lớn. Tôi bây giờ tự hỏi làm thế nào tôi đi về điều chỉnh chức năng drawPolygon của tôi cho phù hợp với lô? Ngoài ra, nơi tốt nhất để đặt GLES20.glBufferData (mục tiêu, kích thước, dữ liệu, sử dụng) là gì? – Hank

+0

Tôi nên đi vào chi tiết hơn, các đa giác và đường kẻ đang vẽ nhưng bây giờ chúng là một đa giác liên tục và một đường liên tục. Đó là một chút lộn xộn để xem xét. Tuy nhiên vào thời điểm này, nó bây giờ là rất nhanh và panning bản đồ được mịn màng. Cho dù điều này thay đổi bằng cách phá vỡ chúng lên vẫn còn để được nhìn thấy. Tôi có cần gửi GLES một mảng các vị trí bắt đầu hoặc một thứ gì đó dọc theo các dòng đó cho mỗi bộ đệm riêng lẻ trong bộ đệm lớn không? – Hank

0

Bạn đang chạy ứng dụng này trong máy ảo hoặc trên điện thoại thực?

Bạn có thể thêm một số mã để kiểm tra thời gian biểu của các chức năng của bạn không?

Cố gắng tìm hiểu những gì đang diễn ra theo cách đó.

+0

Thiết bị cầm tay, khoảng 1000ms cho mỗi chế độ hiển thị đầy đủ – Hank

+0

Có nhưng bao nhiêu cho mỗi bước. Mất bao lâu trênDrawFrame, drawPolygon và drawLineString lấy mỗi? – Agnfolie

3

Tôi khuyên bạn nên tập trung giới hạn số tiền bạn đang vẽ dựa trên mức thu phóng và chế độ xem thay vì cố gắng tối ưu hóa hiệu suất kết xuất. Rất có thể, bạn không thực hiện quá nhiều cuộc gọi hiển thị không hiệu quả nếu bạn có tới 17.000 đa giác với thời gian phản hồi tốt.

Nhìn vào hình ảnh bạn đã đăng. Nếu bạn đang vẽ 17.000 đa giác và 1.500 dòng ở đó, hầu hết các chi tiết bị lãng phí vì chúng ta không thể thấy mức chi tiết đó đúng không? Tôi chắc chắn không thấy 17.000 đa giác.

Thay vào đó, hãy giữ nguyên chi tiết đầy đủ và viết mã để giới hạn chi tiết dựa trên mức thu phóng. Cách tiếp cận này không được ngạc nhiên gọi là thuật toán level of detail. Nếu bạn đã từng làm nhiều việc với MipMaps dựa trên cùng một hiệu trưởng.

Tôi sẽ tính toán mức độ dữ liệu chi tiết cho tất cả các mức thu phóng mà bạn mong muốn và tham chiếu dữ liệu được lưu trong bộ nhớ cache này dựa trên mức thu phóng hiện tại. Khi người dùng không ở một trong các mức thu phóng rời rạc của bạn, chỉ cần tham khảo mức độ và quy mô gần nhất.

Khi cần có chi tiết cao ở mức thu phóng gần hơn, bạn có thể giữ mọi thứ nhanh chóng bằng cách culling những đường và đa giác nào không cần được hiển thị ở cấp độ dữ liệu chi tiết bằng thuật toán Spatial Partitioning.

Nếu bạn cần làm rõ trên bất kỳ điểm nào, hãy cho tôi biết. Công cụ này rất dễ nói nhưng khó mã hóa. Chúc may mắn!

CHỈNH SỬA:

Một triển khai LoD sẽ tính toán đa giác và vị trí đường dựa trên quy mô ma trận của bạn. Sau đó, loại bỏ bất kỳ điểm nào không đủ xa nhau.Tôi chỉ cần đúc các vị trí dấu chấm động của họ để bắt đầu, và xem nó trông như thế nào. Làm điều này cho một số mức độ mở rộng quy mô. Lưu trữ các kết quả này trong một mảng, sau đó làm tròn bất kỳ mức độ rộng nào bạn đang ở để chọn dữ liệu LoD được lưu trữ gần nhất.

+1

Lol Tôi không thể tin rằng bạn không tính chúng. Tôi đồng ý rất nhiều chi tiết bị lãng phí. Mức độ chi tiết (LOD) có vẻ là nơi tốt nhất để bắt đầu, tôi sẽ xem xét tiêu hủy khi tôi đã sẵn sàng để phóng to. Tôi đã không làm bất cứ điều gì với Mipmaps bằng cách này. Tìm một thuật toán phù hợp với dường như bước tiếp theo, bất kỳ ý tưởng nào để tìm những thuật toán hiện có? Tôi giả sử cho mỗi bộ đệm Float một loại chỉ số thu phóng và phân loại nó trên chỉ mục đó, có thể là một cách để đi, tuy nhiên việc tìm kiếm được ưu tiên hơn một cái khác, nó hoạt động như thế nào? – Hank

+0

Tôi đã thử tìm kiếm các thuật toán LoD hiện có cho các dòng và đưa ra ít. Tôi đã chỉnh sửa câu hỏi của mình để đưa ra giải pháp có thể. Nó phải dễ thực hiện. –

2

Một vài điều nhảy ra khỏi tôi.

1) Không tạo đối tượng trong các thường trình vẽ của bạn như onDrawFrame. Các công cụ lặp lại như

ListIterator<mapLayer> orgNonAssetCatLayersList_it = default_settings.orgNonAssetCatMappableLayers.listIterator(); 

tạo đối tượng và tạo đối tượng trong thói quen vẽ của bạn làm giảm hiệu suất.

2) Giảm thiểu các cuộc gọi OpenGL càng nhiều càng tốt. Java vẫn cần phải vượt qua ranh giới JNI khi bạn thực hiện các cuộc gọi OpenGL, vì vậy nếu bạn có thể đặt mọi thứ vào một số bộ đệm lớn và tránh thay đổi trạng thái OpenGL. Tôi đã cố gắng để tổ chức các dữ liệu vào như một vài bộ đệm có thể rút ra các dòng và một bộ vẽ các đa giác.

Bạn có thể chỉ xem xét hiển thị các phần của dữ liệu ở các mức thu phóng khác nhau. Những người khác có thể có ý tưởng tốt hơn và nếu bạn nhìn xung quanh SO hoặc trực tuyến, tôi chắc chắn bạn sẽ tìm thấy chúng.

3) Và luôn đo lường hiệu suất của bạn để xem các vấn đề thực sự của bạn ở đâu. Android có nhiều công cụ khác nhau (TraceviewSystrace, OpenGL ES Tracer) khả dụng.

Xem để biết thêm mẹo hiệu suất Android nói chung: http://developer.android.com/training/articles/perf-tips.html

+0

Việc đặt một bộ đa giác thành một bộ đệm có vẻ thú vị như thế nào khi nó đã hoàn thành một đa giác và bắt đầu một đa giác khác? – Hank

+1

Tôi không nhận ra bạn đang sử dụng LINE_LOOP/LINE_STRIP và đang nghĩ đến việc sử dụng tam giác thoái hóa với TRIANGLE_STRIP để vẽ nhiều đường. Xem câu hỏi SO này trên chiều rộng dòng: http://stackoverflow.com/questions/14514543/opengl-es-2-0-dynamically-change-line-width –

2

Không ai đang đề cập đến FBO ?? Ý tôi là, LOD sẽ là một cách tiếp cận tốt, nhưng trong một số trường hợp, bạn có thể sử dụng FBO. Nó sẽ phụ thuộc vào nhiều thứ, nhưng bạn nên xem xét chúng!

Bạn có thể hiển thị cảnh lỗ (hoặc một phần của nó) thành đối tượng bộ đệm khung và hiển thị hình ảnh thay vì vẽ cảnh mỗi khung hình. Điều đó làm giảm số lượng đa giác chỉ là một vài (2 cho trường hợp tốt nhất, đó là một hình vuông).

Một vấn đề mới sẽ là cách xử lý việc quét/thu phóng khi bạn cần phải tính toán lại động của fbo. Bạn có thể vẽ hình ảnh blury cho đến khi fbo sẵn sàng hoặc bạn có thể sử dụng các phương pháp nâng cao hơn với tải trước, như chia bản đồ thành hình vuông và tải trước 9 bản đồ (trung tâm và 8 hàng xóm) làm bản đồ google để tải dữ liệu bản đồ.

Bạn cũng sẽ cần phải xem xét mức tiêu thụ bộ nhớ, bạn không thể chỉ vẽ mọi kết hợp với FBO.

Tôi lặp lại, FBO không phải là giải pháp "độc lập", chỉ cần lưu ý để xem bạn có thể sử dụng chúng ở đâu đó không!

Các vấn đề liên quan