Cesium學習筆記(六):幾何和外觀(Geometry and Appearances)

我們先直接來看一個例子

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

var flag = 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
        })
    }
});

這是我們之前的寫法,直接創建一個實體對象

而在這一章,我們將會使用幾何和外觀來創建實體對象,這樣更靈活更有效率

首先,還是先看一下,上面那段代碼的改造

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
//創建幾何圖形
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')
  })
}));

這樣的寫法自然是有優點也有缺點的

優點:

  • 性能 - 當繪製大量靜態圖元時,直接使用幾何形狀可以將它們組合成單個幾何體,以減少CPU開銷並更好地利用GPU。並且組合是在網絡上完成的,可以保持UI的響應。
  • 靈活性 - 基元組合幾何和外觀。通過解耦,我們可以獨立地修改。我們可以添加與許多不同外觀兼容的新幾何體,反之亦然。
  • 低級訪問 - 外觀提供了接近於渲染器的訪問,可以直接使用渲染器的所有細節(Appearances provide close-to-the-metal access to rendering without having to worry about all the details of using the Renderer directly)。外觀使其易於:
    • 編寫完整的GLSL頂點和片段着色器。
    • 使用自定義渲染狀態。

缺點:

  • 代碼量增大,並且需要使用者對這方面有更深入的理解。
  • 組合幾何可以使用靜態數據,不一定是動態數據。
  • primitives 的抽象級別適合於映射應用程序;幾何圖形和外觀的抽象層次接近傳統的3D引擎(Primitives are at the level of abstraction appropriate for mapping apps; geometries and appearances have a level of abstraction closer to a traditional 3D engine)(感覺翻譯的不太好的地方都給上了原文)

我們可以用一個primitives畫出多個幾何圖形,這樣可以明顯能看出性能上的優勢

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

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
  })
});

var 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')
  })
}));

這裏寫圖片描述

對於不同的圖形,我們可以單獨給它們設置屬性,這裏,我們使用PerInstanceColorAppearance不同顏色來遮蔽每個實例

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

var instance = new Cesium.GeometryInstance({
  geometry : new Cesium.RectangleGeometry({
    rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
    vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
  }),
  attributes : {
    //(紅,綠,藍,透明度)
    color : new Cesium.ColorGeometryInstanceAttribute(0.0, 0.0, 1.0, 0.8)
  }
});

var anotherInstance = new Cesium.GeometryInstance({
  geometry : new Cesium.RectangleGeometry({
    rectangle : Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0),
    vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
  }),
  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()
}));

這裏寫圖片描述

可能這樣大家還感覺不出來性能上的優勢,那我們可以這樣

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

var instances = [];
//循環創建隨機顏色的矩形
for (var lon = -180.0; lon < 180.0; lon += 5.0) {
  for (var 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()
}));

這裏畫了2592個不同顏色的矩形,而且速度非常快,這就更明顯的看出primitives在性能上的優勢了

這裏寫圖片描述

雖然我們是通過一個primitives來創建的,但是我們可以給每一個幾何圖形一個id,這樣我們就可以單獨訪問他們了、

var instance = new Cesium.GeometryInstance({
    id : "blue rectangle",
    geometry : new Cesium.RectangleGeometry({
        rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
        vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
    }),
    attributes : {
        color : new Cesium.ColorGeometryInstanceAttribute(0.0, 0.0, 1.0, 0.8)
    }
});

var anotherInstance = new Cesium.GeometryInstance({
    id : "red rectangle",
    geometry : new Cesium.RectangleGeometry({
        rectangle : Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0),
        vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
    }),
    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()
}));
//獲取屏幕事件管理器
var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
//監聽屏幕輸入事件(這裏是監聽左鍵點擊事件)
handler.setInputAction(function (movement) {
    var pick = scene.pick(movement.position);
    if (Cesium.defined(pick) ) {
        switch (pick.id)
        {
            case 'blue rectangle':
                console.log('Mouse clicked blue rectangle.');
                break;
            case 'red rectangle':
                console.log('Mouse clicked red rectangle.');
                break;
        }
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

然後我點擊兩個矩形,控制檯就輸出了相應的log

這裏寫圖片描述

當只要改變屬性,不需要改變幾何形狀時候還可以把幾何圖形的創建給提出來

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
//使用同一個幾何圖形
var ellipsoidGeometry = new Cesium.EllipsoidGeometry({
    vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
    radii : new Cesium.Cartesian3(300000.0, 200000.0, 150000.0)
});

var 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)
    }
});

var 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
    })
}));

這裏寫圖片描述

在創建完之後,我們依舊可以動態的修改模型的屬性,當然,這需要給模型加上一個id

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

var ellipsoidGeometry = new Cesium.EllipsoidGeometry({
    vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
    radii : new Cesium.Cartesian3(300000.0, 200000.0, 150000.0)
});

var cyanEllipsoidInstance = new Cesium.GeometryInstance({
    id : 'cyan',
    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)
    }
});

var orangeEllipsoidInstance = new Cesium.GeometryInstance({
    id : 'orange',
    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)
    }
});

var primitive = scene.primitives.add(new Cesium.Primitive({
    geometryInstances : [cyanEllipsoidInstance, orangeEllipsoidInstance],
    appearance : new Cesium.PerInstanceColorAppearance({
        //不透明
        translucent : false,
        closed : true
    })
}));

setInterval(function() {
    var attributes1 = primitive.getGeometryInstanceAttributes('cyan');
    attributes1.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({alpha : 1.0}));
    var attributes2 = primitive.getGeometryInstanceAttributes('orange');
    attributes2.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({alpha : 1.0}));
},1000);

這裏寫圖片描述

下面列舉下cesium中的幾何圖形和外觀,要注意的是有些外觀和幾何是不兼容的

幾何圖形 描述
BoxGeometry 盒子
BoxOutlineGeometry 只有外部線條的的盒子
CircleGeometry 圓圈或擠壓圓
CircleOutlineGeometry 同上(只有線條的圓,後面我就省略了)
CorridorGeometry 垂直於表面的折線,寬度以米爲單位,可選擇擠壓高度
CorridorOutlineGeometry
CylinderGeometry 圓柱體,圓錐體或截錐體
CylinderOutlineGeometry
EllipseGeometry 橢圓或擠出橢圓
EllipseOutlineGeometry
EllipsoidGeometry 橢圓形
EllipsoidOutlineGeometry
RectangleGeometry 矩形或擠壓矩形
RectangleOutlineGeometry
PolygonGeometry 具有可選孔或擠出多邊形的多邊形
PolygonOutlineGeometry
PolylineGeometry 一組寬度爲像素的線段
SimplePolylineGeometry
PolylineVolumeGeometry 沿着折線擠壓的2D形狀
PolylineVolumeOutlineGeometry
SphereGeometry 一個球體
SphereOutlineGeometry
WallGeometry 垂直於地球的牆壁
WallOutlineGeometry
外觀 描述
MaterialAppearance 外觀與所有幾何類型一起使用,並支持材料描述陰影。
EllipsoidSurfaceAppearance 幾何像幾何平行於地球表面的“Material Appearance”一樣,就像一個多邊形,並且使用這個假設來通過程序上計算許多頂點屬性來節省內存。
PerInstanceColorAppearance 使用每個實例的顏色來遮蔽每個實例。
PolylineMaterialAppearance 支持材料遮蔽Polyline。
PolylineColorAppearance 使用每頂點或每段着色來遮蔽折線。

參考資料:官方文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章