草庐IT

Android GLES 2画线闪烁和奇怪的效果

coder 2023-12-23 原文

我正在尝试使用 gles 2 在 android 中绘制一些 3d 线。但它导致了一些奇怪的效果。当我旋转场景/相机时会发生闪烁。但不仅如此,还有一些随机绘制的 2d 线(有时是点)。这是屏幕截图:

虽然这张图片完全没有问题(使用不同的相机角度):

我也尝试过使用 GLES 1 来绘制这些线条并且它起作用了(没有闪烁或随机线条)。也许它与着色器代码有关?顶点着色器取自 android gles 示例,非常简单。

更新: 经过更多尝试,我发现只有当相机偏航(y 轴旋转)超过 90 度时才会发生这种情况。在 0-90 yaw 范围内,线条显示正常。 我究竟做错了什么? 我正在使用 android v4.4.2 在 Galaxy Tab S 上运行该程序。

下面是用于重现错误图像的完整代码:

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

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

还有最重要的部分,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 );
    }
}

最佳答案

我遇到了同样的问题,尤其是三星设备(我有 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;

我希望这会有所帮助(即使答案来得很晚)。

关于Android GLES 2画线闪烁和奇怪的效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29091110/

有关Android GLES 2画线闪烁和奇怪的效果的更多相关文章

  1. ruby-on-rails - 浮点乘法的 Ruby 奇怪问题 - 2

    有没有人用ruby​​解决这个问题:假设我们有:a=8.1999999我们想将它四舍五入为2位小数,即8.20,然后乘以1,000,000得到8,200,000我们是这样做的;(a.round(2)*1000000).to_i但是我们得到的是8199999,为什么?奇怪的是,如果我们乘以1000、100000或10000000而不是1000000,我们会得到正确的结果。有人知道为什么吗?我们正在使用ruby​​1.9.2并尝试使用1.9.3。谢谢! 最佳答案 每当你在计算中得到时髦的数字时使用bigdecimalrequire'bi

  2. ruby - 奇怪的 ruby​​ for 循环行为(为什么这样做有效) - 2

    defreverse(ary)result=[]forresult[0,0]inaryendresultendassert_equal["baz","bar","foo"],reverse(["foo","bar","baz"])这行得通,我想了解原因。有什么解释吗? 最佳答案 如果我使用each而不是for/in重写它,它看起来像这样:defreverse(ary)result=[]#forresult[0,0]inaryary.eachdo|item|result[0,0]=itemendresultendforainb基本上就

  3. ruby-on-rails - ruby数组奇怪的东西(无限数组) - 2

    当我写下面的代码时:x=[1,2,3]x我得到这个输出:[1,2,3,[...]][1,2,3,[...]][1,2,3,[...]]我不应该只得到[1,2,3,[1,2,3]]吗?解释是什么? 最佳答案 这没什么奇怪的。数组的第四个元素就是数组本身,所以当你求第四个元素时,你得到的是数组,当你求第四个元素的第四个元素时,你得到的是数组,当你求第四个元素时,你得到的是数组。第四个元素的第四个元素的第四个元素的元素......你得到了数组。就这么简单。唯一有点不寻常的是Array#to_s检测到这样的递归,而不是进入无限循环,而是返回

  4. ruby - 比较 rspec 中的 float 时的奇怪行为 - 2

    以下测试中的第3个失败:specify{(0.6*2).shouldeql(1.2)}specify{(0.3*3).shouldeql(0.3*3)}specify{(0.3*3).shouldeql(0.9)}#thisonefails这是为什么呢?这是浮点问题还是ruby​​或rspec问题? 最佳答案 从rspec-2.1开始specify{(0.6*2).shouldbe_within(0.01).of(1.2)}在那之前:specify{(0.6*2).shouldbe_close(1.2,0.01)}

  5. ruby - 在不同的文件中设置断点没有效果 - 2

    ruby调试器不会在我在与执行开始时不同的文件中设置的断点处停止。例如,考虑这两个文件,foo.rb:#foo.rbclassFoodefbarputs"baz"endend和main.rb:#main.rbrequire'./foo'Foo.new.bar我使用ruby-rdebug.\main.rb开始调试。现在,当我尝试使用b./foo.rb:4在另一个文件的特定行上设置断点时,我收到消息Setbreakpoint1atfoo.rb:4,但是当我cont时,程序执行到最后,调试器永远不会停止。但是,如果我在main.rb中的一行上打断,例如b./main.rb:3,或者一个方法,

  6. ruby - Rails 3 应用程序的 respond_with 语法有奇怪的行为吗? - 2

    在为提供json的Rails3.0.3应用构建API时,发生了一些意外行为。以下是Controller。问题是关于respond_with。我已经在应用程序Controller中有respond_to:json。createAction正常运行,创建后数据也被发回。但是更新操作的respond_with不会发回任何数据。响应主体为空白。defcreateline=get_lineinput_header=line.input_headers.create(params[:input_header])respond_with(input_header,:location=>api_v1_

  7. arrays - 数组元素赋值的奇怪行为 - 2

    今天我遇到了数组元素赋值的一些奇怪行为:arr=["a","b"]arr2=[1,2]arr.unshift(arr2)#=[[1,2],"a","b"]arr.push(arr2)#=>["a","b",[1,2]]但是,这是有道理的:arr[0,0]=arr2#=>[1,2,"a","b"]我知道在[0,0]中,第一个零是index,第二个是该数组中从index开始的元素数。在我看来它应该与unshift相同,但事实并非如此。谁能解释一下这种行为? 最佳答案 如果我们diveintotherubysourcecode,我们会找到

  8. ruby - 打包的 Ruby 字符串中的奇怪行为 - 2

    我对某些ruby​​行为感到困惑。看下面的代码:[127].pack("C")=="\x7f"#=>true这是有道理的。现在:[128].pack("C")#=>"\x80""\x80"#=>"\x80"[128].pack("C")=="\x80"#=>falsepackoption"C"代表8-bitunsigned(unsignedchar),应该可以存储128的值。两个字符串也打印相同的东西,那么为什么它们不相等呢?这与编码有关吗?我使用的是ruby​​2.0.0p247。 最佳答案 这是错误的,因为编码不同:[128].

  9. ruby-on-rails - Ruby表达式 '-'后留空格的效果 - 2

    今天我在我的Rails控制台中尝试了一些东西,这发生了,2.0.0p247:009>Date.today-29.days=>Fri,07Feb20142.0.0p247:010>Date.today-29.days=>Thu,09Jan2014我很困惑。我可以看到我缺少一些基本的东西。但这让我印象深刻!谁能解释为什么会这样? 最佳答案 实际发生的是这样的:Date.today(-29.days)#=>Fri,07Feb2014today有一个名为start的可选参数,默认为Date::ITALY。Anoptionalargument

  10. Unity 血条及“掉血”缓冲效果 - 2

     视频教程:https://www.bilibili.com/video/BV1WJ411778C/?spm_id_from=333.999.0.0&vd_source=4a4c35da6aef7094d5990c213c39aa09使用素材(推荐使用GitZipforgithub下载):https://github.com/zheyuanzhou/Youtube-Unity-Tutorial/tree/master/EP45_Health%20Bar/Sprites效果如下图所示:首先在场景中创建一个新的Canvas,并命名为HeathBar,并创建三个Image作为前者的子物体,分别命名为

随机推荐