之前的笔记种记录了Cesium可以使用实体(如多边形和椭球)创建不同的地质类型。例如:使用点阵图在地球上创建一个矩形
let view = new Cesium.Viewer('cesiumDemo');
view.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
})
}
});
下面将记录primitives ,并查看形成它们的类型Geometry和Appearance类型。几何定义了primitives的结构,即构成原语的三角形,线条或点。外观定义了primitives的阴影,包括其完整的GLSL顶点和片段着色器以及渲染状态。
Cesium支持以下几何形状
使用几何和外观的好处是:
还有一些缺点:
用primitives将上面的例子重写
let view = new Cesium.Viewer('cesiumDemo', {
baseLayerPicker: false,
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url: 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
}),
shadows: true
});
let scene = view.scene;
scene.globe.enableLighting = true;
// 创建几何实例
let instance = new Cesium.GeometryInstance({
// 矩形几何
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
})
});
// 添加
scene.primitives.add(new Cesium.Primitive({
geometryInstances: instance,
// 几何外观
appearance: new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Stripe')
})
}));
当我们使用一个primitives绘制多个静态几何时,我们看到了性能优势。例如,我们画出两个矩形。
// 创建几何实例
let instance = new Cesium.GeometryInstance({
// 矩形几何
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
})
});
// 另一个实例
let anotherInstance = new Cesium.GeometryInstance({
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0),
})
});
// 添加
scene.primitives.add(new Cesium.Primitive({
// 用数组方式可以添加多个实例
geometryInstances: [instance,anotherInstance],
// 几何外观
appearance: new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Stripe')
})
}));
我们创建了另一个具有不同矩形的实例,然后将这两个实例提供给基元。这两个实例都使用相同的外观。一些外观允许每个实例提供唯一的属性。例如,我们可以使用PerInstanceColorAppearance不同颜色来遮蔽每个实例。
// 创建几何实例
let 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)
}
});
// 另一个实例
let 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,它知道使用每个实例的颜色属性来确定阴影。
组合几何使Cesium可以有效地绘制出几何图形。以下示例绘制2,592个独特的彩色矩形。它将优化几何,然后绘制非常快。
let 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()
}));
实例组合后,它们仍然可以独立访问。特别是,我们可以分配一个id实例并使用它来确定实例是否被选中Scene.pick。 id可以是任何JavaScript类型:字符串,数字,具有其属性的对象等。
以下示例使用a创建一个实例id,并在单击该控件时将消息写入控制台。
let instance = new Cesium.GeometryInstance({
id: 'instance',
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
}
});
scene.primitives.add(new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance()
}));
// 添加监听事件
let handler = new Cesium.ScreenSpaceEventHandler();
handler.setInputAction((movement)=>{
let pick = scene.pick(movement.position);
if(Cesium.defined(pick) && pick.id==='instance'){
console.log('单击了实例')
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
使用id,而不是对实例本身的引用,允许原始和我们的应用程序避免在构建原语后,在内存中保留对完整实例的引用,包括其对几何的引用。由于几何可以包含几个大型类型的数组,这样我们可以节省大量的内存。
到目前为止,我们已经将几何实例定义为几何体的容器。此外,实例用于在场景的不同部分中定位,缩放和旋转相同的几何。这是可能的,因为多个实例可以引用相同Geometry,并且每个实例可以具有不同的modelMatrix。这使我们只能计算几何一次,并重复使用多次。
几何体的每个实例属性在添加到基元之后也可以进行更新。每个实例的属性包括:
此示例显示如何更改几何实例的颜色:
let 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'
});
let primitive = new Cesium.Primitive({
geometryInstances : circleInstance,
appearance : new Cesium.PerInstanceColorAppearance({
translucent : false,
closed : true
})
});
scene.primitives.add(primitive);
setInterval(()=> {
var attributes = primitive.getGeometryInstanceAttributes('circle');
attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({alpha : 1.0}));
},2000);
几何实例的属性可以从原语使用中检索primitive.getGeometryInstanceAttributes。attributes可以直接改变属性。在这种情况下,我们正在改变attributes.color为每2000毫秒等于一个新的随机生成的颜色。
几何定义结构。原语的另一个关键属性appearance定义了原始的阴影,即单个像素如何着色。一个原语可以有多个几何实例,但它只能有一个外观。根据外观的类型,外观将会material定义阴影的大部分。
Cesium有以下外观:
外观定义绘制原始图形时在GPU上执行的完整GLSL顶点和片段着色器。除非我们正在编写自定义的外观,否则我们很少会碰到这些。外观还定义了完整渲染状态,当绘制原始图形时控制GPU的状态。我们可以直接定义渲染状态或使用像更高级别的性能closed和translucent,它的出现将转换为渲染状态。例如:
let appearance = new Cesium.PerInstanceColorAppearance({
translucent : false,
closed : true
});
let anotherAppearance = new Cesium.PerInstanceColorAppearance({
renderState : {
depthTest : {
enabled : true
},
cull : {
enabled : true,
face : Cesium.CullFace.BACK
}
}
});
一旦创建了外观,我们就不能改变它的renderState属性,但是我们可以改变它的属性material。同样,我们也可以改变原始的appearance属性。
大多数外观也有flat和faceForward属性,间接控制GLSL着色器。
我们已经看到,并不是所有的外观都适用于所有几何体。例如,EllipsoidSurfaceAppearance不适合WallGeometry因为墙壁垂直于球体而不是平行的。
除了这样的语义之外,为了与几何兼容的外观,它们必须具有匹配的顶点格式,这意味着几何必须具有外观所期望的数据作为输入。VertexFormat创建几何时可以提供A。
我们可以通过请求几何计算所有顶点属性来保持简单,但效率低下,浪费,这将使几何与所有外观兼容(忽略每个实例的属性;见下文)。
let geometry = new Cesium.RectangleGeometry({
vertexFormat : Cesium.VertexFormat.ALL
// ...
});
EllipsoidSurfaceAppearance例如,如果我们正在使用,我们可以只是请求位置。
let geometry = new Ceisum.RectangleGeometry({
vertexFormat : Ceisum.VertexFormat.POSITION_ONLY
// ...
});
一般来说,我们如何知道用于给定外观的顶点格式?大多数外观都有一个vertexFormat属性,甚至一个VERTEX_FORMAT静态常量。
let geometry = new Ceisum.RectangleGeometry({
vertexFormat : Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT
// ...
});
let geometry2 = new Ceisum.RectangleGeometry({
vertexFormat : Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT
// ...
});
let appearance = new Ceisum.MaterialAppearance(/* ... */);
let geometry3 = new Ceisum.RectangleGeometry({
vertexFormat : appearance.vertexFormat
// ...
});
而且,几何形状vertexFormat决定了它是否可以与其他几何组合。两个几何不一定是相同的类型; 他们只需要匹配的顶点格式。
官方文档