3D Tiles Styling,这应该是一个使用率最高的例子了吧,因为觉得它的使用场景实现是太多了。它是可以根据Cesium3DTileFeature属性来进行个性化渲染的功能,比如分级渲染,距离渲染、条件显示。这些功能的实现都很简单,根据项目需要,创建一个相应的Cesium3DTileStyle对你,并赋值给Cesium3DTileset即可完成。但前提条件是,你的3D Tiles的属性字段中得有需要字段与值。如何判断是否有相应字段的方法是,在加载完成3dtiles之后,绑定一个点击事件,利用getProperty方法,查看是否有。代码如下:
function addListener () {
let scene = viewer.scene
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (click) {
// setColor()
var pickedFeature = viewer.scene.pick(click.position)
console.log("pickedFeature=", pickedFeature)
if (pickedFeature) {
// selectFeature(pickedFeature)
getAllProperty(pickedFeature)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
function getAllProperty (feature) {
var propertyNames = feature.getPropertyNames()
var length = propertyNames.length
for (var i = 0; i < length; ++i) {
var propertyName = propertyNames[i]
console.log(propertyName + ': ' + feature.getProperty(propertyName))
}
}
然后就可以在控制台查看属性了,如下图:
我只是测试练习,所以渲染效果就根据这些字段来。需要注意的是代码中属性字段的名称是严格区分大小写的。
测试中的分级渲染是根据建筑的高度,渲染成不同的颜色。代码如下:
var tileset
function add3dtiles (url) {
tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: url
}))
tileset.readyPromise.then((tileset) => {
//后面相应的效果代码都是放这里。
setColorByHeight()
viewer.flyTo(tileset)
})
}
function setColorByHeight () {
tileset.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: [
["${height} >= 300", "rgba(45, 0, 75, 0.5)"],
["${height} >= 200", "rgb(102, 71, 151)"],
["${height} >= 100", "rgb(170, 162, 204)"],
["${height} >= 50", "rgb(224, 226, 238)"],
["${height} >= 25", "rgb(252, 230, 200)"],
["${height} >= 10", "rgb(248, 176, 87)"],
["${height} >= 5", "rgb(198, 106, 11)"],
["true", "rgb(127, 59, 8)"],
],
},
});
}
还没有能力去看原码,但setColorByHeight函数中创建分级渲染的方法很清楚,"${height}就是获取Cesium3DTileFeature中height属性的值,如果该直大于等300,则赋值该Cesium3DTileFeature颜色为rgba(45, 0, 75,0.5)。其中rgba应该是GLSL中创建颜色的函数。最后一个是["true", "rgb(127, 59, 8)"],表达的意思是上面都设置完了,剩下的都用rgb(127, 59, 8)这个颜色。实现的效果如下图:
按距离渲染是指,Cesium3DTileFeature离某个点距离当作渲染条件进行的渲染。代码如下:
function colorByDistance () {
tileset.style = new Cesium.Cesium3DTileStyle({
defines: {
distance:
"distance(vec2(${longitude},${latitude}), vec2(-1.291777521, 0.7105706624))",
},
color: {
conditions: [
["${distance} > 0.0012", "color('red')"],
[
"${distance} > 0.0008",
"mix(color('yellow'), color('red'), (${distance} - 0.008) / 0.0004)",
],
[
"${distance} > 0.0004",
"mix(color('green'), color('yellow'), (${distance} - 0.0004) / 0.0004)",
],
["${distance} < 0.00001", "color('white')"],
[
"true",
"mix(color('blue'), color('green'), ${distance} / 0.0004)",
],
],
},
});
}
创建Cesium3DTileStyle的代码中可以看到,分成两部份。defines和color,从实现的效果来看,其实就是在defines中定义了一个叫distance的字段,但是字段的值是由其实它字段参与计算来的。计算的表达式是:
"distance(vec2(${longitude},${latitude}), vec2(-1.291777521, 0.7105706624))"
意思应该是:它调用了一个GLSL的内置函数distance,用原有属性的经纬度来计算它离vec2(-1.291777521, 0.7105706624)这个点的距离,distance的值,值得注意的是:vec2(-1.291777521, 0.7105706624)是弧度,而实例原码是:
"distance(vec2(radians(${Longitude}), radians(${Latitude})), vec2(-1.291777521, 0.7105706624))"
即调用了GLSL的radians函数,把经纬度转成弧度,但是我的属性数据本来就是弧度,所以不需要再转换。
。而在color的计算中,上面定义的distance就与原有的属性一样使用,其中mix是GLSL的内置函数。实现的效果如下图:
按条件显示是设置Cesium3DTileStyle可选属性show的显示条件即可,代码如下:
function hideByHeight () {
tileset.style = new Cesium.Cesium3DTileStyle({
show: "${height} > 200",
});
}
代码的意思是只显示height属性大于200的Cesium3DTileFeature进行渲染。
测试是点击某个Cesium3DTileFeature时,改变Cesium3DTileFeature的颜色。代码如下:
function addListener () {
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (click) {
// setColor()
var pickedFeature = viewer.scene.pick(click.position)
console.log("pickedFeature=", pickedFeature)
if (pickedFeature) {
// selectFeature(pickedFeature)
// getAllProperty(pickedFeature)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
function selectFeature (feature) {
var selectbuilding = feature.getProperty('id');
var s = "${id} ===" + selectbuilding
console.log("s=", s)
var selectcontent = s;
var transparentStyle = new Cesium.Cesium3DTileStyle({
color: {
conditions: [
[selectcontent, "rgb(255,255,0)"],
["${height} >= 300", "rgba(45, 0, 75, 0.5)"],
["${height} >= 200", "rgb(102, 71, 151)"],
["${height} >= 100", "rgb(170, 162, 204)"],
["${height} >= 50", "rgb(224, 226, 238)"],
["${height} >= 25", "rgb(252, 230, 200)"],
["${height} >= 10", "rgb(248, 176, 87)"],
["${height} >= 5", "rgb(198, 106, 11)"],
["true", "rgb(127, 59, 8)"],true表示剩余的显示的对象
]
},
});
tileset.style = transparentStyle
}
实现效果如下图: