Ich habe eine OpenGL-App für Anfänger erstellt, die einen sich drehenden Stier zeigt, der aus einer obj-Datei geladen wurde. Es hat gut funktioniert und ich habe es meinen Freunden gezeigt. Gestern habe ich die App geöffnet und die Ansicht wird nicht mehr aktualisiert. Wenn ich die Home-Taste drücke und dann erneut auf die App tippe, wird die Ansicht aktualisiert, sodass ich weiß, dass die Hauptschleife aktiv ist.
Ich ging nach Hause und steckte es in Android Studio, um zu bestätigen, dass der Render-Thread einwandfrei ausgelöst wird und view.requestRender();
auch aufgerufen wird.
Ich habe keine Ahnung, warum das nicht mehr funktioniert.
Hier ist mein Android-Fragment, das die Ansicht und den Renderer lädt
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
/**
* Inflate the layout for this fragment
*/
View root = inflater.inflate(R.layout.glfragment, container, false);
GLSurfaceView glview = (GLSurfaceView)root.findViewById(R.id.surface_view);
Log.i("Method", "OpenGLFragment::onCreateView()");
Context context = this.getActivity().getApplicationContext();
MyRenderer renderer = new MyRenderer(context);
glview.setEGLContextClientVersion(2);
glview.setRenderer(renderer);
glview.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
loadMeshes(context); // loads obj file into variable tourus
renderer.addToScene(tourus);
update = new GraphicsThread(glview);
update.start();
return root;
}
@Override
public void onDestroyView() {
if(update != null) {
update.quit();
}
super.onDestroyView();
}
Hier ist der Grafik-Thread:
public class GraphicsThread extends Thread {
private GLSurfaceView.Renderer renderer;
private GLSurfaceView view;
private boolean isRunning;
public GraphicsThread(GLSurfaceView view) {
this.view = view;
this.isRunning = true;
}
@Override
public void run() {
while (this.isRunning) {
view.requestRender(); // I verified this loop is executed just fine
}
}
public void quit() {
this.isRunning = false;
}
}
Hier ist MyRenderer
Code
public class MyRenderer implements GLSurfaceView.Renderer {
private int program; // default shader program
private List<Mesh> drawables;
private Context context;
private long lastFrameTime;
private RenderInfo info; // MVP and Light matrices
private Bitmap bg;
public MyRenderer(Context context) {
this.drawables = new ArrayList<>();
this.context = context;
this.lastFrameTime = 0;
this.info = null;
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
info = new RenderInfo(context);
GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLES20.glEnable(GLES20.GL_CULL_FACE);
}
public void onDrawFrame(GL10 unused){
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
float elapsed = getElapsedTime();
float rot = 10.0f*elapsed;
for(Mesh m : drawables) {
m.rotateX(rot);
m.draw(info, elapsed);
}
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
if(width > 0 && height > 0) {
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
info.resizePerspective(left, right, 1, -1);
}
}
public void addToScene(Mesh mesh) {
drawables.add(mesh);
}
private float getElapsedTime() {
long currentTime = SystemClock.elapsedRealtime();
float elapsed = (float)(currentTime - lastFrameTime) / 1000.0f; //convert ms to seconds
lastFrameTime = currentTime;
return elapsed;
}
}
Zum Schluss zeichne ich hier meine Maschen. RenderInfo
hat Weltinformationen wie Kamera MVP Matrix und Lichter und ihre Matrizen. Nichts im Zusammenhang mit dem Problem.
public void draw(RenderInfo info, float elapsed) {
if(!loaded) {
Log.d("Mesh", "failed to draw");
return;
};
final int program = info.getProgram();
int position = GLES20.glGetAttribLocation(program, "a_Position");
int normal = GLES20.glGetAttribLocation(program, "a_Normal");
int aColor = GLES20.glGetAttribLocation(program, "a_Color");
//int textcoord = GLES20.glGetAttribLocation(program, "a_TexCoordinate");
GLES20.glEnableVertexAttribArray(position);
GLES20.glVertexAttribPointer(position, 3, GLES20.GL_FLOAT, false, 3 * 4, verticesBuffer);
GLES20.glEnableVertexAttribArray(aColor);
GLES20.glVertexAttribPointer(aColor, 4, GLES20.GL_FLOAT, true, 4*4, colorBuffer);
//GLES20.glEnableVertexAttribArray(normal);
//GLES20.glVertexAttribPointer(normal, 3, GLES20.GL_FLOAT, false, 3 * 4, normalBuffer);
float[] modelMatrix = new float[16];
Matrix.setIdentityM(modelMatrix, 0);
Matrix.setRotateM(modelMatrix, 0, rotX , 1.0f, 0.0f, 0.0f);
//Matrix.setRotateM(modelMatrix, 0, rotY , 0.0f, 1.0f, 0.0f);
//Matrix.setRotateM(modelMatrix, 0, rotZ , 0.0f, 0.0f, 1.0f);
float[] mvpMatrix = info.getMVP(modelMatrix);
int MVP = GLES20.glGetUniformLocation(program, "u_MVP");
GLES20.glUniformMatrix4fv(MVP, 1, false, mvpMatrix, 0);
float[] mvMatrix = info.getMV();
int MV = GLES20.glGetUniformLocation(program, "u_MV");
GLES20.glUniformMatrix4fv(MV, 1, false, mvMatrix, 0);
int lightM = GLES20.glGetAttribLocation(program, "u_LightPos");
GLES20.glUniformMatrix4fv(lightM, 1, false, info.getLightMatrix(), 0);
int lightCol = GLES20.glGetAttribLocation(program, "u_LightCol");
GLES20.glUniform4fv(lightCol, 1, info.getLightColor(), 0);
Log.d("boogio", "u_LightCol is: " + Integer.toString(lightCol));
GLES20.glDrawElements(GLES20.GL_TRIANGLES, facesList.size() * 3, GLES20.GL_UNSIGNED_SHORT, facesBuffer);
GLES20.glDisableVertexAttribArray(position);
GLES20.glDisableVertexAttribArray(aColor);
//GLES20.glDisableVertexAttribArray(normal);
}
TL; DR: App wird gut gerendert und zum Aktualisieren verwendet. Plötzlich wird die App nicht mehr visuell aktualisiert (keine Neuzeichnungen). Es wird nur neu gezeichnet, wenn die App für 1 Frame verliert und den Fokus wiedererlangt. Keine Ahnung warum.
Sie veröffentlichen nicht den gesamten Code, daher ist es unmöglich, die Situation zu reproduzieren. Alles, was ich tun kann, um Ihnen zu helfen, ist, einige Dinge vorzuschlagen.
Zunächst sollten Sie der GLView mitteilen, dass der OpenGL-Kontext mithilfe des setPreservceEGLContext beibehalten werden soll . Falls sich die Situation dadurch nicht beheben lässt, ist es besser, die DEBUG-Ablaufverfolgung im OpenGL ES-Kontext mithilfe der setDebugFlas- Methode zu aktivieren .
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
/**
* Inflate the layout for this fragment
*/
View root = inflater.inflate(R.layout.glfragment, container, false);
GLSurfaceView glview = (GLSurfaceView)root.findViewById(R.id.surface_view);
Log.i("Method", "OpenGLFragment::onCreateView()");
Context context = this.getActivity().getApplicationContext();
MyRenderer renderer = new MyRenderer(context);
glview.setEGLContextClientVersion(2);
// added code
glview.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR); // enable log
glview.setPreserveEGLContextOnPause(true); // default is false
glview.setRenderer(renderer);
glview.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
loadMeshes(context); // loads obj file into variable tourus
renderer.addToScene(tourus);
update = new GraphicsThread(glview);
update.start();
return root;
}
Dadurch werden Ihrer App in weitere Debug-Informationen hinzugefügt logcat
(ich hoffe, Sie wissen bereits, was es ist). Ich denke, Sie werden einige Fehler finden (Zeilen mit OPEN GL-Fehler .. etwas).
Ich vermute, dass Sie die Aktivität erneut öffnen. Der OpenGL-Kontext versucht, Ressourcen zu verwenden, die nicht mehr gültig sind (da der OpenGL-Kontext zerstört wird). Ein typisches Beispiel für Ressourcen, die Sie während der Kontexterstellung neu verwalten müssen, sind Textur- und Shader-Programme.
Fügen Sie einfach einige Log-Debug-Informationen zu Graphic Thread hinzu:
public class GraphicsThread extends Thread {
private GLSurfaceView.Renderer renderer;
private GLSurfaceView view;
private boolean isRunning;
public GraphicsThread(GLSurfaceView view) {
this.view = view;
this.isRunning = true;
Log.i("GraphicsThread", "GraphicsThread::constructor()");
}
@Override
public void run() {
while (this.isRunning) {
Log.i("GraphicsThread", "requestRender");
view.requestRender(); // I verified this loop is executed just fine
}
}
public void quit() {
this.isRunning = false;
Log.i("GraphicsThread", "GraphicsThread::quit()");
}
}
Mithilfe der Protokollinformationen in GraphicThread können Sie überprüfen, ob der Thread wie vorgesehen funktioniert.
glview.setPreserveEGLContextOnPause(true);
Schont Ressourcen, wenn Sie den Kontext zerstören (Bildschirmrotation oder Aktivität im Hintergrund): Die Alternative besteht darin, alle Ressourcen neu zu erstellen und neu zu laden. Ich nehme an, es wurde gemacht, weil Android-Geräte am Anfang keinen Speicher hatten, um den GLContext zu erhalten, als das GLView zerstört wurde.RENDERMODE_CONTINUOUSLY
fordert GLView auf, eine Szene zu zeichnen, wann immer dies möglich ist (und dies ist der beste Weg für das, was ich weiß).Ich hoffe meine Vorschläge können Ihnen helfen.
Dieser Artikel stammt aus dem Internet. Bitte geben Sie beim Nachdruck die Quelle an.
Bei Verstößen wenden Sie sich bitte [email protected] Löschen.
Lass mich ein paar Worte sagen