Cesium,ClippingPlanes,任意剪裁面对3DTiles剪裁
一、簡介
相關官方文檔地址:ClippingPlaneCollection、Cesium3DTileset
官方Demo地址:3D Tiles Clipping Planes
官方介紹:Cesium Feature Highlight: Clipping Planes
對于3DTiles和gltf,均可以通過ClippingPlaneCollection來實現顯示時的模型剪裁顯示,即僅顯示模型的一部分區域。該項特性在cesium1.4開始提供。
由于官方demo和文檔的信息依然較少,在下在業務需求中又遇到了需要將3DTiles按照任意多邊形進行剪裁的需求,因此此篇文章主要是總結了下如何實現該需求。
二、具體實現
業務需求是希望將3DTiles按照任意平行于地表的多邊形進行剪裁顯示,換句話說,剪裁面都是垂直于地表的,因此只考慮這種需求。
圖1 未剪裁前:
圖2 剪裁后:
關于ClippingPlanes的基本使用在api文檔和demo中有詳細描述。
下面給出一個簡單示例:
各參數不再贅述。
這里的重點是planes的計算,planes對應一個ClippingPlane對象的數組。ClippingPlane也就是實際使用的剪裁面。
ClippingPlane的計算
構造:
Cesium.ClippingPlane(normal, distance)由文檔可知,需要計算剪裁面的法向量作為normal和原點到該剪裁面的最短距離作為distance。
需注意的是,對于平面的normal,它指向的方向將不會被裁剪,反向的方向才會被裁剪。
根據文檔中的介紹可知,ClippingPlane所位于的坐標系應該是,以3DTiles原點為坐標原點,該點正東為x軸正方向,該點正北為y軸正方向,該點的地球橢球體法線為z軸,遠離地心的那一端為z軸正方向。
因此可以先將剪裁面的相應計算所需的點,轉換到上述坐標系,然后進行計算。
假設一條位于地表的線段p1,p2定義一個剪裁面,那么計算如下:
1.計算坐標轉換需要用到的矩陣的方法:
function getInverseTransform (tileSet) {let transformlet tmp = tileSet.root.transformif ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {// 如果root.transform不存在,則3DTiles的原點變成了boundingSphere.centertransform = Cesium.Transforms.eastNorthUpToFixedFrame(tileSet.boundingSphere.center)} else {transform = Cesium.Matrix4.fromArray(tileSet.root.transform)}return Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4()) }關于原點的一點補充,原點的選擇直接影響到ClippingPlane的構造,ClippingPlaneCollection的文檔中提到了這一點,如果root.transform存在,需要使用root.transform對應的坐標原點作為構造ClippingPlane時的坐標原點,如果不存在的話,就使用boundingSphere.center。
這也是顯而易見的,因為如果root.transform存在并且不等于Cesium.Matrix4.IDENTITY,就說明3DTiles的根瓦片存在一個自身定義的相對變換。此時包圍盒的中心點和3DTiles中對圖形頂點定位的局部坐標系坐標原點并不重合。
2.對點進行坐標轉換的方法:
3.具體的計算:
function createPlane (p1, p2, inverseTransform) {// 將僅包含經緯度信息的p1,p2,轉換為相應坐標系的cartesian3對象let p1C3 = getOriginCoordinateSystemPoint(p1, inverseTransform)let p2C3 = getOriginCoordinateSystemPoint(p2, inverseTransform)// 定義一個垂直向上的向量uplet up = new Cesium.Cartesian3(0, 0, 10)// right 實際上就是由p1指向p2的向量let right = Cesium.Cartesian3.subtract(p2C3, p1C3, new Cesium.Cartesian3())// 計算normal, right叉乘up,得到平面法向量,這個法向量指向right的右側let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3())normal = Cesium.Cartesian3.normalize(normal, normal)//由于已經獲得了法向量和過平面的一點,因此可以直接構造Plane,并進一步構造ClippingPlanelet planeTmp = Cesium.Plane.fromPointNormal(p1C3, normal)return Cesium.ClippingPlane.fromPlane(planeTmp) }上面就構造了一個由地平面兩點p1,p2定義的剪裁面,這個剪裁面始終剪裁掉位于p1指向p2的向量的左側。
4.數組的構造
由3可以得到一個剪裁面了。那么對于數組[p1,p2,p3…pN],當該數組中的點是按照順時針排序時(因為3中叉乘的方向是right × up),相鄰點兩兩構成一個剪裁面,就可以達到如上圖2的效果。如果數組是按照逆時針排序,還需要將數組reverse下。
如何判斷位于數組中的點,是按照順時針還是逆時針排序?
網上能找到很多資料,這里我用的是下面的方法:
判斷一個多變形是順時針還是逆時針的方法(含凹多邊形)
下面給出我使用上面算法的具體實現:
關于凹多邊形作為剪裁面
雖然傳值是可以正常傳入凹多邊形的剪裁面,但實際表現情況如下圖:
總結
以上是生活随笔為你收集整理的Cesium,ClippingPlanes,任意剪裁面对3DTiles剪裁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梯度裁剪Grandient Clippi
- 下一篇: 实现从淘宝定时抓取订单数据、打印电子面单