Android Opengl Graphical Glitch

你离开我真会死。 提交于 2020-01-15 11:53:27

问题


Using Opengl 2.0 on android I am trying to create a class to help me draw square sprites from a texture atlas. I'm getting some weird graphical glitches(sometimes lines/ squares missing form textures), especially when the device is brought from sleep.

Here is how it should look:

Here is an example of the problem after waking the phone from sleep:

and my code for the Renderer.

package com.krazy.androidopengl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.os.SystemClock;


public class GameRenderer implements GLSurfaceView.Renderer 
{   
private int spriteWidth, spriteHeight;
private int spriteRows,spriteColumns;

private Bitmap atlas;

private float mScale;

private float[] spritePositionData = new float[12];
private float[] cubeTextureCoordinateData = new float[12];

/** Used for debug logs. */
private static final String TAG = "LessonFourRenderer";

private final Context mActivityContext;

/**
 * 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];


/** Store our model data in a float buffer. */
private FloatBuffer mCubePositions;
private FloatBuffer mCubeTextureCoordinates;

/** This will be used to pass in the transformation matrix. */
private int mMVPMatrixHandle;

/** This will be used to pass in the modelview matrix. */
private int mMVMatrixHandle;


/** This will be used to pass in the texture. */
private int mTextureUniformHandle;

/** This will be used to pass in model position information. */
private int mPositionHandle;


/** This will be used to pass in model texture coordinate information. */
private int mTextureCoordinateHandle;

/** How many bytes per float. */
private final int mBytesPerFloat = 4;   

/** Size of the position data in elements. */
private final int mPositionDataSize = 3;    

/** Size of the texture coordinate data in elements. */
private final int mTextureCoordinateDataSize = 2;

/** This is a handle to our cube shading program. */
private int mProgramHandle;

/** This is a handle to our texture data. */
private int mTextureDataHandle;

/**
 * Initialize the model data.
 */


private Drawer drawer;

public GameRenderer(final Context activityContext, Drawer d)
{   

    mActivityContext = activityContext;

    drawer = d;

}

@Override
public void onSurfaceCreated(GL10
        glUnused, EGLConfig config) 
{
    // Set the background clear color to black.
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    // Use culling to remove back faces.
    GLES20.glEnable(GLES20.GL_CULL_FACE);

    // Enable depth testing
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);

    // Enable texture mapping
    GLES20.glEnable(GLES20.GL_TEXTURE_2D);

    // Position the eye in front of the origin.
    final float eyeX = 0.0f;
    final float eyeY = 0.0f;
    final float eyeZ = -0.5f;

    // Facing negative because of anti clockwise triangles are only visible in that direction
    // We are looking toward the distance
    final float lookX = 0.0f;
    final float lookY = 0.0f;
    final float lookZ = -1.0f;

    // Set our up vector. This is where our head would be pointing were we holding the camera.
    final float upX = 0.0f;
    final float upY = 1.0f;
    final float upZ = 0.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 = getVertexShader();          
    final String fragmentShader = getFragmentShader();          

    final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);       
    final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);     

    mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, 
            new String[] {"a_Position",  "a_Color", "a_Normal", "a_TexCoordinate"});

    // Load the texture
    mTextureDataHandle = loadTexture(atlas);


}   

@Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) 
{
    // Set the OpenGL viewport to the same size as the surface.
    GLES20.glViewport(0, 0, width, height);

    // Create a new perspective projection matrix. The height will stay the same
    // while the width will vary as per aspect ratio.
    final float left = 0f;
    final float right = width;
    final float bottom = 0f;
    final float top = height;
    final float near = 0f;
    final float far = 10.0f;
    Matrix.orthoM(mProjectionMatrix, 0, left, right, bottom, top, near, far);

}   

public void setAtlas(int w, int h, Bitmap bitmap, float scale)
{
    spriteWidth = w;
    spriteHeight = h;
    spriteRows = bitmap.getHeight()/spriteHeight;
    spriteColumns = bitmap.getWidth()/spriteWidth;
    atlas = bitmap; 
    mScale = scale;

    spritePositionData = spriteCoords(spriteWidth * scale,spriteHeight * scale);

    // Initialize the buffer.
    mCubePositions = ByteBuffer.allocateDirect(spritePositionData.length * mBytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();                            
    mCubePositions.put(spritePositionData).position(0); 

    // Initialize the texture buffer.
    mCubeTextureCoordinates = ByteBuffer.allocateDirect(12 * mBytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
}


@Override
public void onDrawFrame(GL10 glUnused) 
{
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);                    


    // Set our per-vertex lighting program.
    GLES20.glUseProgram(mProgramHandle);

    // Set program handles for drawing.
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
    mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix"); 
    mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");
    mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");

    // Set the active texture unit to texture unit 0.
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

    // Bind the texture to this unit.
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);

    // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
    GLES20.glUniform1i(mTextureUniformHandle, 0);                            

    // Pass on drawing to Drawer
    drawer.onDrawFrame(this);
}               

/**
 * Draws a cube.
 */         
public void drawSprite(float x, float y, int t, float scale)
{   
    if(Math.abs(scale-1f) > 0.00001)
    {
        spritePositionData = spriteCoords(spriteWidth * scale,spriteHeight * scale);
        mCubePositions.put(spritePositionData).position(0);
    }
    else
    {
        spritePositionData = spriteCoords(spriteWidth * mScale,spriteHeight * mScale);
        mCubePositions.put(spritePositionData).position(0);
    }
    int row = t/spriteColumns -1;
    int column = (t-1)%spriteColumns;

    float rowHeight = 1f/spriteRows;
    float columnWidth = 1f/spriteColumns;

    cubeTextureCoordinateData[0] = column*columnWidth;
    cubeTextureCoordinateData[1] = row*rowHeight;
    cubeTextureCoordinateData[2] = column*columnWidth;
    cubeTextureCoordinateData[3] =(row+1)*rowHeight;
    cubeTextureCoordinateData[4] =(column+1)*columnWidth;
    cubeTextureCoordinateData[5] = row*rowHeight;
    cubeTextureCoordinateData[6] =column*columnWidth;
    cubeTextureCoordinateData[7] = (row+1)*rowHeight;
    cubeTextureCoordinateData[8] = (column+1)*columnWidth;
    cubeTextureCoordinateData[9] = (row+1)*rowHeight;
    cubeTextureCoordinateData[10] =(column+1)*columnWidth;
    cubeTextureCoordinateData[11] = row*rowHeight;

    mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);

    // Translate/ Rotate      
    Matrix.setIdentityM(mModelMatrix, 0);
    Matrix.translateM(mModelMatrix, 0, x, y, -1f);

    // Pass in the position information
    mCubePositions.position(0);     
    GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
            0, mCubePositions);        

    GLES20.glEnableVertexAttribArray(mPositionHandle);        

    // Pass in the texture coordinate information
    mCubeTextureCoordinates.position(0);
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 
            0, mCubeTextureCoordinates);

    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);

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

    // Pass in the modelview matrix.
    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 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);

    // Pass in the combined matrix.
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);

    // Draw the cube.
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 36); 
}   

public static int loadTexture(Bitmap bitmap)
{
    final int[] textureHandle = new int[1];

    GLES20.glGenTextures(1, textureHandle, 0);

    if (textureHandle[0] != 0)
    {

        // Bind to the texture in OpenGL
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

        // Set filtering
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

        // Load the bitmap into the bound texture.
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        // Recycle the bitmap, since its data has been loaded into OpenGL.
        bitmap.recycle();                       
    }

    if (textureHandle[0] == 0)
    {
        throw new RuntimeException("Error loading texture.");
    }

    return textureHandle[0];
}

private float[] spriteCoords(float x, float y)
{
    x /= 2;
    y /= 2;
    final float[] spritePositionData =
        {
            // In OpenGL counter-clockwise winding is default. This means that when we look at a triangle, 
            // if the points are counter-clockwise we are looking at the "front". If not we are looking at
            // the back. OpenGL has an optimization where all back-facing triangles are culled, since they
            // usually represent the backside of an object and aren't visible anyways.

            -x, y, 0f,              
            -x, -y, 0f,
            x, y, 0f, 
            -x, -y, 0f,                 
            x, -y, 0f,
            x, y,0f,
        };

    return spritePositionData;
}

protected String getVertexShader()
{
    return RawResourceReader.readTextFileFromRawResource(mActivityContext, R.raw.per_pixel_vertex_shader);
}

protected String getFragmentShader()
{
    return RawResourceReader.readTextFileFromRawResource(mActivityContext, R.raw.per_pixel_fragment_shader);
}
}

回答1:


It sounds like you're losing your device context, which you've surmised in the comments. Anything you've loaded is probably now garbage.

From the GLSurfaceView.Renderer doc:

When the EGL context is lost, all OpenGL resources (such as textures) that are associated with that context will be automatically deleted.

Some useful links:

  • Android: When is OpenGL context destroyed?
  • Workaround to losing the OpenGL context when Android pauses?
  • Preventing Android GL Context loss
  • Losing OpenGL Textures in Android after a resume
  • No current openGL context when returning from activity?
  • Prevent onPause from trashing OpenGL Context


来源:https://stackoverflow.com/questions/12015963/android-opengl-graphical-glitch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!