0、概述
本教程将向您介绍Primitive API 的 Geometry & Appearances(几何体和外观)系统。
这是一个高级主题,用于通过自定义网格、形状、体积和外观扩展CesiumJS,并不适合Cesium初学者。
声明:内容均来自Cesium官方教程,经翻译和整理而成。
原文链接:https://cesium.com/learn/cesiumjs-learn/cesiumjs-geometry-appearances/
一、几何体(Geometry)
CesiumJS可以使用Entity(如多边形和椭球)创建不同的几何体类型。
例如,将以下内容复制并粘贴到Hello World Sandcastle示例中,以在球体上创建一个带有条纹图案的矩形。
viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees(-100, 20, -90, 30), material: new Cesium.StripeMaterialProperty({ evenColor: Cesium.Color.YELLOW, oddColor: Cesium.Color.RED, repeat: 10 }) } })
在本教程中,我们深入了解 Geometry 和 Appearance 类型。
几何定义了Primitive(图元)的结构,即构成图元的三角形、线或点。
Appearance(外观)定义图元的着色,包括其完整的 GLSL 顶点和片元着色器,以及渲染状态。
使用几何图形和外观的好处是:
让我们使用几何图形和外观重写初始代码示例:
var viewer = new Cesium.Viewer('cesiumContainer'); var scene = viewer.scene; // original code //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 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') }) }));
我们没有使用rectangle entity,而是使用了通用的 Primitive,它结合了几何实例和外观。
目前,除了实例是几何体的容器之外,我们不会区分 Geometry 和 GeometryInstance 。
为了创建矩形的几何图形,即覆盖矩形区域并适合地球曲率的三角形,我们创建了一个 RectangleGeometry。
由于它在表面上,我们可以使用EllipsoidSurfaceAppearance。
这通过基于几何体位于表面上或椭圆体上方的恒定高度这一事实进行假设来节省内存。
二、几何体类型
CesiumJS 支持以下几何图形:
Cesium Sandcastle
三、组合几何体
当我们使用一个图元绘制多个静态几何图形时,我们看到了性能优势。例如,在一个图元中绘制两个矩形。
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() }));
每个实例都有一个 Color
属性。图元是用PerInstanceColorAppearance
构造的 ,它使用每个实例的颜色属性来确定着色。
组合几何图形允许 CesiumJS 有效地绘制大量几何图形。
四、拾取
实例合并后可以独立访问。为实例指定id,并使用该id确定是否使用Scene.pick拾取实例。
下面的示例创建一个id为my rectangle的实例,并在单击该实例时将消息写入控制台。
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, 30.0, -90.0, 40.0), vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), 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); if (Cesium.defined(pick) && (pick.id === 'my rectangle')) { console.log('Mouse clicked rectangle.'); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
使用id
可以避免在构造图元后在内存中保留对完整实例的引用,包括几何图形。
五、几何实例
实例可用于在场景的不同部分定位、缩放和旋转相同的几何体。
这是可能的,因为多个实例可引用相同的Geometry
,并且每个实例可以具有不同的modelMatrix
。
这允许我们只计算一次几何图形并多次重复使用它。
下面的示例创建一个EllipsoidGeometry和两个实例。每个实例都引用相同的椭球几何体,但使用不同modelMatrix,
从而使一个椭球位于另一个之上。
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 }) }));
六、更新每个实例的属性
将几何图形添加到图元后,更新几何图形的每个实例属性以更改可视化效果。每个实例的属性包括:
此示例显示如何更改几何实例的颜色:
var viewer = new Cesium.Viewer('cesiumContainer'); var scene = viewer.scene; var 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' }); var 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);
几何实例的属性可以使用primitive.getGeometryInstanceAttributes从图元中检索。可以直接更改属性的属性。
七、外观(Appearance)
几何定义了结构。图元的另一个关键属性appearance
定义了图元的着色,即单个像素的着色方式。
CesiumJS有以下几种Appearance:
外观定义了在绘制图元时在 GPU 上执行的完整 GLSL 顶点和片元着色器。Appearances 还定义了完整的渲染状态,它在绘制图元时控制 GPU 的状态。 我们可以直接定义渲染状态,也可以使用更高级别的属性,如closed和translucent,外观将转换为渲染状态。例如: // Perhaps for an opaque box that the viewer will not enter. // - Backface culled and depth tested. No blending. var appearance = new Cesium.PerInstanceColorAppearance({ translucent : false, closed : true }); // This appearance is the same as above var anotherAppearance = new Cesium.PerInstanceColorAppearance({ renderState : { depthTest : { enabled : true }, cull : { enabled : true, face : Cesium.CullFace.BACK } } });
一旦外观被创建,我们就不能改变它的 renderState 属性,但我们可以改变它的 material。我们还可以更改图元的 外观 属性。
大多数外观还具有 flat 和 faceForward 属性,它们间接控制 GLSL 着色器。
faceForward - 照明时,翻转法线使其始终面向观察者。避免背面的黑色区域,例如墙的内侧。
八、几何和外观兼容性
并非所有外观都适用于所有几何图形。例如,椭球曲面外观不适用于墙几何图形,因为墙不在球体的表面上。
要使外观与几何体兼容,它们必须具有匹配的顶点格式,这意味着几何体必须具有外观所需的数据作为输入。创建几何图形时,可以提供VertexFormat。
几何图形 vertexFormat
决定了它是否可以与另一个几何图形组合。两个几何图形不必是相同的类型,但它们需要匹配的顶点格式。
为方便起见,外观具有 vertexFormat
属性或 VERTEX_FORMAT
静态常量,可以作为几何体的选项传入。
var geometry = new Cesium.RectangleGeometry({ vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT // ... }); var geometry2 = new Cesium.RectangleGeometry({ vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT // ... }); var appearance = new Cesium.MaterialAppearance(/* ... */); var geometry3 = new Cesium.RectangleGeometry({ vertexFormat : appearance.vertexFormat // ... });
在参考文档中,请参阅:
有关材料的更多信息,请参阅 Fabric 。
有关未来计划,请参阅 几何和外观路线图。