可以看到新更新的poi,在计算纹理坐标时候,有一部分像素包含了其他poi的像素。这个问题是因为新poi的区域刚好叠在了先前poi的边界上,那么我们只要给新的poi加一点buffer,这个buffer是白素透明区域,buffer会把之前的poi像素覆盖掉,而我们计算纹理坐标时,只取poi的边界,那么就可以解决这个问题。
那么首先绘制的时候就要保留buffer
上传的时候使用buffer
计算纹理坐标时,排除buffer
六、局部更新带来的性能问题 根据目前的结果,局部更新能后解决crash的问题,但是带来了严重的性能开销,与同事应用局部更新提升性能的结果相反。这个问题还要继续跟踪。
目前发现问题是因为使用了getImageData来获取数据,然后传递到gpu中,非ios设备用这种方式有时候getImageData的开销特别大,而ios设备相对好一些。
测试发现非ios设备直接上传一张大纹理的效果反而比getImageData这种方式更好。但是依然不如之前上传多个canvas的性能。而在iphone5的测试机和iphone6的机器上性能比之前直接上传多个canvas的方式好一些,且没有崩溃问题。但是在岳阳的iphone6 plus 16g内存的手机上发现用具局部纹理更新性能很差,而且经常崩溃。
后来发现原因是因为,虽然getImageData在IOS上性能好过非IOS设备,但性能开销仍然比较大,所以当场景中POI很多时,仍然会引起主线程卡顿,甚至计算太密集引起浏览器崩溃。其中层尝试使用cesium方式,每个poi创建新的canvas,将canvas进行局部上传,本以为这种方式不需要getImageData会更快一些,然而实践发现每次创建canvas设置参数的过程更耗时。
最终的方案是仍然使用getImageData,但是将getImageData的过程分块处理,每50ms处理一次,分块放到场景中,这样就解决密集计算引起的崩溃问题,虽然增加了控制成本,但是能够有效解决IOS崩溃问题。有趣的是在安卓上getImageData方式开销很大,即使分块也不适合,而且安卓用一张大纹理的方式来处理,会发现很多POI绘制效果不好。
最终方案是,IOS使用getImageData局部纹理+分块加载方式绘制POI。安卓使用POI独立创建canvas+全量加载方式。(安卓不适用分块加载,是为了尽快把所有POI呈现给用户)
七、文字黑色描边问题这个问题自始至终困扰我好久一直没找到黑边的原因;
将原始的canvas导出后发现这是因为原始的canvas就有一层边界
曾经怀疑是minFilter的设置不对在pc端纹理使用NEARESTFilter方式取值发现的确能够消除黑边,然而移动端仍然会出现黑边,最后使用颜色混合公式解决问题。
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
在Three.js中需要设置SpriteMaterial的blending为CustomBlending
但是使用上述方式同样引来新问题,设计反映poi的icon四周被裁切掉,