FME将osgb数据转换成3dtiles数据
The following article is from FME软件 Author FME
前不久,终于对osgb以及3dtiles的数据结构有了足够的了解,成功地利用FME将osgb数据转换成了3dtiles数据。于是,我开心地决定先来写一下如何将osgb转换成3dtiles数据。
为了让大家能够比较详细的了解这两个数据格式,该系列文章一共分为上下两篇,我将会从osgb与3dtiles的数据结构以及层级构建两个方面对其进行介绍。下篇仍在酝酿中,所以我们可以先将此篇作为单篇来看。
本篇文章,仅讲解osgb与3dtiles的数据结构,不会涉及到层级等等的介绍,但为了能够成功的看到我们最终转换出来的数据效果,因此我们仅挑选osgb中的一个层级进行转换,这样能有效地排除层级渲染的时候对数据最终效果的影响。
要想正确的对这两个数据进行转换,我们需要对这两个数据进行一些初步的了解。
首先什么是osgb数据?什么是3dtiles数据?他们两个数据之间有什么差异?
不知道大家有没有想过,为什么市面上能够找到osgb数据向3dtiles数据格式转换,却鲜有能够将3dtiles转换成osgb数据的?是否是这两个数据格式之间存在着很大的差异?
我也一头雾水,后来请教了一个3dtiles数据的大佬。
他跟我说:“理论上,3dtiles是可以转换成osgb数据的,不过成本很大。因为诸如osgb数据转3dtiles本质上是将对人类友好的对象型数据,裂解为对GPU友好的图形编程型数据;以3dtiles、gltf等格式的数据,是为了怎么渲染快怎么来,从来没有考虑过往回倒的余地。”
嗯,了然,就是说这类型数据就不是创建出来给人看的而是给计算机看的,可二次利用率很低。
好了,明白了这个道理,我就不再纠结回转了。
现在我们看一下,这两个数据的区别。
osgb数据,通常渲染在平面坐标场景上,其数据使用的是ENU坐标系。我更习惯叫它相对坐标,在其数据本身的坐标数值上,再加入坐标原点的值,即是正常的载体坐标(通常为2000平面坐标)。其坐标原点及坐标系定义存储在名为“metadata.xml”的xml文件内,长宽高单位为米。
而3dtiles数据格式,则是渲染在球面场景上,坐标常为wgs84经纬度坐标,(也可能为2000经纬度坐标),其长宽为经纬度,高为米。
如前文所说,这次转换不涉及层级,因此我只提取了其中一个层级的数据,如下图所示。
废话了那么多,我想说的是,osgb数据要转3dtiles,必须要经过坐标转换。
坐标转换非常简单,利用Offsetter给模型添加上坐标原点的偏移量将其转换为正常的载体坐标,然后Reprojector转换成wgs84的经纬度坐标就完了。(一般在已经定义了原始数据的坐标系的情况下,FME写出3dtiles的时候会自动将其转换到经纬度坐标上,之所以加上这一步,是为了让大家对数据转换过程中到底发生了哪些变换有一个了解)
转换完成后,如果在datainspecter里面查看数据,你会发现你什么都看不到。
遇到这个问题不要慌,FME并不能渲染球面场景的数据,因此出现这样的问题是正常的,我们暂且不去管它,先写出成osgb数据看一下。
在写出的时候,参数如下设置,这表示,我要将每一个osgb文件生成一个单独的b3dm文件,并汇总到一个叫做“Tile+001+010_L22”的文件夹中,由FME自己创建层级tileset.json文件
这样转换后,是否就搞定了呢?其实不一定。这里先略过如何加载3dtiles数据不谈,我们直接看结果。(如何在浏览器里面查看3dtiles数据格式,可以参考另外一篇博客https://blog.csdn.net/fmechina/article/details/109383801?spm=1001.2014.3001.5501)
在转换后有一些osgb数据(如我现在用的这个)当你将转换后如果你将数据加载到cesium里面去看,会看到如下场景。
没错,五彩斑斓的黑(其实还是能看到模型的颜色的,只是因为截图被压缩的缘故,整体会显得更暗一点点)。
不过,有一点可以肯定的是,转坐标这个思路肯定是没有问题的。
然后我翻了网上的资料,影响一个模型数据的光亮程度,除了渲染引擎之间的区别、渲染场景的光照等因素;剩下的就只有数据本身的纹理了。
在FME打开osgb数据,查看数据的纹理结构,你会发现存在这样几个属性
这里,就要插一点题外话了,FME对几何的的分类。
可以看到,在FME中,是将单个.osgb数据当作一个三维的IFMEAggregate,这个聚合体(IFMEAggregate),分为多个部分,每一个部分下都是一个IFMEMesh,而每一个IFMEMesh都存在对应的几何和纹理。
纹理一般分为正面纹理(FrontAppearance Reference)和背面纹理(Back Appearance Reference)。
正面纹理则是我们看到的一个物体的表面,既外部的纹理特征,背面纹理则是物体的内部,在转3dtiles中,意义不大。
影响纹理的表现特征的几个属性,从上到下,依次分为:
• Alpha:纹理的透明度级别
• Ambient Color:环境反射颜色
• Diffuse Color:漫反射颜色
• Emissive Color:自发光颜色
• Specular Color:镜面反射颜色
• Shininess:光泽度
查找关于着色器的资料,大概是这么说的,“物体表面的颜色是自发光(放射 emissive)、环境反射(ambient)、漫反射(diffuse)和镜面反射(specular)等光照作用的总和。”然后罗列了一堆计算公式和专业术语……
呃……
看不懂……
首先去掉几个错误答案,肯定不是透明度和光泽度,白色光也肯定不会让纹理变黑。
剩下的就只有EmissiveColor(自发光颜色)和Specular Color(镜面反射颜色)均为0, 0, 0(黑色),经过我的细(hu)心(luan)验(chang)证(shi),造成模型变黑的罪魁祸首就是这两个属性。
其实不只是在转3dtiles格式,在转其他格式的时候,如果你发现自己的模型纹理变黑了,多半也是这两个属性造成的。
但是如何修改这个属性呢?你会发现这并不是一个通常意义下存储在attribute下面的属性,传统的修改方式并不能奏效。
一开始,我想的是通过PythonCaller调用FME Objects Python API来实现这个需求,不过官方文档实在是写的晦涩难懂,也没有实际案例,花了几天也没看懂如何操作FMELibrary。
后来无意之中,发现了SharedItemRetriever和SharedItemAdder这两个转换器,终于算是实现了这个需求。
修改模型的EmissiveColor步骤如下图所示。
和修改普通的属性不同,我们需要先通过SharedItemRetriever提取到模型的SpecularColor属性,修改其值为1, 1, 1,然后再利用SharedItemAdder转换器将该属性添加回去,等待一切完成后,再将多余的属性要素删除即可。
这一步操作可能和平时的FME修改属性操作不太一样,理解就好。
然后再在FME中查看,我已经将该属性修改成了白色,完美。
然后再次转换成3dtiles数据,就可以看到,整个模型的颜色已经变亮~~……咳咳咳,我再次重申,这是截图被压缩了的问题,好吧,它确实还是有那么一点点黑。
为了尽善尽美,我们以同样的方式,再加上修改EmissiveColor(自发光颜色),如下图是值为0.01,0.01,0.01的样子
再到0.02,0.02,0.02
可以看出,模型已经明显亮了很多,欠缺的部分,可以通过渲染引擎调整光照等因素来弥补,以达到完美的表现形式。鉴于本人不会cesium,下一步操作略过。
果然,要想研究好三维数据,需要强大的知识储备,我还需要加倍努力。
至此,osgb转3dtiles数据篇的讲解已经告一段落,整体上其实还是比较简单的一个操作,只是网络上相关资料太少,和我们接触的常规的二维数据差别太大。
- END -