opengl es - Android GLES 2 draw line flicker and strange effects -
i trying draw 3d lines in android using gles 2. resulted in strange effects. flicker happens when rotate scene/camera. not that, there lines drawn in 2d (sometime dots) @ random. screenshot:
while image shows no problem @ (using different camera angle):
i've tried use gles 1 draw these lines , worked (no flicker or random lines). perhaps have shader code? vertex shader taken android gles example simple.
update: after more tries, found happens when camera yaw (y axis rotary) more 90 degree. within range of 0-90 yaw, lines display normally. doing wrong? i'm running program on galaxy tab s android v4.4.2.
here whole code used reproduce erroneous image:
main activity:
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); } }
surface view:
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; } }
and important part, gl renderer:
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 cam_focus_range = 175 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; (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 divide 0 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 experienced same problem samsung devices (i had 3 of them showing same issues). turned out drawing lines gl_line_strip or gl_lines results in artefacts , flickering show in screenshots. if line traverses camera plane , if first coordinate of line behind camera's plane , second coordinate in front of camera's plane. when it's other way round - no problem.
in opinion not make sense @ , seems driver problem - there no error in code.
as workaround let vertex shader detect constellation , flip vertices. detection done checking sign of matrice's z-scaling component [2][2]. in case vertices {0,0,1} , {0,0,-1} - flipping can done negating vertex values.
// vertex shader snippet cposition = vposition; vomatrix = viewmatrix * objmatrix; if ( vomatrix [2][2] < 0.0 ) cposition = -vposition;
i hope helps (even if answer comes in quite late).
Comments
Post a Comment