翻譯自官方文檔。canvas
這篇教程介紹的是 Primitive API 有關的資料,適合高級用戶。想快速繪製各類形狀,建議參考 Entity API。api
Cesium 能夠建立 Entity API 建立各類幾何圖形,例如繪製一個矩形:app
viewer.entities.add({ rectangle : { coordinates : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), material : new Cesium.StripeMaterialProperty({ evenColor: Cesium.Color.WHITE, oddColor: Cesium.Color.BLUE, repeat: 5 }) } });
這是一個很常見的例子。dom
在本教程中,將深刻研究 Primitive API:使用 Geometry 和 Appearance 來構造幾何圖形。性能
使用 Primitive API 中的 Geometry 和 Appearance 的好處是:翻譯
缺點也是有的:code
使用 Primitive API 重寫上面的代碼:orm
var instance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT }) }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : instance, appearance : new Cesium.EllipsoidSurfaceAppearance({ material : Cesium.Material.fromType('Stripe') }) }));
GeometryInstance 是 Geometry 的容器,當前只有一個 Geometry。對象
爲了建立矩形,使用 RectangleGeometry:
由於它是地面的矩形,因此使用 EllipsoidSurfaceAppearance
這種外觀,
十幾種(有對應的線框模式),簡單列舉以下:
在沙盒中能夠找到對應的示例代碼(Geometries And Appearance):
當你須要繪製多個靜態的幾何圖形時,Primitive API 就有性能優點了。例如,能夠在一個 Primitive 中組合兩個矩形:
const instance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT }) }); const anotherInstance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0), vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT }) }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : [instance, anotherInstance], appearance : new Cesium.EllipsoidSurfaceAppearance({ material : Cesium.Material.fromType('Stripe') }) }));
建立了兩個 geometry instance,共用了一個 appearance。
有一些 Appearance 容許使用 GeometryInstance 本身的屬性來着色:
const instance = new Cesium.GeometryInstance({ geometry : // 和上面同樣 attributes : { color : new Cesium.ColorGeometryInstanceAttribute(0.0, 0.0, 1.0, 0.8) } }); const anotherInstance = new Cesium.GeometryInstance({ geometry : // 和上面同樣 attributes : { color : new Cesium.ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 0.8) } }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : [instance, anotherInstance], appearance : new Cesium.PerInstanceColorAppearance() }));
出來的效果:
每一個 GeometryInstance 都帶了一個 color attribute。
組合圖形讓 Cesium 能繪製大量幾何圖形,下例是 2592 個獨立顏色的矩形:
const instances = []; for (let lon = -180.0; lon < 180.0; lon += 5.0) { for (let lat = -85.0; lat < 85.0; lat += 5.0) { instances.push(new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(lon, lat, lon + 5.0, lat + 5.0), vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({alpha : 0.5})) } })); } } scene.primitives.add(new Cesium.Primitive({ geometryInstances : instances, appearance : new Cesium.PerInstanceColorAppearance() }));
GeometryInstance 繪製後仍然是能夠獨立訪問的,只需分配一個 id 便可。
const instance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0), vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), // 加了個id id : 'my rectangle', attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED) } }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : instance, appearance : new Cesium.PerInstanceColorAppearance() })); // 當你點擊的時候 控制檯就刷出一句提示 var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); handler.setInputAction(function (movement) { var pick = scene.pick(movement.position); // pick.id 即 GeometryInstance.id if (Cesium.defined(pick) && (pick.id === 'my rectangle')) { console.log('Mouse clicked rectangle.'); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
Geometry 容許使用不一樣的轉換矩陣,構造不一樣位置的 GeometryInstance,這樣頂點數據只存了一份:
下面這個實例只建立一個橢球幾何體,可是用不一樣的矩陣來表示不一樣的位置。
const ellipsoidGeometry = new Cesium.EllipsoidGeometry({ vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT, radii : new Cesium.Cartesian3(300000.0, 200000.0, 150000.0) }); const cyanEllipsoidInstance = new Cesium.GeometryInstance({ geometry : ellipsoidGeometry, // 同一個幾何 modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-100.0, 40.0)), new Cesium.Cartesian3(0.0, 0.0, 150000.0), new Cesium.Matrix4() ), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.CYAN) } }); const orangeEllipsoidInstance = new Cesium.GeometryInstance({ geometry : ellipsoidGeometry, // 同一個幾何 modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-100.0, 40.0)), new Cesium.Cartesian3(0.0, 0.0, 450000.0), new Cesium.Matrix4() ), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.ORANGE) } }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : [cyanEllipsoidInstance, orangeEllipsoidInstance], appearance : new Cesium.PerInstanceColorAppearance({ translucent : false, closed : true }) }));
繪製幾何完成後,能夠更新 GeometryInstance 的屬性,包括:
ColorGeometryInstanceAttribute
對象,使用此屬性,Primitive 必須使用的是 PerInstanceColorAppearance
const circleInstance = new Cesium.GeometryInstance({ geometry : new Cesium.CircleGeometry({ center : Cesium.Cartesian3.fromDegrees(-95.0, 43.0), radius : 250000.0, vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 0.0, 0.0, 0.5)) }, id: 'circle' }); const primitive = new Cesium.Primitive({ geometryInstances : circleInstance, appearance : new Cesium.PerInstanceColorAppearance({ translucent : false, closed : true }) }); scene.primitives.add(primitive); setInterval(function() { var attributes = primitive.getGeometryInstanceAttributes('circle'); attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({alpha : 1.0})); },2000);
這個例子每隔2秒,顏色就會變化一次。
使用 primitive.getGeometryInstanceAttributes('id')
能夠獲取某個 GeometryInstance 的屬性,固然,它的返回值的屬性能夠直接修改,像代碼中的 attributes.color = ...
同樣。
幾何只定義告終構,外觀負責顏值。Primitive 能夠有若干圖幾何,可是隻能有一種外觀。
Cesium 自帶的外觀以下:
能夠定義渲染狀態,或者使用更高級的屬性 closed
、translucent
,例如:
// 不透明 var appearance = new Cesium.PerInstanceColorAppearance({ translucent : false, closed : true }); // 這是比較底層的寫法,效果與上面同樣 var anotherAppearance = new Cesium.PerInstanceColorAppearance({ renderState : { depthTest : { enabled : true }, cull : { enabled : true, face : Cesium.CullFace.BACK } } });
建立外觀後,是沒辦法改變它的 renderState 的,可是能夠修改材質。
能夠更改圖元的外觀屬性,大多數外觀有 flat 和 faceForward 屬性,這兩個屬性間接控制着 GLSL 着色器。
並非全部的外觀都適合全部的幾何。好比,EllipsoidSurfaceAppearance 不適合 WallGeometry,由於牆面是垂直地面的,並不貼地。
爲了使得外觀與幾何圖形兼容,它們的頂點格式必須匹配。指定 Geometry 的 vertexFormat 屬性便可。
下圖能夠說明這個問題,當外觀須要有 st(即紋理座標)而 Geometry 沒有時,就會報錯:
外觀類有 VertexFormat
靜態屬性,或外觀對象有 vertexFormat
屬性可供使用。
幾何的 vertexFormat
是組合幾何圖形的因素,幾何的類型能夠不一樣,可是頂點的格式必須是同樣的。
const geometry = new Ceisum.RectangleGeometry({ vertexFormat : Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT // ... }); const geometry2 = new Ceisum.RectangleGeometry({ vertexFormat : Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT // ... }); const appearance = new Ceisum.MaterialAppearance(/* ... */); const geometry3 = new Ceisum.RectangleGeometry({ vertexFormat : appearance.vertexFormat // ... });
譯者注:頂點格式,即頂點的座標、法線、uv(即st)、顏色等組合狀況
Entity 用的是 Graphic,參數化建立圖形,並能夠參數符號化,幾何形狀和外觀耦合在一塊兒
Primitive 用的是 Geometry + Appearance,能夠分別修改幾何形狀和外觀。雖然有預約義的 Geometry,可是 Primitive API 提供的是更接近 WebGL 的接口,構造 Geometry 徹底可使用與 WebGL 十分接近的邏輯,傳入頂點、法線等素材建立不可思議的形狀。
Entity 擁有 Property 進行時間插值,Primitive 沒有時間插值,須要深刻着色器。
除此以外,Entity 在數據量特別大的狀況下性能比 Primitive 差。