2013-07-10 7 views
5

アンドロイドでOpenGL-ESを使用してマップを作成しました。私の地図はうまく表示されています。タッチイベントの処理を追加したので、移動したり動かしたりすることもできます。OpenGL(ES)2でレンダリングをスピードアップする方法Android

ただし、約1秒の遅延時間があります。私は明らかにイメージのパンニングを可能な限り滑らかにしたいと思います。

私はかなり多くのベクトルデータを表示していますが、インタラクティブ性をスムーズにするための代替手段が必要です.17000ポリゴン(土地区画またはロット)と約1500行(道路中心線)があります。アプリケーションの起動時にFloatBuffersを保持するリストに両方ともプリロードされます。私がマップアクティビティに行くと、レンダラーはこれらのリストを繰り返します。下のコードを参照してください。

私はスピードをどのように拾うことができるかについてのいくつかの指摘を本当に感謝します。

(ちょうど別のノートに、私が今に焦点を当てていますすべてのマップをパンされ、彼らは働いていない、スケール検出器および任意の回転コードを無視してください。)

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

ハローハンク。あなたは質問を読んで、あなたに画像添付を見て、とても興味がありました。 Imは現在、2階建ての小規模オフィス地図のレンダリング問題を強いられています。それは、私があなたが地図が理解できるように、私が必要とするものを正確に添付しているように思えます。地図のレンダリングに関するサイト、書籍、技術など、始める場所を探しています。あなたがコードスニペットの情報を持っていて、私を指向させることができるなら、私は非常にうまくいくでしょう。あらかじめThx。 –

答えて

5

ここで他の答えはすでに非常に良いショー見て場所や改善すべきものです。私は減速がdrawPolygonとdrawLineを描画フレーム(何千ものポリゴンとラインがある場合)ごとに数千回呼び出していると思われ、メソッド呼び出しごとにOpenGLメソッドを何度も呼び出しています。これらの呼び出しをバッチして、すべてのポリゴンとすべての線を単一の描画呼び出しで描画する必要があります。

正確に時間を計るのは難しいですが、OpenGLは呼び出しをバッファし、Androidトレーサさえも私の経験からは不正確な結果を出します。あなたができることは、ラン間のコードを削除して変更し、ドローループ全体を時間をかけて変えていく方法です。

Thread.currentThread()。setPriority(Thread.MIN_PRIORITY);を削除して、データをGL_STATIC_DRAWでバインドされた頂点バッファオブジェクトに配置するようにアプリケーションを再設計してください。 1回の描画呼び出しですべての行を描画します。状態の変化を避け、ドローコールを分割するために、カラーをユニフォームとしてではなく属性として配置することができます。ラインごとではなく、全体の描画ごとに一度、行列の均一性を計算して渡すこともできます。

+0

そして、VBOを作成した後に変更したくない、GL_STATIC_DRAWも動作します。 –

+0

私はすべての私のFloatBuffersを2つの大きな単一のFloatBuffersに入れました。私はバッチに合わせてdrawPolygon関数をどのように調整するのか、今私は不思議に思っていますか?また、GLES20.glBufferData(ターゲット、サイズ、データ、使用法)を設定する最適な場所はどこですか? – Hank

+0

ポリゴンと線が描画されているはずですが、ポリゴンと線は1つの連続したポリゴンと1つの連続した線になります。それは見ることの混乱のビットです。しかし、現時点では非常に高速で、地図をパンすることはスムーズです。これを分割して変更するかどうかはまだ分かりません。大規模なバッファ内の個々のバッファごとに、GLESに開始位置の配列またはそれらの行に沿った配列を送る必要がありますか? – Hank

0

これをVMまたは実際のハンドセットで実行していますか?

機能のレンダリング時間をチェックするコードを追加できますか?

時間のかかることを調べてみてください。

+0

ハンドセット、1回のレンダリングあたり約1000msレンダー – Hank

+0

はい、1ステップあたりどれくらいですか? onDrawFrame、drawPolygon、drawLineStringはどれくらいかかりますか? – Agnfolie

3

レンダリングの効率を最適化するのではなく、ズームレベルとビューポートに基づいて描画する量を制限することに焦点を当ててください。適度な応答時間で最大17,000のポリゴンを使用すると、レンダリングの呼び出しが非効率的になりすぎることはありません。

投稿した画像を見てください。 17,000のポリゴンと1,500の線をレンダリングしている場合、詳細のレベルが正しく表示されないため、ほとんどのディテールは無駄になります。私は確かに17,000のポリゴンは見ません。

代わりに、完全な詳細をロードしたままにし、ズームレベルに基づいて詳細を制限するコードを作成します。この手法は、意外にもlevel of detailアルゴリズムと呼ばれています。 MipMapsを使って同じことをしたことがある人は、同じプリンシパルに基づいています。

私は望むすべてのズームレベルの詳細データのレベルを計算し、現在のズームレベルに基づいてこのキャッシュデータを参照します。ユーザーが個別のズームレベルにない場合は、最も近いズームレベルを参照してください。

近いズームレベルで詳細が必要な場合はcullingアルゴリズムでSpatial Partitioningアルゴリズムを使用して詳細レベルのデータでレンダリングする必要がない線やポリゴンを高速に保つことができます。

ご要望があれば、私に教えてください。このことは簡単に話すことができますが、コードを書くのは難しいです。がんばろう!

EDIT:

つのLOD実装は、あなたの行列のスケーリングに基づいて、ポリゴンやライン位置を計算することであろう。次に、十分に離れていない点は破棄します。私は浮動小数点の位置をintにキャストして開始し、それがどのように見えるかを見ます。いくつかのスケーリングレベルでこれを行います。これらの結果を配列に格納し、次に最も近いキャッシュされたLoDデータを選択するスケーリングレベルを丸めます。

+1

Lol私はあなたがそれらを数えなかったと信じられない。私は細部の多くが無駄であることに同意する。詳細レベル(LOD)が最適な場所であるように見えます。一度ズームインする準備ができたら、私はカリングを見ます。途中でミップマップで何もしていません。適合するアルゴリズムを見つけることは、次のステップと思われます。既存のものを見つけるためのアイデアはありますか?私は各フロートバッファに一種のズームインデックスを与え、そのインデックス上でソートするといいでしょうが、別のものよりも優先されるものを見つけることはできますが、どのように機能しますか? – Hank

+0

私は、ラインのための既存のLoDアルゴリズムを探してみましたが、ほとんど出てこなかった。私は可能な解決策を含めるために私の質問を編集しました。実装が容易でなければなりません。 –

2

私はいくつかのことを飛び出します。

1)onDrawFrameなどの描画ルーチンにオブジェクトを作成しないでください。

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

などのイテレータは、描画ルーチンでオブジェクトを作成してオブジェクトを作成するとパフォーマンスが低下します。

2)できるだけ多くのOpenGL呼び出しを最小限に抑えます。 OpenGLの呼び出しを行うときにJavaがJNIの境界を越えなければならないので、すべてをいくつかの大きなバイトバッファに入れてOpenGLの状態を変更することはできません。私は線を描画する可能なバッファーと、ポリゴンを描画する別のセットにデータを整理しようとしました。

データの一部のみをさまざまなズームレベルでレンダリングすることを検討したい場合があります。他の人はもっと良いアイデアを持っているかもしれません。あなたがSOやオンラインを見ても、あなたはそれらを見つけることができます。

3)実際の問題がどこにあるかを確認するために、パフォーマンスを常に測定してください。 Androidにはさまざまなツール(TraceviewSystrace,OpenGL ES Tracer)が用意されています。

より一般的なAndroidのパフォーマンスのヒントを参照してください:http://developer.android.com/training/articles/perf-tips.html

+0

ポリゴンを1つのバッファに配置することは、1つのポリゴンを終了して別のポリゴンを開始したことをどのように知るのでしょうか? – Hank

+1

私はあなたがLINE_LOOP/LINE_STRIPを使っていることに気付かず、TRIANGLE_STRIPで縮退三角形を使って複数の線を描くことを考えていました。行幅に関するこのような質問を参照してください:http://stackoverflow.com/questions/14514543/opengl-es-2-0-dynamically-change-line-width –

2

誰もFBOのことを言及していませんか?つまり、LODは良いアプローチですが、場合によってはFBOを使用することもできます。それは多くのものに依存しますが、それらを考慮する必要があります!

ホールシーン(またはその一部)をフレームバッファオブジェクトにレンダリングし、シーンごとにフレームを描画する代わりにイメージを表示することができます。これにより、ポリゴン数がわずかに減少します(最良の場合は2、1つの正方形)。

新しい問題は、fboを動的に再計算する必要があるようにパン/ズームを処理する方法です。 fboの準備が整うか、または地図を四角で分割してそれらのうちの9つ(中央と8つの近傍)を事前ロードしてより高度なアプローチを取ることができるようになるまで、bluryイメージを描画できます。データをマップします。

また、メモリ消費量を調べる必要があります。すべての組み合わせをFBOに描画することはできません。

FBOは「スタンドアロン」ソリューションではありません。どこかで使用できるかどうかを確認してください。

関連する問題