前言: 网上找了不少资料,属实少,为后来者添加多一份参考。绘制geometry,主要的还是每个顶点的位置颜色。而由于我是先从three.js做好的效果,移植到cesium的时候 发现首先连坐标轴都不对。所以如果你想得到正确的结果,你最好想确认你的顶点位置 是对的。
效果
所需知识(新增修改 来自2022/4/28)
考虑到仍有许多没有webgl基础的人阅读此文章
特从传进去的realPos、colors、indices 分别说明
- realPos 位置属性
realPos 是由经纬度加高度(绝大部分数据都是如此)通过cesium内置的Cesium.Cartesian3.fromDegrees 此API 转换而来。 是一个一维数组,在后面传入顶点时需要用缓冲数组进行处理。指定Cesium每3个数值(x , y , z)读取为一个位置。 - colors 颜色属性
此处代码传入RGBA , 没有设置normalize(专业名词归一化,白话就是映射 => 0 - 255 => 0.0 - 1.0)的情况,此处传入的colors 应是 浮点数。如( 1.0, 0.0,0.0, 1.0) 表示透明度为1 的红色。指定Cesium 每4 个 数值读取为一个颜色 - indices 顶点索引
无需做缓冲处理,cesium内部已做处理,直接传入一维数组即可
核心
省去多余的数据处理部分主要是会引起误解,核心关键在于cesium是如何生成一个几何体的。three.js 里 是通过bufferGeometry的 各个bufferattribute。而cesium是通过geometryInstance 包装geometry,geometry里相关attribute,思路其实大致一样。通过appearance 这个外观类控制顶点着色器与片元着色器。所以第一步,我们需要装配相关的顶点属性。
generateGeometry: function (realPos, __colors, __indices) {
/**
* 构造 几何体的 内部属性
*/
var attributes = new Cesium.GeometryAttributes({
position: new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.DOUBLE,
componentsPerAttribute: 3,
values: new Float64Array(realPos),
}),
color: new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.FLOAT,
componentsPerAttribute: 4,
values: new Float32Array(__colors),
}),
})
//包围球
var boundingSphere = Cesium.BoundingSphere.fromVertices(
realPos,
new Cesium.Cartesian3(0.0, 0.0, 0.0),
3
)
// console.log(boundingSphere)
// 计算顶点法向量
var geometry = new Cesium.Geometry({
attributes: attributes,
indices: __indices,
primitiveType: Cesium.PrimitiveType.TRIANGLES,
boundingSphere: boundingSphere,
})
return geometry
},
- 需要说明的是: realPos 顾名思义, 是 世界坐标才能在cesium球体上正常的显示,同时 包围球的计算也是必须的。顶点属性应该都是一维数组。这个不清楚的话,去搜索,不再此赘述。
添加该集合体进场景
// 添加geometry 进场景
addPrimitive: function (realPos, __colors, __indices, wire) {
if (wire) {
//四面体的实例
var instance = new Cesium.GeometryInstance({
geometry: Cesium.GeometryPipeline.toWireframe(
this.generateGeometry(realPos, __colors, __indices)
),
})
} else {
var instance = new Cesium.GeometryInstance({
geometry: this.generateGeometry(
realPos,
__colors,
__indices
),
})
}
//加入场景
this.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: false,
}),
asynchronous: false,
})
)
},
- 两种表现形式,wire 为true时,不给三角面填充颜色,如上图效果一致。否则填色。
- 如果需要表现出一种阴影(高低起伏)效果,需要在返回的geometry前包装一个如 Cesium.GeometryPipeline.computeNormal(geometry),计算每个点的法向量,在外观appearance里的flat设置为false,即可。
新增(2022/6/21)
wire为false时,还需要Appearance里面flat 更改为false ,才可正常填色。不用再问我。
友情赠送
// 将经纬度高度 转换未世界坐标
transformCartesian3Pos: function (__positions) {
let realPos = []
for (let i = 0, ii = __positions.length; i < ii; i += 3) {
let position = Cesium.Cartesian3.fromDegrees(
__positions[i],
__positions[i + 1],
__positions[i + 2]
)
realPos.push(position.x, position.y, position.z)
}
return realPos
},