Cesium 下雨教程

📅 2026/7/11 21:01:29
Cesium 下雨教程
下雨 ·Rain· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么Cesium3DTileset 加载 3D Tiles 倾斜摄影Cesium PostProcessStage 全屏后期3D Tiles 流式 LOD 场景效果说明本案例演示下雨效果初始化viewer加载倾斜摄影或人工 3D Tiles 白膜并自动定位相机核心用到 Cesium3DTileset、Cesium、3D。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念Viewer聚合 Scene、Camera、Clock 与渲染循环是 Cesium 应用入口。Cesium3DTileset流式加载 LOD 瓦片适合城市倾斜摄影常用viewer.zoomTo(tileset)或viewBoundingSphere定位。阅读下方完整源码时建议从init/load/animate三条主线入手再深入 shader 与工具函数。实现步骤创建 Viewer配置地形/影像若案例需要并设置初始相机异步加载模型 / 3D Tiles / GeoJSON 等资源并加入 scene 或 entities在定时器或 GSAP 时间轴中更新 uniform / 变换驱动特效播放在requestAnimationFrame循环中更新状态并 renderCesium 为viewer.render或自动渲染代码要点import * as Cesium from cesium;let viewer; let tileset; let rainEffect; /**初始化viewer*/ const initViewer () { const DOM document.getElementById(box); viewer new Cesium.Viewer(DOM, { animation: false, //是否创建动画小器件左下角仪表 baseLayerPicker: false, //是否显示图层选择器右上角图层选择按钮 baseLayer: Cesium.ImageryLayer.fromProviderAsync( Cesium.ArcGisMapServerImageryProvider.fromUrl( https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer ) ), fullscreenButton: false, //是否显示全屏按钮右下角全屏选择按钮 timeline: false, //是否显示时间轴 infoBox: false, //是否显示信息框 }); let handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function (event) { let cartesian viewer.camera.pickEllipsoid(event.position); let cartographic Cesium.Cartographic.fromCartesian(cartesian); let lng Cesium.Math.toDegrees(cartographic.longitude); // 经度 let lat Cesium.Math.toDegrees(cartographic.latitude); // 纬度 let alt cartographic.height; // 高度椭球面height永远等于0 let coordinate { longitude: Number(lng.toFixed(6)), latitude: Number(lat.toFixed(6)), altitude: Number(alt.toFixed(2)), }; console.log(coordinate); }, Cesium.ScreenSpaceEventType.LEFT_CLICK); initScene(); addMaterial(); let interval; interval setInterval(() { if (tileset.customShader.uniforms.u_rainAlpha.value 0.5) { window.clearInterval(interval); return false; } tileset.customShader.uniforms.u_rainAlpha.value 0.05; }, 20); }; const addMaterial () { let appearance new Cesium.MaterialAppearance({ material: new Cesium.Material({ fabric: { type: MyImage, uniforms: { image: HOST /files/images/rain.png, }, }, }), fragmentShaderSource:#define MAX_RADIUS 2 #define DOUBLE_HASH 0 #define HASHSCALE1 .1031 #define HASHSCALE3 vec3(.1031, .1030, .0973) in vec2 v_st; float hash12(vec2 p) { vec3 p3 fract(vec3(p.xyx) * HASHSCALE1); p3 dot(p3, p3.yzx 19.19); return fract((p3.x p3.y) * p3.z); } vec2 hash22(vec2 p) { vec3 p3 fract(vec3(p.xyx) * HASHSCALE3); p3 dot(p3, p3.yzx19.19); return fract((p3.xxp3.yz)*p3.zy); } void main() { float iTime czm_frameNumber / 120.; float resolution 20.; vec2 uv v_st * resolution; vec2 p0 floor(uv); vec2 circles vec2(0.); for (int j -MAX_RADIUS; j MAX_RADIUS; j) { for (int i -MAX_RADIUS; i MAX_RADIUS; i) { vec2 pi p0 vec2(i, j); #if DOUBLE_HASH vec2 hsh hash22(pi); #else vec2 hsh pi; #endif vec2 p pi hash22(hsh); float t fract(0.3*iTime hash12(hsh)); vec2 v p - uv; float d length(v) - (float(MAX_RADIUS) 1.)*t; float h 1e-3; float d1 d - h; float d2 d h; float p1 sin(31.d1)smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1); float p2 sin(31.d2)smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2); circles 0.5normalize(v)((p2 - p1) / (2.h)(1. - t) * (1. - t)); } } circles / float((MAX_RADIUS21)(MAX_RADIUS*21)); float intensity mix(0.01, 0.15, smoothstep(0.1, 0.6, abs(fract(0.05iTime 0.5)2.-1.))); vec3 n vec3(circles, sqrt(1. - dot(circles, circles))); vec3 color texture(image_0, uv/resolution - intensityn.xy).rgb 5.pow(clamp(dot(n, normalize(vec3(1., 0.7, 0.5))), 0., 1.), 6.); out_FragColor vec4(color, 0.5); }, });var positions Cesium.Cartesian3.fromDegreesArray([ 113.059339, 22.645815, 113.060204, 22.645928, 113.060253, 22.642831, 113.059298, 22.642799, ]); viewer.scene.primitives.add( new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: Cesium.PolygonGeometry.fromPositions({ positions: positions, height: 70, }), }), appearance: appearance, }) ); }; const initScene async () { tileset await Cesium.Cesium3DTileset.fromUrl( FILE_HOST 3dtiles/house/tileset.json, { customShader: new Cesium.CustomShader({ uniforms: { u_lightColor: { type: Cesium.UniformType.VEC3, value: new Cesium.Cartesian3(1, 1, 1), }, u_rainAlpha: { type: Cesium.UniformType.FLOAT, value: 0, }, }, fragmentShaderText:#define MAX_RADIUS 2 // Set to 1 to hash twice. Slower, but less patterns. #define DOUBLE_HASH 0 // Hash functions shamefully stolen from: // https://www.shadertoy.com/view/4djSRW #define HASHSCALE1 .1031 #define HASHSCALE3 vec3(.1031, .1030, .0973) float hash12(vec2 p) { vec3 p3 fract(vec3(p.xyx) * HASHSCALE1); p3 dot(p3, p3.yzx 19.19); return fract((p3.x p3.y) * p3.z); } vec2 hash22(vec2 p) { vec3 p3 fract(vec3(p.xyx) * HASHSCALE3); p3 dot(p3, p3.yzx19.19); return fract((p3.xxp3.yz)*p3.zy);} void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) { vec3 positionEC fsInput.attributes.positionEC; vec3 positionMC fsInput.attributes.positionMC; vec2 uv fsInput.attributes.texCoord_0 * 500.; vec3 pos_dx dFdx(positionEC); vec3 pos_dy dFdy(positionEC); vec3 normalEC normalize(cross(pos_dx, pos_dy)); vec4 positionWC normalize(czm_inverseView * vec4(positionEC,1.0)); vec3 normalWC normalize(czm_inverseViewRotation * normalEC); float time czm_frameNumber / 60.0; vec2 p0 floor(uv); vec2 circles vec2(0.); for (int j -MAX_RADIUS; j MAX_RADIUS; j) { for (int i -MAX_RADIUS; i MAX_RADIUS; i) { vec2 pi p0 vec2(i, j); #if DOUBLE_HASH vec2 hsh hash22(pi); #else vec2 hsh pi; #endif vec2 p pi hash22(hsh);float t fract(0.3*time hash12(hsh)); vec2 v p - uv; float d length(v) - (float(MAX_RADIUS) 1.)*t;float h 1e-3; float d1 d - h; float d2 d h; float p1 sin(31.d1)smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1); float p2 sin(31.d2)smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2); circles 0.5normalize(v)((p2 - p1) / (2.h)(1. - t) * (1. - t)); } } circles / float((MAX_RADIUS21)(MAX_RADIUS*21)); vec3 n vec3(circles, sqrt(1. - dot(circles, circles))); material.diffuse mix(material.diffuse, vec3((nvec3(1.2)).r) , u_rainAlphasmoothstep(0., .5, dot(positionWC.xyz, normalWC))); material.diffuse min(max(0.0, dot(normalEC, czm_sunDirectionEC)1.0) u_lightColor, 1.0);}, }), } ); viewer.flyTo(tileset); viewer.scene.primitives.add(tileset);rainEffect new Cesium.PostProcessStage({ fragmentShader:uniform sampler2D colorTexture; in vec2 v_textureCoordinates; float hash(float x){ return fract(sin(x23.3)13.13); } void main(){ float time czm_frameNumber / 120.0; vec2 resolution czm_viewport.zw; vec2 uv(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y); vec3 cvec3(.6,.7,.8); float a-.4; float sisin(a),cocos(a); uv*mat2(co,-si,si,co); uvlength(uvvec2(0,8.9)).31.; float v1.-sin(hash(floor(uv.x100.))2.); float bclamp(abs(sin(20.timevuv.y(5./(2.v))))-.95,0.,1.)20.; cvb; out_FragColor mix(texture(colorTexture, v_textureCoordinates), vec4(c, 1), 0.5); }, }); viewer.scene.postProcessStages.add(rainEffect); }; initViewer();完整源码GitHub小结本文提供下雨完整 Cesium.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Cesium.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库