PDA

View Full Version : Disappearing lines and random lines when drawing using GL_LINES in GLES 2



dave_xenos
06-11-2015, 04:01 AM
I am trying to draw some lines (with 3d projection) in android using GLES 2. But it resulted in some strange effects. Some lines disappear when i rotate the scene/camera. But not only that, there are also some random lines drawn (somewhat 2d projected to the camera).

This is the screenshot of the issue:
1866

And here is another screenshot taken using different camera angle that happens to display the lines normally:
1867

The second image is what I expect to happen at all camera angle. But it only happens at some angles.
Lines disappear at an angle and reappear at different angle causing a 'flickering' effect while rotating the scene/camera.

As you can see in the second image, there are lines forming a grid/net. Some lines parallel to x axis and some other parallel to z axis.
My camera yaws by rotating around Y axis. Yaw=0 degree means camera look down X+ axis, yaw=90 degree means camera look down Z+ axis.
Yaw values have interesting connection to the issue:
-At yaw 0-90 all lines will flicker randomly.
-At yaw 90-180 only lines parallel to Z axis will flicker randomly.
-At yaw 180-270 all the lines will always displays normally.
-At yaw 270-360 only lines parallel to X axis will flicker randomly.

I reckon this might be a faulty shader code. Can anyone clarify what I did wrong?
Here is my rendering code:

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 = 200;
float cam_pos_z = 0;
float fcs_pos_x = 0;
float fcs_pos_y = 0;
float fcs_pos_z = 0;
float cam_pitch = -30;
float cam_yaw = 200;
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);
}
}


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

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_y = (float) ( _cam_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) );
_fcs_pos_x = (float) ( _cam_pos_x + (cam_to_focus_horz * Math.cos( Math.toRadians(_cam_yaw) )));
_fcs_pos_z = (float) ( _cam_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) ;
}
}

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



I am using Android Studio to create the program. Here are some other related classes if you need to reproduce the problem:

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;

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;

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



I used a very simple shader there. I'm not sure what went wrong.
I have tried to draw these lines using GLES 1 and it worked (no flicker or random lines). So it might be the shader's fault.
Or is it something else?
If it's relevant I'm running the program on Galaxy Tab S with android v4.4.2.


Thanks in advance!

Dark Photon
06-13-2015, 07:52 AM
I can't easy run your code, so try glDisable( GL_DEPTH_TEST ).

dave_xenos
06-15-2015, 02:42 AM
I have tried disabling depth test. It didn't work, still the same issue.
Do you see anything wrong in my rendering code (shader programs, matrix multiplications, etc)?
Looking at the first image, I think it might be something to do with the matrices being used by the shader (if the shader program is correct).
All method related to my matrix are done using android.opengl.Matrix. To be specific the methods are : setLookAtM, frustumM and multiplyMM.
Did I somehow misuse them?

I'm sorry if the code isn't easy to read (just point out what isn't clear and I'll explain). The program actually only consist of these three java files/classes.
Is it possible to upload the project file here? If you have Android Studio, I'd be happy to post the project file especially designed to reproduce the problem.

Or perhaps we can work the other way... Can you provide me a working code to draw 3d lines like these? I'll run the code here. And if it doesn't work then perhaps I can start blaming hardware...


Discovered additional trait to the issue : The lines drawn must be really long for the issue to occur. (the line vertices must be really out of perspective)
For example, in my code above I used line_length = 6000 (with line_gap = 100).
But if you change line_length to 250 (with line_gap = 5) the lines will be drawn normally on all angles.

GClements
06-15-2015, 03:48 AM
I reckon this might be a faulty shader code.

I'm fairly sure it isn't. My suspicion is a driver bug. The symptoms suggest something that's going wrong internally rather than anything that could be caused by the data.

You could try changing the line width to see if that has an effect.

You could also try the OpenGL ES forum (https://www.khronos.org/message_boards/).