Cesium官方教程8-- 几何体和外观效果

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cesium官方教程8-- 几何体和外观效果相关的知识,希望对你有一定的参考价值。

原文地址:https://cesiumjs.org/tutorials/Geometry-and-Appearances/
几何体和外观效果(Geometry and Appearances)
这篇教程会教大家学习Primitive API中支持的几何体和外观效果。这篇教程并不是面向Cesium的普通用户,主要讨论Cesium的高级知识,包括自定义三角网(mesh),形状(shape),体(volume)以及他们的外观。如果你是初学者,建议先学下这篇教程。
Cesium可以使用Entity创建不同的几何体,比如多边形和椭圆等。比如把下面代码拷贝到 Sandcastle 的Hello World 就能创建一个带条纹状材质的矩形:
技术分享图片
技术分享图片
条纹矩形
这篇教程里,我们深入到图元内部,使用 Geometry类和 Appearance 类来创建效果。几何体定义了图元的结构,比如三角网、线、点等。外观(appearance)定义了图片的着色效果,包含完整的顶点(vertex)和片段(fragment)着色器(shader)以及着色器状态。
Cesium支持下列几何体:
技术分享图片
Box Geometry
BoxGeometry
技术分享图片
Box Outline Geometry
BoxOutlineGeometryA box
技术分享图片
Circle Geometry
CircleGeometry
技术分享图片
Circle Outline Geometry

CircleOutlineGeometry
技术分享图片
Corridor Geometry
CorridorGeometry
技术分享图片
Corridor Outline Geometry
CorridorOutlineGeometry 以米为单位的折线 和 一个挤压高度
技术分享图片
Cylinder Geometry
CylinderGeometry
技术分享图片
Cylinder Outline Geometry
CylinderOutlineGeometry圆柱, 椎体,半椎体
技术分享图片
Ellipse Geometry
EllipseGeometry
技术分享图片
Ellipse Outline Geometry
EllipseOutlineGeometry椭圆或者垂直挤压的椭圆
技术分享图片
Ellipsoid Geometry
EllipsoidGeometry
技术分享图片
Ellipsoid Outline Geometry
EllipsoidOutlineGeometry椭球体
技术分享图片
Extent Geometry
RectangleGeometry
技术分享图片
Extent Outline Geometry
RectangleOutlineGeometry矩形或者垂直挤压矩形
技术分享图片
Polygon Geometry
PolygonGeometry
技术分享图片
Polygon Outline Geometry
PolygonOutlineGeometry多边形,支持带洞以及垂直挤压
技术分享图片
Polyline Geometry
PolylineGeometry
技术分享图片
Polyline Outline Geometry
SimplePolylineGeometry像素宽度定义的折线段
技术分享图片
Volume Geometry
PolylineVolumeGeometry
技术分享图片
Volume Outline Geometry
PolylineVolumeOutlineGeometry一个二维图形沿着折线的延伸体。
技术分享图片
Sphere Geometry
SphereGeometry
技术分享图片
Sphere outline Geometry
SphereOutlineGeometry球体
技术分享图片
all Geometry
WallGeometry
技术分享图片
Wall Outline Geometry
WallOutlineGeometry垂直于地表的墙面
技术分享图片
几何体全家福

使用几何体和外观的优势:

性能 - 尤其是绘制大量静态图元(比如整个美国的邮政编码区域多边形),使用几何体可以把他们组合成一个单一的几何体,这样会减少cpu的开销,并且充分利用GPU的能力。组合几何体可以在web worker中完成,不会影响用户界面的响应。
灵活性 - 图元由几何体和外观构成。不过他们可以单独修改。新建的几何体可以兼容多种不同的外观,反之亦然。

底层访问 - 外观提供了近乎最底层的渲染访问,但是又不需要直接担心渲染 Renderer 的细节技术 。外观使下面的技术简单了很多:

编写完整的顶点和片段着色器GLSL代码。
使用用户自定义的渲染状态。

当然也有一些缺点:

使用几何体和外观需要写更多的代码,并且需要对图形知识有深刻的理解。Entity是应用层的抽象;而几何体和外观更像是一个传统3D引擎的级别。
对于静态数据,几何体合并非常有效,但是对于动态数据不适合。
使用几何体和外观来重新编写示例代码:
技术分享图片
没有用矩形的entity,我们使用了普通的 Primitive, 它里面连接和几何体和外观。现在先忽略 Geometry和 a GeometryInstance 的区别,只需知道instance是geometry的容器。
创建矩形几何体 RectangleGeometry的时候,这个矩形区域的三角网会贴合地球曲率。
技术分享图片
网格效果

因为我们预先知道这个几何体是在球面上,所以直接使用 EllipsoidSurfaceAppearance。这样做也能节省内存 ,支持所有的材质,因为几何体是在椭球体上方的固定高度(译者注:个人理解是说顶点可以只需要二维坐标,高度值可以当作uniform传进去)。
几何体合并
当使用一个图元去绘制多个静态几何体的时候,会有些效率提升。比如我们画两个矩形:
技术分享图片
技术分享图片
两个矩形

创建了另一个矩形的instance,然后把两个instance都添加到一个图元里,使用同一个外观去绘制。 一些外观允许为每个instance设置不同的属性(attribute)。比如,使用 PerInstanceColorAppearance 对每个instance着不同颜色。
技术分享图片
技术分享图片
不同颜色的矩形

每个intance有一个Color 属性。图元里创建一个PerInstanceColorAppearance,它知道使用每个instance的color属性去着色。
几何体合并允许Cesium高效的渲染大量几何体。下面示例绘制了2592个不同颜色的矩形。优化之后,渲染非常块。
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()
}));
技术分享图片
几何体合并

拾取
当instance合并之后,仍然支持独立访问。通常,我们会设置一个id属性, Scene.pick函数里通过它来判定哪个instance被拾取。这个id 可以任何js类型:字符串,数字,带属性的对象等等。
下面的示例创建一个带id 的instance,当它被点击的时候控制台会输出一个消息。
技术分享图片
使用id 而不是用instance对象本身去判定,主要是为了避免在创建图元之后,我们的图元甚至我们的项目对所有的instance对象 以及 它的几何体 一直被引用无法释放内存。因为几何体一般包含了一个比较大的数组,这种方式就可以帮我们节省大量内存。
几何体intances
目前为止,我们创建的每个几何体instance都只包含一个几何体。此外,instance竟然用来把同一个几何体放置在场景的不同位置,包括不同大小和方向。由于多个instance可以引用同一个几何体( Geometry),而每个instance可以有不同的偏移矩阵(modelMatrix)。这样,我们就只需要计算一次几何体(计算顶点等)而多次使用它。
技术分享图片
几何体 instance
下面的代码创建了一个EllipsoidGeometry 和 两个instance. 每个instance 引用了相同的椭球几何体,但是使用 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
})
}));
技术分享图片
椭球体instances

更新每个instance的属性
即便是已经添加到图元里,每个instance的一些属性也可以修改,包括:

Color : ColorGeometryInstanceAttribute 决定了几何体颜色。不过图元应该设置一个 PerInstanceColorAppearance外观。
Show :布尔变量决定instance是否可见,对任意instance都有效。
下面代码演示如何修改几何体instance的颜色:
This example shows how to change the color of the geometry instance:
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来获取到。attributes 里的值可以直接修改。这里,我们每2秒钟设置‘circle‘这个几何体随机颜色。
外观(Appearances)
几何体定义了结构。图元的另一个关键属性是appearance,决定图元的着色,也就说每个像素是如何上色的。一个图元可以有若干个几何体instance,但是只能有一个appearance属性。根据appearance类型不同,一个appearance可能有一个 material 属性,材质属性决定了大体的着色( the bulk of the shading)。
技术分享图片
Appearances
Cesium 包含下述外观类型:
技术分享图片
MaterialAppearance
MaterialAppearance 所有几何体都使用同一个外观,支持使用 materials 去定义着色效果.
技术分享图片
EllipsoidSurface
EllipsoidSurface MaterialAppearance 的简化版本,假定几何体都和地球椭球体平行,就像多边形一样。使用这个可以在计算大量顶点属性的时候节省内存
技术分享图片
PerInstanceColorAppearance
PerInstanceColorAppearance 每个instance使用不同的颜色去着色。
技术分享图片
PolylineMaterialAppearance
PolylineMaterialAppearance 支持在折线上设置材质。
技术分享图片
PolylineColorAppearance

PolylineColorAppearance支持折线在每个顶点或者每一段设置颜色。
外观完整的定义了顶点和片段着色器代码,在GPU中图元渲染的时候使用。除非要自定义外观,否则我们很少使用它们。外观也定义了完整的渲染你状态,它控制了图元渲染时候的GPU状态。我们可以使用高级的属性来定义渲染状态,比如 闭合closed 和 半透明translucent,外观会把他们转换为真正的底层状态,比如:
技术分享图片
一旦我们的外观创建了,我们不能修改它的renderState属性,但是我们能修改它的材质 material。当然,我们可以整个替换图元的appearance属性。
大部分外观包含 flat 和faceForward 属性, 这个直接控制了GLSL的着色效果。

flat - 纯色着色,不考虑光照效果。

faceForward - 当有光照的的时候,当视图正对它的时候反转法向量,避免墙体的背面是黑色的。
flat : true | faceForward : false | faceForward : true |
技术分享图片
flat:true
技术分享图片
faceForward : false
技术分享图片
faceForward : true
几何体和外观的匹配性
我们发现不是所有的外观都能作用在任意几何体上。比如EllipsoidSurfaceAppearance 不能用在WallGeometry 上,因为墙永远垂直地表,而不是平行地表。
隐含之意,一个外观能和一个几何体匹配,需要顶点格式匹配,也就是说几何体必须包含外观需要的顶点格式数据。创建一个几何体的时候,可以指定一个 VertexFormat 参数。
有时候为了简化问题,但是接受一点点浪费和效率低,可以计算一个几何体的所有顶点属性格式,这样就能和所有外观兼容(忽略per-instance属性)
技术分享图片
不兼容
如果使用EllipsoidSurfaceAppearance,比如我们只创建了顶点的位置属性,那么就会崩溃(get away)。
技术分享图片
通常,我们怎么知道某种外观需要哪种顶点格式?大部分外观都有一个 vertexFormat 属性, 甚至一个 VERTEX_FORMAT静态常量。
技术分享图片
同样,几何体的 vertexFormat 属性也决定了几何体是否可以合并。如果要合并,可以几何体类型不同,但是必须保证顶点格式一致。
相关资源
用户手册:

所有几何体
所有外观
图元Primitive
几何体instanceGeometryInstance

想了解材质的更多内容,请访问Fabric。
想了解这块的开发计划,请访问: Geometry and Appearances Roadmap.技术分享图片

技术分享图片

以上是关于Cesium官方教程8-- 几何体和外观效果的主要内容,如果未能解决你的问题,请参考以下文章

Cesium开发入门篇 05Cesium API结构介绍

Cesium官方教程10--高级粒子特效

Cesium官方教程10--高级粒子特效

Cesium官方教程5--地形图层

Cesium官方教程9--粒子系统

自定义Harbor外观,当Harbor遇上"神仙姐姐"