para obj developers descargar cambiar android opengl-es

obj - ¿Cómo limitar la velocidad de fotogramas cuando se utiliza GLSurfaceView.RENDERMODE_CONTINUO DE Android?



opengl es 3.1 android download (6)

Cuando usa GLSurfaceView, realiza el dibujo en el OnDrawFrame de su Representante, que se maneja en un hilo separado por GLSurfaceView. Simplemente asegúrese de que cada llamada a onDrawFrame tome (1000 / [frames]) milisegundos, en su caso algo como 33ms.

Para hacer esto: (en tu onDrawFrame)

  1. Mida la hora actual antes de comenzar a dibujar usando System.currentTimeMillis (Llamémoslo startTime)
  2. Realizar el dibujo
  3. Medir el tiempo otra vez (Llamémoslo tiempo final)
  4. deltaT = endTime - starTime
  5. si deltaT <33, sleep (33-deltaT)

Eso es.

Tengo un juego de C ++ corriendo a través de JNI en Android. La velocidad de fotogramas varía de aproximadamente 20-45 fps debido a la complejidad de la escena. Cualquier cosa por encima de 30 fps es una tontería para el juego; es sólo quemar la batería. Me gustaría limitar la velocidad de fotogramas a 30 fps.

  • Podría cambiar a RENDERMODE_WHEN_DIRTY y usar un Timer o ScheduledThreadPoolExecutor para requestRender (). Pero eso agrega una gran cantidad de partes móviles adicionales que pueden o no funcionar de manera consistente y correcta.
  • Intenté inyectar Thread.sleep () cuando las cosas se están ejecutando rápidamente, pero esto no parece funcionar en absoluto para valores de tiempo pequeños. Y puede ser que solo esté haciendo una copia de respaldo de los eventos en la cola, no haciendo una pausa.

¿Hay un método "capFramerate ()" oculto en la API? ¿Alguna forma confiable de hacer esto?


La solución de Fili está fallando para algunas personas, así que sospecho que está durmiendo hasta inmediatamente después de la próxima sincronización, en lugar de hacerlo inmediatamente antes. También siento que mover la suspensión al final de la función daría mejores resultados, ya que allí puede rellenar el cuadro actual antes de la próxima sincronización, en lugar de intentar compensar la anterior. Thread.sleep () es inexacto, pero afortunadamente solo necesitamos que sea preciso para el período vsync más cercano de 1 / 60s. El código LWJGL al que tyrondis publicó un enlace parece demasiado complicado para esta situación, probablemente está diseñado para cuando vsync está deshabilitado o no está disponible, lo que no debería ser el caso en el contexto de esta pregunta.

Intentaría algo como esto:

private long lastTick = System.currentTimeMillis(); public void onDrawFrame(GL10 gl) { UpdateGame(dt); RenderGame(gl); // Subtract 10 from the desired period of 33ms to make generous // allowance for overhead and inaccuracy; vsync will take up the slack long nextTick = lastTick + 23; long now; while ((now = System.currentTimeMillis()) < nextTick) Thread.sleep(nextTick - now); lastTick = now; }


La solución de Mark es casi buena, pero no del todo correcta. El problema es que el intercambio en sí toma una cantidad de tiempo considerable (especialmente si el controlador de video contiene instrucciones de almacenamiento en caché). Por lo tanto, debe tener eso en cuenta o terminará con una velocidad de cuadros inferior a la deseada. Así que la cosa debería ser:

En algún lugar al inicio (como el constructor):

startTime = System.currentTimeMillis();

luego en el bucle de render:

public void onDrawFrame(GL10 gl) { endTime = System.currentTimeMillis(); dt = endTime - startTime; if (dt < 33) Thread.Sleep(33 - dt); startTime = System.currentTimeMillis(); UpdateGame(dt); RenderGame(gl); }

De esta manera, tendrá en cuenta el tiempo que lleva intercambiar los búferes y el tiempo para dibujar el marco.


Si no quieres confiar en Thread.sleep , usa lo siguiente

double frameStartTime = (double) System.nanoTime()/1000000; // start time in milliseconds // using System.currentTimeMillis() is a bad idea // call this when you first start to draw int frameRate = 30; double frameInterval = (double) 1000/frame_rate; // 1s is 1000ms, ms is millisecond // 30 frame per seconds means one frame is 1s/30 = 1000ms/30 public void onDrawFrame(GL10 gl) { double endTime = (double) System.nanoTime()/1000000; double elapsedTime = endTime - frameStartTime; if (elapsed >= frameInterval) { // call GLES20.glClear(...) here UpdateGame(elapsedTime); RenderGame(gl); frameStartTime += frameInterval; } }


También puede intentar y reducir la prioridad del hilo desde onSurfaceCreated ():

Process.setThreadPriority(Process.THREAD_PRIORITY_LESS_FAVORABLE);


La respuesta de Fili me pareció excelente, pero lamentablemente limité el FPS en mi dispositivo Android a 25 FPS, aunque Thread.sleep() 30. Descubrí que Thread.sleep() no funciona con la suficiente precisión y duerme más de lo debido.

Encontré esta implementación del proyecto LWJGL para hacer el trabajo: https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/opengl/Sync.java