翻译自官方文档。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 差。