1. 程式人生 > 其它 >[轉]cesium很全的入門教程-翻譯官網和加入自己理解

[轉]cesium很全的入門教程-翻譯官網和加入自己理解

快速入門教程基本涵蓋了大多數的CesiumJS API概念,主要用於Cesium基本入門,對Cesium有全面基本的瞭解和使用

一、概述
本教程會一步一步教會你做一個專案,主要介紹如下內容:

配置1個Cesium viewer
載入各種資料集
建立幾何和設定樣式
載入3D Tiles
控制相機
新增滑鼠互動
學完後你將會建立如下專案。

二、前期準備
下載 workshop code
在vscode中開啟cesium-workshop 目錄.
Run npm install.安裝需要的依賴
Run npm start.服務會使用node.js啟動,主要根據服務中的server.js配置檔案啟動,也可以直接使用其他伺服器啟動,不需要 server.js
2.1 workshop code目錄結構
Source/ : js業務邏輯和一些資料.
ThirdParty/ : 可以引用其他類庫,如 CesiumJS library.
LICENSE.md : Terms of use for this application.
index.html : 主頁.
server.js : 服務會使用node.js啟動,主要根據服務中的server.js配置檔案啟動.
因此,我們主要使用index.html和app.js兩個檔案進行本專案的編寫工作,如果你下載了workshop code工程,可以看到裡面的程式碼是寫好的,我們主要需要學會每行程式碼的意義和使用方法。
該專案完整的演示效果:演示地址
2.2 從index.html開始
引入cesium類庫,在原始碼中執行npm run build會將所有的原始碼建立快捷索引到一個ceiusm.js檔案中,該檔案只是對所有原始碼建立了快捷入口方式,不同於npm run release,可以使用該檔案進行原始碼除錯 建立一個App.js邏輯檔案或者index.js,來初始化三維地球,裡面就是寫var viewer = new Cesium.Viewer('cesiumContainer');初始化等功能
匯入cesium樣式檔案,@import url(ThirdParty/Cesium/Widgets/widgets.css);
讓我們正式開始吧!

三、建立一個地球視窗

var viewer = new Cesium.Viewer('cesiumContainer',option);

Viewer是一個綜合,包含中心的地球globe,周圍的控制元件widget,如果只需要一個地球的話,使用可以cesiumwidget()來初始化,viewer的內部原始碼就是使用了cesiumwidget()建立地球,並建立一些div來生成widget控制元件

1、Geocoder : 地名地址搜尋,地點搜尋預設使用bing地圖. Uses Bing Maps data by default.
2、HomeButton : 主頁檢視,可覆蓋該方法,自定義主頁檢視.
3、SceneModePicker : 不解釋。Switches between 3D, 2D and Columbus View (CV) modes.
4、BaseLayerPicker : 不解釋。Chooses the imagery and terrain to display on the globe.
5、NavigationHelpButton :幫助資訊,沒啥用。 Displays the default camera controls.
6、Animation : 一般去掉。Controls the play speed for view animation.
7、CreditsDisplay : 使用程式碼可以去掉版權資訊:viewer._cesiumWidget._creditContainer.style.display=“none”;
8、Timeline : 不顯示一般。Indicates current time and allows users to jump to a specific time using the scrubber.
9、FullscreenButton : Makes the Viewer fullscreen.

var viewer = new Cesium.Viewer('cesiumContainer', {
    scene3DOnly: true,
    selectionIndicator: false,
    baseLayerPicker: false
});

四、Cesium ion
Cesium的資料伺服器,功能很強大,但是國內一般不用

4.1 新增影像地圖Adding Imagery
支援的 Imagery Formats:
WMS
TMS
WMTS (with time dynamic imagery)
ArcGIS
Bing Maps
Google Earth
Mapbox
Open Street Map
Cesium提供了不同的介面載入上述幾種型別的服務,但都是使用ImageryProvider來載入,可通過該連結檢視所有介面型別many different providers
示例如下:

// 去掉預設底圖bing   Remove default base layer
viewer.imageryLayers.remove(viewer.imageryLayers.get(0));

// Add Sentinel-2 imagery
viewer.imageryLayers.addImageryProvider(new Cesium.IonImageryProvider({ assetId : 3954 }));

通過以上示例可以知道,預設的Cesium會載入一個底圖,是bingMap底圖,網路不太好,一般要先去掉這個預設的,載入我們自己的。

五、新增地形服務Adding Terrain

示例程式碼如下:

// Load Cesium World Terrain
viewer.terrainProvider = Cesium.createWorldTerrain({
    requestWaterMask : true, // required for water effects
    requestVertexNormals : true // required for terrain lighting
});
// Enable depth testing so things behind the terrain disappear.
viewer.scene.globe.depthTestAgainstTerrain = true;

equestVertexNormals是地形光照效果,需要開啟場景光源支援,depthTestAgainstTerrain是地形遮擋效果開關,開啟後地形會遮擋看不到的區域

六、配置Scene
重點標註:影像和地形都是載入scene中的globe物件上的,但是其他的entiy和3dtiles等,是載入在scene上的,和globe是同級別的,關閉globe,entiy等也會顯示

6.1 場景中的座標概念簡介:
Cartesian3 : 世界座標系,座標原點在globe球心的一個座標系,座標值是以米為單位,所以Cartesian3的座標值大多是地球的半徑那麼大的數值。a 3D Cartesian coordinate – when used as a position it is relative to the center of the globe in meters using the Earth fixed-frame (ECEF)

Cartographic : WGS84-就是經緯度座標系,地球的經緯度值,單位是度,如118°。a position defined by longitude, latitude (in radians) and height from the WGS84 ellipsoid surface

區域性座標系:啥叫區域性座標系呢?很簡單,就是你自己在地球上找個經緯度點,把他當原點,形成一個座標系。
看程式碼:

// Get the transform from local east-north-up at cartographic (0.0, 0.0) to Earth's fixed frame.
var center = Cesium.Cartesian3.fromDegrees(118.0, 30.0);
var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);

我們把座標原點移動到了118.0, 30.0這個地方,x軸指向東,y軸指向北,還有northEastDownToFixedFrame等不同的方向座標軸

  • HeadingPitchRoll : HPR地球視角上下左右偏移調整,參考部落格相機中的HeadingPitchRoll

  • Quaternion : 行話為四元數,其實就是使一個物體圍繞指定的軸旋轉多少角度。和旋轉方法,旋轉矩陣是同步改變的。(A 3D rotation represented as 4D coordinates.)

6.2 相機控制(Camera Control)

viewer.scene.Camera ,就是單純的實現視角的各種移動縮放等

Camera.setView(options) : 直接定位到一個視角,沒動畫set camera at specific position and orientation immediately
Camera.zoomIn(amount) : 縮放多少米move camera forward along the view vector
Camera.zoomOut(amount) : 縮放多少米move camera backwards along the view vector
Camera.flyTo(options) : 最常用,有動畫過程create an animated camera flight from the current camera position to a new position
Camera.lookAt(target, offset) : 定位到一個點,並以這個點為中心鎖定orient and position the camera to look at target point with given offset
Camera.move(direction, amount) : 平移一定距離move the camera in any direction
Camera.rotate(axis, angle) : 旋轉rotate the camera about any axis
示例:

// Create an initial camera view
var initialPosition = new Cesium.Cartesian3.fromDegrees(-73.998114468289017509, 40.674512895646692812, 2631.082799425431);
var initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(7.1077496389876024807, -31.987223091598949054, 0.025883251314954971306);
var homeCameraView = {
    destination : initialPosition,
    orientation : {
        heading : initialOrientation.heading,
        pitch : initialOrientation.pitch,
        roll : initialOrientation.roll
    }
};
// Set the initial view
viewer.scene.camera.setView(homeCameraView);

可以修改cesium預設的主頁按鈕定位位置

// Add some camera flight animation options
homeCameraView.duration = 2.0;//飛行用時
homeCameraView.maximumHeight = 2000;//飛行過程中最大高度
homeCameraView.pitchAdjustHeight = 2000;
homeCameraView.endTransform = Cesium.Matrix4.IDENTITY;
// Override the default home button覆蓋home預設事件
viewer.homeButton.viewModel.command.beforeExecute.addEventListener(function (e) {
    e.cancel = true;
    viewer.scene.camera.flyTo(homeCameraView);
});

座標系轉換:參考

6.3 Clock Control

這個在沿著路線飛行漫遊的時候能用到,暫時不會,後期補充,舉個使用列子吧在這。

// Set up clock and timeline.
viewer.clock.shouldAnimate = true; // make the animation play when the viewer starts
viewer.clock.startTime = Cesium.JulianDate.fromIso8601("2017-07-11T16:00:00Z");
viewer.clock.stopTime = Cesium.JulianDate.fromIso8601("2017-07-11T16:20:00Z");
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601("2017-07-11T16:00:00Z");
viewer.clock.multiplier = 2; // sets a speedup
viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER; // tick computation mode
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // loop at the end
viewer.timeline.zoomTo(viewer.clock.startTime, viewer.clock.stopTime); // set visible range

七、載入Entities
Entities相較於Primitive介面更加簡單直觀,是對Primitive封裝
常見的Entities:

Polygon
Polyline
Billboard
Label
可以使用viewer.entities.add()方法直接新增entity到一個預設的dataSource裡面,DataSource是新增各種entity的集合,預設有一個defaultDataSource,viewer.entities.add()如果不知道載入到哪個DataSource裡面,就會被預設載入到defaultDataSource裡。
DataSource有一下幾類:
CustomDataSource-就是最常見的新增Entity型別的

var dataSource = new Cesium.CustomDataSource('myData');

var entity = dataSource.entities.add({
   position : Cesium.Cartesian3.fromDegrees(1, 2, 0),
   billboard : {
       image : 'image.png'
   }
});

viewer.dataSources.add(dataSource);
  • CzmlDataSource-載入czml檔案格式的資料
  • GeoJsonDataSource-載入geojson格式的資料
var viewer = new Cesium.Viewer('cesiumContainer');
viewer.dataSources.add(Cesium.GeoJsonDataSource.load('../../SampleData/ne_10m_us_states.topojson', {
  stroke: Cesium.Color.HOTPINK,
  fill: Cesium.Color.PINK,
  strokeWidth: 3,
  markerSymbol: '?'
}));
  • KmlDataSource-載入kml格式的資料
var kmlOptions = {
    camera : viewer.scene.camera,
    canvas : viewer.scene.canvas,
    clampToGround : true
};
// Load geocache points of interest from a KML file
// Data from : http://catalog.opendata.city/dataset/pediacities-nyc-neighborhoods/resource/91778048-3c58-449c-a3f9-365ed203e914
var geocachePromise = Cesium.KmlDataSource.load('./Source/SampleData/sampleGeocacheLocations.kml', kmlOptions);

// Add geocache billboard entities to scene and style them
geocachePromise.then(function(dataSource) {
    // Add the new data as entities to the viewer
    viewer.dataSources.add(dataSource);

        // Get the array of entities
    var geocacheEntities = dataSource.entities.values;

    for (var i = 0; i < geocacheEntities.length; i++) {
        var entity = geocacheEntities[i];
        // Add geocache billboard entities to scene and style them

        if (Cesium.defined(entity.billboard)) {
            // 貼地形Adjust the vertical origin so pins sit on terrain
            entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
            // 去掉自帶的標註,不顯示那麼亂--Disable the labels to reduce clutter
            entity.label = undefined;
            // 按照縮放距離顯示Add distance display condition
            entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0);

               // Compute longitude and latitude in degrees
            var cartographicPosition = Cesium.Cartographic.fromCartesian(entity.position.getValue(Cesium.JulianDate.now()));
            var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude);
            var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude);
            // Modify description
            // Modify description
            var description = '<table class="cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter"><tbody>' +
                '<tr><th>' + "Longitude" + '</th><td>' + longitude.toFixed(5) + '</td></tr>' +
                '<tr><th>' + "Latitude" + '</th><td>' + latitude.toFixed(5) + '</td></tr>' +
                '</tbody></table>';
            entity.description = description;
            // entity styling code here

            // Set the polygon material to a random, translucent color.
            entity.polygon.material = Cesium.Color.fromRandom({
                red : 0.1,
                maximumGreen : 0.5,
                minimumBlue : 0.5,
                alpha : 0.6
            });

            // 面貼地或者貼3dties---Tells the polygon to color the terrain. ClassificationType.CESIUM_3D_TILE will color the 3D tileset, and ClassificationType.BOTH will color both the 3d tiles and terrain (BOTH is the default)
            entity.polygon.classificationType = Cesium.ClassificationType.TERRAIN;

            // entity styling code here

            // Generate Polygon position
            var polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
            //求一個面的中心點座標
            var polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center;
            polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter);
            entity.position = polyCenter;
            // Generate labels
            entity.label = {
                text : entity.name,
                showBackground : true,
                scale : 0.6,
                horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
                verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
                distanceDisplayCondition : new Cesium.DistanceDisplayCondition(10.0, 8000.0),
                disableDepthTestDistance : 100.0
            };
// Add computed orientation based on sampled positions根據位置自動調整朝向
            entity.orientation = new Cesium.VelocityOrientationProperty(entity.position);
            // Smooth path interpolation路徑插值,就是在兩點直接移動過程中,使物體的移動平滑
drone.position.setInterpolationOptions({
    interpolationDegree : 3,
    interpolationAlgorithm : Cesium.HermitePolynomialApproximation
});
            
        }
    }
});

程式碼說明

  1. clampToGround意思是新增的entity到dem上,而不是wgs84的球面
  2. load載入資料都是非同步載入的,所以會返回一個Promise—Promise是ES6解決ajax迴圈請求問題的。
  3. entity.description是修改這個預設彈框資訊:

entity.polygon.classificationType = Cesium.ClassificationType.TERRAIN;可以把面貼地,或者貼3dtiles表面
Cesium.BoundingSphere.fromPoints(polyPositions).center;計算幾何中心
Property Types Demo動態效果實現用到了cesium中的property屬性功能
根據position自動計算entity的方向。VelocityOrientationProperty
setInterpolationOptions就是使用插值演算法,使模型在兩點直接移動過程中,在兩點之間進行插值,使移動更平滑
property介紹–參考vtxf部落格
比如一個entity中很多值都是屬性property型別new Cesium.Entity({position:PositionProperty,orientation:property}),這個屬性值是Cesium提供的一種機制,讓某個property比如positioon可以隨時間自動發生變化,自動賦予不同的數值(位置)。這也就是property的作用了。

// 建立盒子
var blueBox = viewer.entities.add({
    name : 'Blue box',
    position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
    box : {
        dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
        material : Cesium.Color.BLUE,
        outline: true,
    }
});

    var property = new Cesium.SampledProperty(Cesium.Cartesian3);

    property.addSample(Cesium.JulianDate.fromIso8601('2019-01-01T00:00:00.00Z'), 
        new Cesium.Cartesian3(400000.0, 300000.0, 200000.0));
    
    property.addSample(Cesium.JulianDate.fromIso8601('2019-01-03T00:00:00.00Z'), 
        new Cesium.Cartesian3(400000.0, 300000.0, 700000.0));

    blueBox.box.dimensions = property;

以上程式碼的意思就是在兩個不同的時間點分別賦予不同的位置,用SampledProperty包裝成一個property,最後賦給blueBox.box.dimensions。

由此可見,Property最大的特點是和時間相互關聯,在不同的時間可以動態地返回不同的屬性值。而Entity則可以感知這些Property的變化,在不同的時間驅動物體進行動態展示。

Cesium宣稱自己是資料驅動和time-dynamic visualization,這些可都是仰仗Property系統來實現的。

通俗講就是比如position屬性不只是能賦值一個固定的座標,還能賦值一個有時間和位置組成的陣列物件。
屬性的作用是可以實現漫遊飛行功能:
漫遊飛行實現Interpolation

八、3D Tiles
簡介
開源介紹
格式介紹
The 3D Tiles Inspector
各類示例

載入3dtiles

// Load the NYC buildings tileset
var city = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(75343) }))

新增樣式

cesium專門提供了3D Tiles styling language

var defaultStyle = new Cesium.Cesium3DTileStyle({
    color : "color('white')",
    show : true
});
//按照條件
var heightStyle = new Cesium.Cesium3DTileStyle({
    color : {
        conditions : [
            ["${Height} >= 300", "rgba(45, 0, 75, 0.5)"],
            ["${Height} >= 200", "rgb(102, 71, 151)"],
            ["${Height} >= 100", "rgb(170, 162, 204)"],
            ["${Height} >= 50", "rgb(224, 226, 238)"],
            ["${Height} >= 25", "rgb(252, 230, 200)"],
            ["${Height} >= 10", "rgb(248, 176, 87)"],
            ["${Height} >= 5", "rgb(198, 106, 11)"],
            ["true", "rgb(127, 59, 8)"]
        ]
    }
});

九、滑鼠點選互動事件Interactivity

滑鼠事件主要有左鍵,右鍵,滾輪鍵盤,滑鼠移動事件,使用ScreenSpaceEventHandler來獲取相應的事件

//滑鼠移動事件捕捉
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(movement) {}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

滑鼠事件主要用於捕捉選擇場景中新增的各種資料,選擇到資料後,便可以對資料進行各種展示處理操作,選擇場景中的資料的方式主要使用pick()函式,目前有一下幾類:

Scene.pick : 選擇一個圖元。returns an object containing the primitive at the given window position.
Scene.drillPick : returns a list of objects containing all the primitives at the given window position.
Globe.pick : returns the intersection point of a given ray with the terrain.
高亮示例,移動高亮,移除恢復:

// If the mouse is over a point of interest, change the entity billboard scale and color
var previousPickedEntity = undefined;
handler.setInputAction(function(movement) {
    var pickedPrimitive = viewer.scene.pick(movement.endPosition);

    //獲取滑鼠的經緯度位置
    var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, scene.globe.ellipsoid);
    if (cartesian) {
        var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);
        var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);

        entity.position = cartesian;
        
    }

    var pickedEntity = (Cesium.defined(pickedPrimitive)) ? pickedPrimitive.id : undefined;
    // Unhighlight the previously picked entity
    if (Cesium.defined(previousPickedEntity)) {
        previousPickedEntity.billboard.scale = 1.0;
        previousPickedEntity.billboard.color = Cesium.Color.WHITE;
    }
    // Highlight the currently picked entity
    if (Cesium.defined(pickedEntity) && Cesium.defined(pickedEntity.billboard)) {
        pickedEntity.billboard.scale = 2.0;
        pickedEntity.billboard.color = Cesium.Color.ORANGERED;
        previousPickedEntity = pickedEntity;
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

可以使用camera.pickEllipsoid來獲取滑鼠移動過程中的位置資訊:

 //獲取滑鼠的經緯度位置
    var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, scene.globe.ellipsoid);
    if (cartesian) {
        var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);
        var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);

        entity.position = cartesian;
        
    }

高亮選擇的3dtiles邊緣示例

3D Tiles Feature Picking Demo

十、Camera Modes

viewer.trackedEntity可以讓視角一直跟著某個entity走,漫遊模式。

// Create a follow camera by tracking the drone entity
function setViewMode() {
    if (droneModeElement.checked) {
        viewer.trackedEntity = drone;
    } else {
        viewer.trackedEntity = undefined;
        viewer.scene.camera.flyTo(homeCameraView);
    }
}

十一、參考資料

西部世界Cesium資料大全
Cesium學習系列彙總

 

原文連結:cesium很全的入門教程-翻譯官網和加入自己理解