2015-03-17 4 views
3

Я пытаюсь нарисовать некоторые 3d линии в android, используя gles 2. Но это привело к некоторым странным эффектам. Мерцание происходит, когда я поворачиваю сцену/камеру. Но не только это, но и некоторые строки, нарисованные в 2d (иногда точки) наугад. Это скриншот: enter image description hereAndroid GLES 2 рисовать линию мерцания и странные эффекты

В то время как это изображение не показывает никаких проблем (с использованием другого угла камеры): enter image description here

Я также попытался использовать Глес-рисовать эти линии, и она работала (не мерцание или случайные линии). Возможно, это как-то связано с шейдерным кодом? Вершинный шейдер был взят из примера android gles, который очень прост.

Обновление: После нескольких попыток, я обнаружил, что это происходит только тогда, когда рыскание камеры (ось оси y) превышает 90 градусов. В диапазоне от 0 до 90 вольт линии отображаются нормально. Что я делаю неправильно? Я запускаю программу на Galaxy Tab S с android v4.4.2.

Вот весь код, используемый для воспроизведения ошибочное изображение:

Основная деятельность: вид

package com.mycompany.bug_test; 

import android.opengl.GLSurfaceView; 
import android.support.v7.app.ActionBarActivity; 
import android.os.Bundle; 

public class OpenGLES20Activity extends ActionBarActivity { 

    private GLSurfaceView mGLView = null; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     if (mGLView == null) { 
      mGLView = new MyGLSurfaceView(this); 
     } 
     setContentView(mGLView); 
    } 
} 

Поверхность:

package com.mycompany.bug_test; 

import android.content.Context; 
import android.opengl.GLSurfaceView; 
import android.view.MotionEvent; 

class MyGLSurfaceView extends GLSurfaceView { 

    private final MyGLRenderer mRenderer; 

    public MyGLSurfaceView(Context context) { 
     super(context); 

     setEGLContextClientVersion(2); 

     mRenderer = new MyGLRenderer(); 
     setRenderer(mRenderer); 
    } 

    private final float TOUCH_SCALE_FACTOR = 360.0f; 
    private float mPreviousX; 
    private float mPreviousY; 

    @Override 
    public boolean onTouchEvent(MotionEvent e) { 

     float x = e.getX(); 
     float y = e.getY(); 

     int action_type = e.getAction(); 
     if (action_type == MotionEvent.ACTION_MOVE) { 
      float dx = x - mPreviousX; 
      float dy = y - mPreviousY; 

      final float div_mag = 10; 
      float min_dx = dx; 
      if (min_dx > (getRootView().getWidth()/div_mag)) {min_dx = (getRootView().getWidth()/div_mag);} 
      if (min_dx < -(getRootView().getWidth()/div_mag)) {min_dx = -(getRootView().getWidth()/div_mag);} 
      float min_dy = dy; 
      if (min_dy > (getRootView().getHeight()/div_mag)) {min_dy = (getRootView().getHeight()/div_mag);} 
      if (min_dy < -(getRootView().getHeight()/div_mag)) {min_dy = -(getRootView().getHeight()/div_mag);} 

      float new_yaw = ( mRenderer.cam_yaw - (min_dx * TOUCH_SCALE_FACTOR/getRootView().getWidth()) ) % 360; 
      float new_pitch = mRenderer.cam_pitch + (min_dy * TOUCH_SCALE_FACTOR/getRootView().getHeight()); 
      if (new_pitch > 89) { 
       new_pitch = 89; 
      } 
      if (new_pitch < -89) { 
       new_pitch = -89; 
      } 


      synchronized (mRenderer.CAM_LOCK) { 
       mRenderer.cam_yaw = new_yaw; 
       mRenderer.cam_pitch = new_pitch; 
      } 
      System.out.println("Yaw=" + new_yaw + " Pitch=" + new_pitch); 
     } 

     mPreviousX = x; 
     mPreviousY = y; 
     return true; 
    } 
} 

И самая важная часть, GL рендерер:

package com.mycompany.bug_test; 

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

import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.FloatBuffer; 

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

public class MyGLRenderer implements GLSurfaceView.Renderer { 

    private final String vertexShaderCode = 
      "uniform mat4 uMVPMatrix;" + 
      "attribute vec4 vPosition;" + 
      "void main() {" + 
      " gl_Position = uMVPMatrix * vPosition;" + 
      "}"; 

    private final String fragmentShaderCode = 
      "precision mediump float;" + 
      "uniform vec4 vColor;" + 
      "void main() {" + 
      " gl_FragColor = vColor;" + 
      "}"; 

    private int mProgram; 

    private int mMVPMatrixHandle; 
    private int mPositionHandle; 
    private int mColorHandle; 



    private final float[] mProjectionMatrix = new float[16]; 
    private final float[] mViewMatrix = new float[16]; 
    float viewAspect; 
    float fovy = 45; 
    float fovx = 45; 

    final Object CAM_LOCK = new Object(); 
    float cam_pos_x = 0; 
    float cam_pos_y = 0; 
    float cam_pos_z = 0; 
    float fcs_pos_x = 0; 
    float fcs_pos_y = 0; 
    float fcs_pos_z = 0; 
    //Try Yaw=246.22672 Pitch=21.992342 with cam_focus_range = 175 to get visible error. 
    float cam_pitch = 21.992342f; 
    float cam_yaw = 246.22672f; 
    float cam_focus_range = 175; 



    final float line_gap = 100; 
    final float line_length = 6000; 

    private final int COORDS_PER_VERTEX = 3; 
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 

    private FloatBuffer vertexBuffer; 
    private int vertexCount = 0; 


    public MyGLRenderer() { 
     float[] GMrkLines = new float[(int)((line_length/line_gap) + 1) * 2 * 2 * COORDS_PER_VERTEX ]; 

     int __P = 0; 
     for (int ln=0; ln<((line_length/line_gap) + 1); ln++) { 
      GMrkLines[__P++] = (float)(line_length /2);        //x 
      GMrkLines[__P++] = 0;             //y 
      GMrkLines[__P++] = (float)(line_gap *ln - line_length /2);    //z 
      vertexCount++; 
      GMrkLines[__P++] = (float)(-line_length /2);       //x 
      GMrkLines[__P++] = 0;             //y 
      GMrkLines[__P++] = (float)(line_gap *ln - line_length /2);    //z 
      vertexCount++; 

      GMrkLines[__P++] = (float)(line_gap *ln - line_length /2);    //x 
      GMrkLines[__P++] = 0;             //y 
      GMrkLines[__P++] = (float)(line_length /2);        //z 
      vertexCount++; 
      GMrkLines[__P++] = (float)(line_gap *ln - line_length /2);    //x 
      GMrkLines[__P++] = 0;             //y 
      GMrkLines[__P++] = (float)(-line_length /2);       //z 
      vertexCount++; 
     } 

     System.out.println("Vertex count=" + vertexCount); 

     { 
      ByteBuffer bb = ByteBuffer.allocateDirect(GMrkLines.length * 4); 
      bb.order(ByteOrder.nativeOrder()); 
      vertexBuffer = bb.asFloatBuffer(); 
      vertexBuffer.put(GMrkLines); 
      vertexBuffer.position(0); 
     } 
    } 


    @Override 
    public void onSurfaceCreated(GL10 unused, EGLConfig config) { 
     int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); 
     int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); 
     mProgram = GLES20.glCreateProgram(); 

     GLES20.glAttachShader(mProgram, vertexShader); 
     GLES20.glAttachShader(mProgram, fragmentShader); 
     GLES20.glLinkProgram(mProgram); 

     GLES20.glUseProgram(mProgram); 

     mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 
     mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 
     mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); 

     GLES20.glUniform4fv(mColorHandle, 1, new float[]{0.3f, 0.3f, 0.3f, 1}, 0); 


     GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
     GLES20.glEnable(GLES20.GL_DEPTH_TEST); 
     GLES20.glDepthFunc(GLES20.GL_LEQUAL); 
     GLES20.glLineWidth(4); 
    } 

    @Override 
    public void onDrawFrame(GL10 unused) { 
     float _cam_pos_x; 
     float _cam_pos_y; 
     float _cam_pos_z; 
     float _fcs_pos_x; 
     float _fcs_pos_y; 
     float _fcs_pos_z; 
     float _cam_pitch; 
     float _cam_yaw; 
     synchronized (CAM_LOCK) { 
      _cam_pos_x = cam_pos_x; 
      _cam_pos_y = cam_pos_y; 
      _cam_pos_z = cam_pos_z; 
      _fcs_pos_x = fcs_pos_x; 
      _fcs_pos_y = fcs_pos_y; 
      _fcs_pos_z = fcs_pos_z; 
      _cam_pitch = cam_pitch; 
      _cam_yaw = cam_yaw; 
     } 


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


     _fcs_pos_x = 0; 
     _fcs_pos_y = 0; 
     _fcs_pos_z = 0; 
     _cam_pos_y = (float) (_fcs_pos_y + (cam_focus_range * Math.sin(Math.toRadians(_cam_pitch)))); 
     double cam_to_focus_horz = cam_focus_range * Math.cos(Math.toRadians(_cam_pitch)); 
     _cam_pos_x = (float) (_fcs_pos_x + (cam_to_focus_horz * Math.cos(Math.toRadians(_cam_yaw)))); 
     _cam_pos_z = (float) (_fcs_pos_z + (cam_to_focus_horz * Math.sin(Math.toRadians(_cam_yaw)))); 

     Matrix.setLookAtM(mViewMatrix, 0, _cam_pos_x, _cam_pos_y,_cam_pos_z, _fcs_pos_x, _fcs_pos_y, _fcs_pos_z, 0, 1, 0); 


     { 
      float[] mMVPMatrix = new float[16]; 
      Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); 
      GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); 

      GLES20.glEnableVertexAttribArray(mPositionHandle); 

      GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 
        vertexStride, vertexBuffer); 
      GLES20.glDrawArrays(GLES20.GL_LINES, 0, vertexCount); 

      GLES20.glDisableVertexAttribArray(mPositionHandle); 
     } 
    } 

    @Override 
    public void onSurfaceChanged(GL10 unused, int width, int height) { 
     if (height <= 0) { // avoid a divide by zero error! 
      height = 1; 
     } 
     viewAspect = (float) width/(float) height; 
     fovx = fovy * viewAspect; 

     GLES20.glViewport(0, 0, width, height); 
     GLU_perspective(mProjectionMatrix, 0, fovy, viewAspect, 1.0f, 8000.0f); 
    } 


    public static int loadShader(int type, String shaderCode) { 
     int shader = GLES20.glCreateShader(type); 

     GLES20.glShaderSource(shader, shaderCode); 
     GLES20.glCompileShader(shader); 

     int[] _param = new int[4]; 
     GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, _param, 0); 
     System.out.println("Shader no : " + shader); 
     System.out.println("Compile status = " + _param[0] + " (GL_TRUE=" + GLES20.GL_TRUE + ")"); 
     System.out.println("ERR : " + GLES20.glGetShaderInfoLog(shader)); 

     return shader; 
    } 

    void GLU_perspective(float[] RetMtx, int offset, float fovY, float aspect, float zNear, float zFar) 
    { 
     float fW, fH; 

     fH = (float) (Math.tan(fovY/360 * Math.PI) * zNear); 
     fW = fH * aspect; 

     Matrix.frustumM(RetMtx, offset, -fW, fW, -fH, fH, zNear, zFar); 
    } 
} 
+0

Я попытался изменить точность на highp для обоих шейдеров, но изменений нет (все еще мерцает). Кто-нибудь пробовал мой код в другой среде? Сообщите, если вы столкнулись с этой проблемой в разных условиях. Это исключает вину за окружающую среду. –

ответ

1

Я столкнулся с такой же проблемой, особенно с устройствами Samsung (у меня было 3 из них, показывающих одни и те же проблемы). Оказалось, что линии рисования с GL_LINE_STRIP или GL_LINES приводят к артефактам и мерцанию, которые вы показываете на скриншотах. Но только если линия пересекает плоскость камеры и только если первая координата линии находится за плоскостью камеры, а вторая координата находится перед плоскостью камеры. Когда все наоборот - проблем нет.

По-моему, это не имеет смысла вообще, и, похоже, это проблема с драйвером - в коде отсутствует ошибка.

Как обходной путь я позволяю вершинному шейдеру обнаруживать это созвездие, а затем переворачивать вершины. Обнаружение выполняется путем проверки знака компонента z-масштабирования матрицы [2] [2]. В моем случае вершины являются {0,0,1} и {0,0, -1} - поэтому переключение может быть легко выполнено путем отрицания значений вершин.

// Vertex shader snippet 
cPosition = vPosition; 
voMatrix = viewMatrix * objMatrix; 
if (voMatrix [2][2] < 0.0) cPosition = -vPosition; 

Надеюсь, это поможет (даже если ответ приходит довольно поздно).