Com*_*che 19 java android opengl-es opengl-es-2.0
我在OpenGL中平滑滚动有问题(在SGS2和ACE上测试)
我创建了简单的应用程序 - 只有固定速度的水平滚动图像,或者只有一个图像(播放器)通过加速器移动,但它的运动不顺畅:-(
我试过了许多代码但不满意......
首先我尝试使用GLSurfaceView.RENDERMODE_CONTINUOUSLY并将所有代码放到onDrawFrame:
public void onDrawFrame(GL10 gl)
{
updateGame(gl, 0.017f);
drawGame(gl);
}
Run Code Online (Sandbox Code Playgroud)
这是最简单,最绝对的顺畅! - 但它取决于硬件速度(=无用)
public void onDrawFrame(GL10 gl)
{
frameTime = SystemClock.elapsedRealtime();
elapsedTime = (frameTime - lastTime) / 1000;
updateGame(gl, elapsedTime);
drawGame(gl);
lastTime = frameTime;
}
Run Code Online (Sandbox Code Playgroud)
这是最好的,但它不像以前那样流畅,有时轻弹
我试过GLSurfaceView.RENDERMODE_WHEN_DIRTY,在onDrawFrame我只有绘图对象和这个代码在单独的线程中:
while (true)
{
updateGame(renderer, 0.017f);
mGLSurfaceView.requestRender();
next_game_tick += SKIP_TICKS;
sleep_time = next_game_tick - System.currentTimeMillis();
if (sleep_time >= 0)
{
try
{
Thread.sleep(sleep_time);
}
catch (Exception e) {}
}
else
{
Log.d("running behind: ", String.valueOf(sleep_time));
}
}
Run Code Online (Sandbox Code Playgroud)
这不是很顺利,并且"跑在后面"不是问题
我的目标是像上面的第一个代码示例中的平滑图像移动.
可能的错误是在我看的其他地方.拜托,有人可以帮帮我吗?
最好使用RENDERMODE_WHEN_DIRTY或RENDERMODE_CONTINUOUSLY吗?
谢谢.
小智 34
几天我一直在与同样的问题作斗争.循环看起来很平滑而没有任何Android时间参考,但是一旦它包含任何类型的"时间同步",android开发控件之外的外部因素会给最终结果带来严重的不连续性.
基本上,这些因素是:
该问题独立于绘图技术(绘图,openGL 1.0/1.1和2.0)和游戏循环方法(固定时间步长,插值,可变时间步长).和你一样,我正在尝试Thread.sleep,疯狂的插值,计时器等.无论你做什么,我们都无法控制这些因素.
根据该网站上的许多问答,制作流畅连续动画的基本规则是:
当然,你在发布这个问题之前做了很多以前的工作,优化你的updateGame()和drawGame()(没有明显的GC和相对恒定的执行时间),以便在主循环中获得平滑的动画,如你所说:简单而绝对的顺畅".
你的具有变量stepTime的特殊情况并没有与realTime事件(如音乐)完美同步的特殊要求,解决方案很简单:"平滑步骤时间变量".
该解决方案适用于其他游戏循环方案(具有可变渲染的固定时间步长),并且易于移植概念(平滑updateGame产生的位移量和跨越几个帧的实时时钟.)
// avoid GC in your threads. declare nonprimitive variables out of onDraw
float smoothedDeltaRealTime_ms=17.5f; // initial value, Optionally you can save the new computed value (will change with each hardware) in Preferences to optimize the first drawing frames
float movAverageDeltaTime_ms=smoothedDeltaRealTime_ms; // mov Average start with default value
long lastRealTimeMeasurement_ms; // temporal storage for last time measurement
// smooth constant elements to play with
static final float movAveragePeriod=40; // #frames involved in average calc (suggested values 5-100)
static final float smoothFactor=0.1f; // adjusting ratio (suggested values 0.01-0.5)
// sample with opengl. Works with canvas drawing: public void OnDraw(Canvas c)
public void onDrawFrame(GL10 gl){
updateGame(gl, smoothedDeltaRealTime_ms); // divide 1000 if your UpdateGame routine is waiting seconds instead mili-seconds.
drawGame(gl);
// Moving average calc
long currTimePick_ms=SystemClock.uptimeMillis();
float realTimeElapsed_ms;
if (lastRealTimeMeasurement_ms>0){
realTimeElapsed_ms=(currTimePick_ms - lastRealTimeMeasurement_ms);
} else {
realTimeElapsed_ms=smoothedDeltaRealTime_ms; // just the first time
}
movAverageDeltaTime_ms=(realTimeElapsed_ms + movAverageDeltaTime_ms*(movAveragePeriod-1))/movAveragePeriod;
// Calc a better aproximation for smooth stepTime
smoothedDeltaRealTime_ms=smoothedDeltaRealTime_ms +(movAverageDeltaTime_ms - smoothedDeltaRealTime_ms)* smoothFactor;
lastRealTimeMeasurement_ms=currTimePick_ms;
}
// Optional: check if the smoothedDeltaRealTIme_ms is too different from original and save it in Permanent preferences for further use.
Run Code Online (Sandbox Code Playgroud)
对于固定时间步骤方案,可以实现中间updateGame以改善结果:
float totalVirtualRealTime_ms=0;
float speedAdjustments_ms=0; // to introduce a virtual Time for the animation (reduce or increase animation speed)
float totalAnimationTime_ms=0;
float fixedStepAnimation_ms=20; // 20ms for a 50FPS descriptive animation
int currVirtualAnimationFrame=0; // useful if the updateGameFixedStep routine ask for a frame number
private void updateGame(){
totalVirtualRealTime_ms+=smoothedDeltaRealTime_ms + speedAdjustments_ms;
while (totalVirtualRealTime_ms> totalAnimationTime_ms){
totalAnimationTime_ms+=fixedStepAnimation_ms;
currVirtualAnimationFrame++;
// original updateGame with fixed step
updateGameFixedStep(currVirtualAnimationFrame);
}
float interpolationRatio=(totalAnimationTime_ms-totalVirtualRealTime_ms)/fixedStepAnimation_ms;
Interpolation(interpolationRatio);
}
Run Code Online (Sandbox Code Playgroud)
使用以下设备测试canvas和openGlES10绘图:SG SII(57 FPS),SG Note(57 FPS),SG标签(60 FPS),在Windows XP(8 FPS)上运行的无品牌Android 2.3(43 FPS)慢速模拟器.测试平台沿着实际物理参数(km/h和G)中指定的路径移动大约45个对象+ 1个巨大背景(来自70MP源图像的纹理),在几个设备之间没有尖峰或轻弹(好吧,模拟器上的8个FPS)看起来不太好,但它按预期以恒定速度流动)
检查android如何报告时间的图表.有时候Android会报告一个较大的增量时间,而下一个循环只会比平均值小,这意味着读取realTime值会产生偏移.

更多细节:

如何在使用Android的GLSurfaceView.RENDERMODE_CONTINUOUSLY时限制帧率?
System.currentTimeMillis vs System.nanoTime
System.currentTimeMillis()方法真的返回当前时间吗?
| 归档时间: |
|
| 查看次数: |
13005 次 |
| 最近记录: |