Cesium生成高清截图
这里写自定义目录标题
- Cesium生成高清截图
- 桌面端生成图片
- Cesium截图
- 基本实现思路
- 访问足够精细的数据
- 单块截图
- 后台图像融合
- PS
Cesium生成高清截图
由于是项目内容,本文不涉及具体代码实现,仅记录实现思路。
刚接到这个要求的时候,感觉是伪需求。网页端本来就是数据越轻量级越好,加载浏览响应更快。仔细分析的话,其实也有点用处,相比于桌面端截取超高分辨率的图片,类似3D软件渲染图片一样;网页端可以制作一些相对低分辨率的图片,没那么精细,但是相对快,也相对够用。
桌面端生成图片
拿Blender来说,场景制作好后,用渲染器生成图片渲染时,可以看到最终图像是分块渲染的,即对每块图片进行光追生成实际场景的静态图片。即每次生成像素时均需要能够访问到全部的数据,以便和射线求教
Cesium截图
在Cesium中截高清图像时,面临以下问题:
- 场景中的数据均做了LOD处理,即三维球中的数据时通过相机位置来动态加载和淘汰的,因此没法访问所有数据,由于是网页可用资源不如桌面端,也无法访问所有数据的最精细一层,即仅可访问部分数据
- 浏览器端也不推荐进行大文件操作,比如大分辨率的图像解成4通道后,占用内存非常高,内存占用过多,会导致Cesium无法在申请足够的内存用来创建纹理等资源,当Cesium无法创建可用的资源时,弹窗报错,场景就奔溃了。网页环境中可用资源有限。
基本实现思路
访问足够精细的数据
既然无法在整屏中都加载足够精细的数据,那就仿照渲染图片,对当前屏幕分块,比如分为6x6,36小块;在一个小块中加载足够精细的数据,其他区域暂时不加载数据,Cesium中请求相对精细的数据比较容易实现,翻看最基础的类QuadPrimitve
是通过距离相机的距离来计算ScreenSpaceError
就能知道怎么请求更大级别的数据,比如当前屏幕请求影像瓦片为15级,可以修改属性来请求17级;倾斜也是类似的。
仅显示一小块的数据,可以在遍历瓦片时增加一次过滤,先计算将要添加到队列的瓦片在屏幕中的大致范围,不在小块范围内的直接跳过。
单块截图
实际截图的时候需要将加载的一块数据渲染到更大尺寸的纹理上,而不是仅扩大当前Canvas
的尺寸,仅扩大Canvas
的尺寸是渲染了所有块的数据,有效区域的一小块占比仍旧小,而且对于性能较差的机器,一次在WebGL中开辟大尺寸的纹理,会导致Cesium请求的回来的数据无法再开辟纹理。这里采用修改Cesium中投影矩阵的方法来实现仅渲染一小块,正常透视投影是将当前屏幕映射到裁剪空间,也可以将近裁剪面上一小块区域的锥体映射到完整的裁剪空间,即可仅绘制这一块的内容,也就是这一小块的坐标映射后落到[-1,1]
,而不是之前的比如[-0.2,0]
。此时可以将这一小块放大到当前屏幕,直接toBlob
获取内容。
后台图像融合
为了避免在网页端操作大内存,将每次截图的一小块传给后台服务,由后台服务将截取的36小块合并成一张大图返回给前端。前端直接通过后台接口获取图片即可。
PS
- 只请求一小块足够精细的数据
- 修改投影矩阵,仅渲染指定屏幕区域一小块的内容
- 图片融合