Android Opengl图形故障 [英] Android Opengl Graphical Glitch
问题描述
在Android上使用Opengl 2.0,我正在尝试创建一个类来帮助我从纹理图集绘制方形精灵.我遇到了一些奇怪的图形故障(有时线条/正方形缺少窗体纹理),尤其是当设备从睡眠状态带入时.
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 an example of the problem after waking the phone from sleep:
和我的渲染器代码.
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);
}
}
推荐答案
听起来您正在丢失设备上下文,您已在评论中推测了该上下文.您已加载的所有内容现在都可能是垃圾.
It sounds like you're losing your device context, which you've surmised in the comments. Anything you've loaded is probably now garbage.
当EGL上下文丢失时,所有OpenGL资源(例如纹理) 与该上下文关联的内容将被自动删除.
When the EGL context is lost, all OpenGL resources (such as textures) that are associated with that context will be automatically deleted.
一些有用的链接:
- Android:何时会销毁OpenGL上下文?
- 在Android暂停时丢失OpenGL上下文的解决方法?
- 防止Android GL上下文丢失
- 恢复后在Android中丢失OpenGL纹理
- 从活动返回时当前没有openGL上下文吗?
- 防止破坏OpenGL上下文的onPause
- 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
这篇关于Android Opengl图形故障的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!