使用OpenGL在Android中进行动态图形绘制

5

我想绘制来自蓝牙设备的实时数据。我有一个蓝牙设备,手机将连接并读取来自其的数据。该数据是一些传感器的电压水平,并具有每秒300个样本的采样率。大多数绘图库(如aiChart、Androidplot、achartengine等)都无法处理这么多的数据和重新绘制图形。因此,我研究了openGL和Android NDK,似乎可以使用其中之一来绘制具有我要求的采样率的图形。是否有人有在android / Java中绘制openGL线条图的示例代码和/或NDK代码示例?

1个回答

3
我们可以通过创建一个带有多个页面的点数组类,并在OpenGL中使用偏移量绘制来实现类似的功能,以便当前点始终处于相同位置。
这个想法是使用固定大小的数组和单独的计数器,以避免出现内存分配问题,从而导致垃圾回收启动。一旦一页已满,就循环到下一页并显示旧的一页。如果你有5页,你可以向其中一张写入数据,将另外3页显示出来,并将最后一张批量写入SD卡上的SQLite数据库中的另一个线程中,以便稍后可以将所有数据提取出来。
只要你只有一个线程写入数组,你就可以轻松地完成类似的操作。
arrayPoint[] p;
....
int currentPos = 0;
arrayPoint current = p[currentPos];

..... 
while(....

if(current.end < current.max)
{
      .... get datax and datay
     current.end++;
     current.x[current.end] = datax;
     current.y[current.end] = datay;
}
else
{
     currentPos = getNextPos();
     current = p[currentPos];
     current.end = -1; // truncate the array without actually freeing or allocating mem
     ..... flip volatile bool to let other thread know its ok to get exclusive access to its data etc      
}

这个工具非常快,并且可以满足您的需求。您可以在画布上输出为一个点,或者在OpenGL ES中进行绘制。

希望对您有所帮助。


你的想法很有道理,关于写入5页数据...实际上最后一页可以被抛到一个侧面的进程/线程中去写入SD卡。虽然你的代码方法我不会采用,因为那似乎太慢了。由于数据可能是可变大小和速率,并且在你有10个新数据点时推送一个数组并重新索引会非常慢。这就是为什么如果我们谈论的是Java代码,我会使用LinkedLists。 - JPM
你的OpenGL代码中有一个问题,你是用Android/Java还是C/NDK编写的? - JPM
嗨,JPM。我选择静态数组的原因是为了避免gc成为我的主要瓶颈。我从个人经验中发现,动态类会创建成千上万个对象,这会杀死保持快速数据流畅的任何机会。使用带有索引到末尾的静态数组意味着只需一次操作即可将其重置(通过将end设置为-1),并且随着添加而覆盖数据。玩一下DDMS,您可以跟踪您正在创建对象的位置。我用Android Java写了所有内容,一旦去除了GC,它就足够快了。 - Kactus
我应该提到,设备处理opengl的能力因设备而异,但您可以通过减少重复调用来进行优化。例如,每帧一组启用,然后执行所有的翻译和DrawElements,最后一组禁用。不要绑定更多的内容。如果您的数据集比较小,那么您需要测试是否最好为每个数据集绘制点,还是重新创建一个页面的顶点缓冲区,但在我的案例中,我使用了单个点与翻译。再次使用DDMS进行方法分析,看看您在哪里可以获得收益。 - Kactus
我对OpenGL还很陌生,不太明白你在说什么,但我相信你。我只是想找出实时数据动态折线图绘制的最佳方法。 - JPM
这种数组回收(可以这么说)似乎是一个很好的想法,可以保护免受GC暂停的影响。我在类似数据速率的FFT中使用了类似的方法,它起作用了。总之,首先优化您的对象创建,然后再进行绘制调用优化。第一步会让它工作,第二步只会让它更快。 - Igor Čordaš

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接