大家好,我是日拱一卒的攻城师不浪,专注可视化、数字孪生、前端提效、nodejs、AI学习、GIS等学习沉淀,这是2024年输出的第22/100篇文章。
交流合作:brown_7778。
前言
上次发了一篇水淹模拟的动画演示cesium中如何高性能渲染3D模型(附水淹分析模拟),其中的水就是简单的用entity
渲染了一个立方体并附着了颜色。
说句实话,这效果如果摆在甲方面前,他可能上来就会给我一个大逼斗!
所以我痛定思痛,决定认真努力工作,立马端正态度。
思路
要想让水体变得逼真,除了要用一个几何体去充当它的载体,更重要的是要有真实的水体材质
,把材质铺贴在几何体之上。
但是光有材质也不行,因为水是动态的,所以还要想办法让材质动起来。
绘制几何体
先用RectangleGeometry画一个矩形的几何体
const rectangleGeometry = new Cesium.RectangleGeometry({
// fromDegrees接收西、南、东、北四个经纬线的具体坐标,从而框出一个矩形
rectangle: Cesium.Rectangle.fromDegrees(120.34, 36.06, 120.42, 36.13),
// 要计算的顶点属性
vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
// 几何体的垂直高度
height: 1000,
})
可能有的小伙伴不知道Cesium.Rectangle.fromDegrees
参数的四个点要怎么获取,具体描述如下:
再画一张意象图:
有的小伙伴说,我理解了这个范围取值,但是我要怎么在地球上去获取具体的坐标点位
呢?这也难不倒我们,我们可以直接在cesium初始化成功之后,开发一个辅助获取坐标点位的功能。
获取点击坐标
// 监听点击事件,拾取具体坐标点位
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((e) => {
const clickPosition = viewer.scene.camera.pickEllipsoid(e.position);
const randiansPos = Cesium.Cartographic.fromCartesian(clickPosition);
console.log(
"经度:" +
Cesium.Math.toDegrees(randiansPos.longitude) +
", 纬度:" +
Cesium.Math.toDegrees(randiansPos.latitude)
);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
以上代码就是通过监听鼠标左键点击,获取到屏幕坐标
,再把屏幕坐标转换成投影坐标系
。
创建几何体实例
const geometryInstance = new Cesium.GeometryInstance({
geometry: rectangleGeometry
})
Primitive
创建图元几何图形,渲染几何体,并给几何体上材质。
const primitive = new Cesium.Primitive({
geometryInstances: geometryInstance,
// appearance用于渲染图元的外观
appearance: new Cesium.EllipsoidSurfaceAppearance({
// 材质参数
material: new Cesium.Material({
fabric: {
type: "Water",
uniforms: {
baseWaterColor: new Cesium.Color(
64 / 255.0,
157 / 255.0,
253 / 255.0,
0.5
),
normalMap: "/images/waterNormals.jpg",
frequency: 1000.0,
animationSpeed: 0.1,
amplitude: 10,
specularIntensity: 10,
},
},
}),
})
})
- fabric:通过配置cesium提供的现有的一些参数组合,可以幕后生成并组装成
glsl
着色器代码
具体参数组合参考:http://cesium.xin/cesium/cn/Documentation1.95/Material.html?classFilter=Material
换句话说:cesium已经提前预置好了一些着色器
代码,并可以通过fabric这个参数的配置去生成一些常见的效果,而省去我们需要写glsl代码的一些成本。
所以我们直接选择可以生成水
的代码片段,参数解析如下:
-
baseWaterColor : rgba 颜色对象水的基色。
-
blendColor :从水混合到非水区域时使用的 rgba 颜色对象。
-
specularMap :用于指示水域的单通道纹理。
-
normalMap :水法线扰动的法线贴图。
-
frequency :控制波数的数字。
-
animationSpeed : 控制水的动画速度的数字。
-
amplitude :控制水波振幅的数字。
-
specularIntensity :控制镜面反射强度的数字。
以上,然后对应我们的代码,我们就可以通过调整这些参数配置,去调整水的样式了,非常方便。
最后别忘记,把生成的primitive添加到场景当中。
viewer.scene.primitives.add(primitive)
就这样,一个真实的水体就通过cesium成功的渲染出来了。
甲方看了后直竖大拇指:这就叫专业!
【开源地址】:https://github.com/tingyuxuan2302/cesium-vue3-vite/blob/github/src/views/material/water.vue
有需要进技术产品开发交流群(可视化&GIS)可以加我:brown_7778,也欢迎
数字孪生可视化领域
的交流合作。
最后,如果觉得文章对你有帮助,也希望可以一键三连👏👏👏,支持我持续开源和分享~