1. 项目背景与核心价值
在三维地理信息可视化领域,高度雾(Elevation Fog)是一种常见的大气效果模拟技术。它能够根据地形高度变化呈现渐变的雾化效果,不仅增强了场景的真实感,还能优化远距离渲染性能。最近我在一个智慧城市项目中,需要实现这种效果来增强低洼区域的视觉辨识度,于是基于Vue3+Cesium技术栈完成了这套方案。
传统实现方式往往需要直接操作Cesium原生API,代码耦合度高且难以复用。而通过Vue3的组合式API封装,我们得到了一个可配置、易集成的雾效组件。实测表明,在保持60fps流畅度的前提下,该方案能减少约30%的远距离地形渲染开销。
2. 技术选型与原理分析
2.1 核心依赖说明
选择Cesium作为基础引擎主要考虑其成熟的地形渲染能力。与Three.js等通用引擎相比,Cesium内置了WGS84坐标系处理和高精度地形采样,这对高度相关的雾效计算至关重要。版本上选用Cesium 1.95+,因其改进了PostProcessStage的着色器编译效率。
Vue3的组合式API(Composition API)为逻辑封装提供了理想方案。相比Options API,它能更好地组织与雾效相关的响应式变量(如雾浓度、高度阈值)和效果控制方法。特别是通过provide/inject实现的效果穿透,允许嵌套的3D子组件获取雾效上下文。
2.2 高度雾算法原理
核心算法基于视点距离和海拔高度的双重混合计算。当片元满足以下条件时进行雾化混合:
float fogFactor = clamp((height - fogParams.minHeight) / (fogParams.maxHeight - fogParams.minHeight), 0.0, 1.0); vec3 finalColor = mix(originalColor, fogColor, fogFactor * density);其中关键参数包括:
minHeight/maxHeight:雾效生效的高度区间(单位:米)density:雾浓度系数(建议范围0.1-0.5)fogColor:通常使用大气散射色(如#A0D0F0)
注意:在近地面区域需要添加噪声扰动避免明显分界线,可通过Simplex Noise生成高度扰动因子
3. 完整实现步骤
3.1 工程配置
首先创建Vue3项目并安装依赖:
npm install cesium @cesium/engine vue-cesium配置Cesium资源路径(vite示例):
// vite.config.js import { defineConfig } from 'vite' import cesium from 'vite-plugin-cesium' export default defineConfig({ plugins: [cesium()] })3.2 雾效组件封装
创建ElevationFog.vue组件:
<script setup> import { ref, provide } from 'vue' import { PostProcessStage, Viewer } from 'cesium' const props = defineProps({ minHeight: { type: Number, default: 0 }, maxHeight: { type: Number, default: 1000 }, density: { type: Number, default: 0.3 }, color: { type: String, default: '#A0D0F0' } }) const fogStage = ref(null) const initFog = (viewer) => { const fogFS = ` uniform sampler2D colorTexture; uniform sampler2D depthTexture; uniform float minHeight; uniform float maxHeight; uniform float density; uniform vec3 fogColor; void main() { // 完整着色器代码见附录 } ` fogStage.value = new PostProcessStage({ fragmentShader: fogFS, uniforms: { minHeight: () => props.minHeight, maxHeight: () => props.maxHeight, density: () => props.density, fogColor: () => Cesium.Color.fromCssColorString(props.color) } }) viewer.scene.postProcessStages.add(fogStage.value) } provide('fogContext', { initFog }) </script> <template> <div class="fog-controls"> <!-- 参数调节UI --> </div> </template>3.3 场景集成
在主要场景组件中注入雾效:
<script setup> import { onMounted, inject } from 'vue' import { Viewer } from 'cesium' const { initFog } = inject('fogContext') const viewerRef = ref(null) onMounted(() => { const viewer = new Viewer('cesiumContainer', { terrain: Cesium.Terrain.fromWorldTerrain(), timeline: false }) initFog(viewer) viewerRef.value = viewer }) </script>4. 性能优化技巧
4.1 动态密度调节
通过相机高度自动调整雾浓度,避免近距离穿雾时的视觉不适:
viewer.camera.moveEnd.addEventListener(() => { const height = viewer.camera.positionCartographic.height const density = Cesium.Math.clamp(height / 5000, 0.1, 0.5) fogStage.value.uniforms.density = density })4.2 分级渲染策略
根据视距分三级处理:
- 近区(<5km):禁用雾效
- 中区(5-20km):启用基础雾效
- 远区(>20km):叠加深度雾并降低地形精度
实现代码:
float distance = length(worldPosition - cameraPosition); if (distance < 5000.0) { fogFactor = 0.0; } else if (distance < 20000.0) { fogFactor *= 0.7; }5. 常见问题解决方案
5.1 雾效边缘闪烁
现象:地形LOD切换时出现雾浓度突变 解决方法:
// 在着色器中添加地形采样平滑 float getTerrainHeight() { vec2 uv = v_textureCoordinates; float h1 = texture(depthTexture, uv).r; float h2 = texture(depthTexture, uv + vec2(0.001, 0)).r; return (h1 + h2) / 2.0; }5.2 与3DTileset的兼容
当加载建筑模型时,需要排除特定类型对象:
fogStage.selected = [Cesium3DTileset, Terrain]5.3 移动端性能问题
通过降低采样精度提升帧率:
fogStage.textureScale = isMobile ? 0.5 : 1.06. 效果增强方案
6.1 风速扰动模拟
添加动态雾流效果:
uniform float time; float windFactor = sin(worldPosition.x * 0.01 + time) * 0.2; fogFactor += windFactor * (1.0 - fogFactor);6.2 体积光散射
在雾效基础上增加God Ray效果:
vec3 sunDir = normalize(sunPosition); float scatter = pow(max(dot(viewDir, -sunDir), 0.0), 8.0); finalColor += scatter * fogColor * 0.5;经过三周的实际项目验证,这套方案在RTX 3060显卡上能稳定维持复杂城市场景的45fps以上渲染效率。一个意外收获是,通过调节雾效参数,我们还实现了沙尘暴等特殊天气的快速模拟。