今天看到前同事出去开公司搞了一个桌面3D宠物,感觉有点意思,以前就想过桌面版的任天狗online,没有想到已经有人搞起来了,“不是我不明白,是世界变化快”啊,所谓3D渲染的桌面宠物,就是类似office助手那种桌面动画(桌面精灵),其实它也是一个窗口,不同的是,是一个shape会改变的不规则窗口,office助手是2D图形,如果换成3D渲染一只宠物,我就称其“3D渲染的桌面宠物”。

 

先说说2D桌面精灵的实现,在2k的系统以后,有一个非常好用的函数,就是UpdateLayeredWindow,只要每次传递给他一个内容不同的dc,该函数就会根据dc的bitmap和key color,把桌面的shape修改为dc的样子,所以对于2D的桌面精灵就是定时修改dc的内容,然后调用UpdateLayeredWindow就可以了。与简单的2D桌面精灵不同的是,3D渲染对shape的变化率要求比较高(取决于fps),而得到3D渲染的rt则受到硬件特性的限制,我们都知道直接lock back buffer或者rt都是很慢,更不用提将rt变化为dc,所以要解决3D渲染转换可以使用的dc,首先要解决的就是速度问题。

 

解决速度问题,我想到了2种方法,第一就是完全软件渲染,摒弃对硬件的依赖,因为一般桌面精灵(即使是3D)对渲染质量不会太高,完全软件渲染的速度是完全可以接受的,无非是变换和光栅化,网络上也有一些纯软件实现的3D framework;第二种方法就是想办法优化从硬件中访问rt的速度,这也是我努力的方向,毕竟能用现成的技术直接渲染桌面精灵是再好不过了,经过不断尝试,总算解决了问题,步骤如下:

1)创建rt,渲染所有图形到rt;

2)创建offscreen surface,把rt的内容通过GetRenderTargetData函数导入到surface;

3.1) 如果需要同桌面alpha混合,lock surface,创建32bit bitmap,select到mem dc;

3.2) 如果不需要alpha混合(可能会有锯齿,或者不会半透明),直接surface->getdc;

4) 使用上述dc调用UpdateLayeredWindow函数,收工。

 

这种方法在我的8800和7600的卡上,通过测试,其关键的时间消耗可能在步骤2)上,之前我直接lock rt,发现很慢,每次lock获取dc需要200ms,而通过一个offscreen surface转换则几乎没有时间消耗,当然GetRenderTargetData函数的效率我没有办法预估在不同card上的表现,如果在某些卡上效率不理想,则只有考虑方法1)了。

image

这是运行的效果图,由于没有模型动画,用了一个简单旋转三角形表示,原理一样。

点击这里下载例子,修改.jpg为.exe。