刷新三维场景中的HUD层
在以three.js为引擎的微信小游戏中,无法使用dom元素。在我正在开发的小游戏里是把场景以外的文字和按钮等二维信息放置到HUD层的。three.js中的HUD层的实现方式是把脱屏canvas转换为纹理,再将纹理传递给材质,然后用正交投影相机投影到一个平面上。
对于界面的变化(就是对脱屏canvas的重新绘制,如drawImage, fillText等操作),一般情况下用局部更新纹理方案就可以了,就是先重绘,然后基于之前的canvas生成新的纹理,然后把新的纹理传递给之前的材质,如下所示:
updateTexture(){
if (this.hudMat!=null && this.hudMat.map!=null){
this.hudMat.map.dispose()
let hudTexture = new THREE.Texture(this.canvas)
hudTexture.needsUpdate = true
hudTexture.minFilter = THREE.NearestFilter
this.hudMat.map = hudTexture
this.hudMat.needsUpdate = true
}
}
但是,对于界面已绘制元素的隐藏,上述方法失效了。经过探索,我发现可能是由于Frame Buffer的原因, 所有的重绘等同于在之前形成的画面上的一种叠加,而由于HUD层的特殊性(作为前景层),它需要是背景透明的,这样的话透明的叠加绘制无法消除之前形成的画面,界面内容只能越画越多,却无法减少。最终的解决方案是重新生成一个新的脱屏canvas,获取新的绘制上下文来进行彻底的更新。当然从性能上讲,这种更新要沉重一些,所以在我的项目中保留了两个HUD层的更新方法。
three.js通常都是用dom来做界面的,这个界面绘制确实很蛋疼。用sprite不知道性能如何?我的界面比较简单,所以暂时没觉得有性能瓶颈。
重绘ui时 HudContext.clearRect(0, 0, windowWidth, windowHeight)应该就可以了。