NOTE: 动画特效的原理:简单的:逐帧绘制,复杂的 调研3D库的实现
目前的调研是两个方面,一,windows的 GDI 二,安卓的绘制
一:
最近用GDI+绘图,初次使用,感觉绘制效率不太满足要求。搜索了些相关资料,多数也只谈到了使用双缓冲(仅仅是解决了画面的闪烁问题)。了解到DirectX绘制要快的多(picasa 就使用的DirectX),但好象没有这个必要,毕竟偶只是在窗口中绘制有动画效果的2维图片。认真研究了一番,也总结了一些提高效率的方法。如果哪位高手有更好的建议,希望指点一二,偶的这篇文章算是抛砖引玉:)
先描述下问题域:在一幅背景画面上有几个圆形按钮,这几个圆形按钮绕成一个大圆环,要做出的效果是:点击按钮,所有的按钮都沿大圆环转动。当然,其过程要平滑。
起初,不知道绘制图片的时间大多浪费的什么地方,一步步摸索,相关资料也是少的可怜啊!
我的解决方法:
1、在对话框初始化的时候,加载图片(包括背景图片、圆形按钮的图片),用类成员指针记录下来。
2、在OnPaint中,把背景和圆形按钮的图片都绘制一次,在内存中把按钮绘制到背景图片的相应的位置上(位置已经计算好了),再一次性画到屏幕上。像这样:
CDC* pDC = GetDC();
Graphics graphics (pDC-> GetSafeHdc());
// 设定裁剪区域(这个区域我剪切成了一个圆环,目的就是提高绘制速度,反复绘制时,只绘制这个圆环区域)
if (!bDrawBkGrd)
graphics.SetClip (m_pClipRgn);
// 内存中绘制
Image* pImg = m_pBkImg-> Clone (); // 不消耗CPU时间
Graphics* pGraphics = graphics.FromImage (pImg);
for (int i = 0; i < 7; i++)
{
pGraphics-> DrawImage (m_pImg[i], m_place[i].X, m_place[i].Y, m_pImg[i]-> GetWidth(), m_pImg[i]-> GetHeight());
}
// 绘制到屏幕
graphics.DrawImage (pImg, 0, 0, pImg-> GetWidth(), pImg-> GetHeight());
delete pGraphics;
delete pImg;
ReleaseDC (pDC);
这样反复绘制时的效果不会闪烁,呵呵。
3、但绘制速度不快,大概是12.5帧/秒。背景图片是1027 X 768的PNG图片,按钮图片是100 X 110的jpg图片,我的机器是P4 1.7G,512内存,显卡是NVIDIA TNT2,绘制效率低了点。
4、一定还能提高帧速,俺研究了半天,试了下CachedBitmap,代码改为:
CDC* pDC = GetDC();
Graphics graphics (pDC-> GetSafeHdc());
// 设定裁剪区域(这个区域我剪切成了一个圆环,目的就是提高绘制速度,反复绘制时,只绘制这个圆环区域)
if (!bDrawBkGrd)
graphics.SetClip (m_pClipRgn);
// 内存中绘制
Image* pImg = m_pBkImg-> Clone (); // 不消耗CPU时间
Graphics* pGraphics = graphics.FromImage (pImg);
for (int i = 0; i < 7; i++)
{
CachedBitmap cachedBitmap((Bitmap*)m_pImg[i], &graphics);
pGraphics-> DrawCachedBitmap (&cachedBitmap, m_place[i].X, m_place[i].Y);
}
// 绘制到屏幕
graphics.DrawImage (pImg, 0, 0, pImg-> GetWidth(), pImg-> GetHeight());
delete pGraphics;
delete pImg;
ReleaseDC (pDC);
果然!呵呵,帧速提高到了15.5帧/秒
5、总结了这些经验,希望能够和大家分享下。上面的代码是包装在一个函数中的。让触发事件来调用,在OnPaint中也有调用。如果哪位高手有什么好的建议的话,还望不吝赐教!帧速越高越好啊,不知道用GDI+速度能够提高到多少:)24帧以上最好了!
偶贴的上一个帖子名字是“GDI+的绘图效率问题,大家讨论一下吧!”。在其中解决的效率问题远远不够。现在工作中的模块做的差不多了,总结了一下最近得到的经验结论,贴出来大家进一步讨论下。。。也算是在优快云上得到了诸多帮助的一个小小的回报:) 在交流中共同进步吧!
不知道为什么MS把GDI+中的 DrawImage 这个函数效率做的这么低,(当然了,它的优点是使用方便、支持透明PNG格式等等,还有什么优点有经验的朋友不妨贴出来共享下:) 那么到底有多低呢?我也不知道,所以刚才做了个试验。让DrawImage和::BitBlt速度做了个比较!
先说下我的机器配置:2*3.0G Intel CPU,1G的内存,Intel945的显卡。在一个窗口中用DrawImage画一个590X480大小的PNG图片,画了100次,用了.......长时间;用BitBlt画同样大小的bmp图片,画了1000次,用了...长时间,多少时间我不管了,帧速我是计算出来了大约是 DrawImage 16.5帧/秒,BitBlt 2169.2帧/秒 。没错!确实是这个数字。我数学学的不好,就用计算器算了一下BitBlt的绘图速度是DrawImage的131.5倍。。。
代码也贴出来吧,写的比较粗糙:
void CCmpBitBltToDrawImageDlg::OnBnClickedButton1()
{
Bitmap* ppng = NULL;
CDC* pDC = GetDC ();
Graphics* pGrp = Graphics::FromHDC (pDC-> GetSafeHdc ());
ppng = Bitmap::FromFile (L"res//tray.png");
clock_t start = clock ();
for (int i = 0; i < 100; i++)
{
pGrp-> DrawImage (ppng, 0, 0);
}
delete pGrp;
ReleaseDC (pDC);
delete ppng;
clock_t time = clock () - start;
float ftime = time / 1000.0f;
CString str;
str.Format ("%.1f frame per second/n", 100 / ftime);
AfxMessageBox (str);
}
void CCmpBitBltToDrawImageDlg::OnBnClickedButton2()
{
CDC memDC;
CBitmap bmp;
if (0 == bmp.LoadBitmap (IDB_BITMAP1))