deeptwins-engine-3d 0.1.65 → 0.1.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/esm/constant.d.ts +10 -0
  2. package/dist/esm/constant.js +10 -1
  3. package/dist/esm/drawCommand/viewShed/RectangularSensorPrimitive.d.ts +1 -0
  4. package/dist/esm/drawCommand/viewShed/ViewShedAnalyserLayer.d.ts +1 -0
  5. package/dist/esm/drawer/common.d.ts +1 -0
  6. package/dist/esm/drawer/coordinate.d.ts +1 -0
  7. package/dist/esm/drawer/index.d.ts +1 -1
  8. package/dist/esm/drawer/shape/BaseShape.d.ts +1 -0
  9. package/dist/esm/graphicLayer/BaseLayer.d.ts +23 -0
  10. package/dist/esm/graphicLayer/BaseLayer.js +387 -65
  11. package/dist/esm/graphicLayer/BasePrimitiveInstance.d.ts +0 -1
  12. package/dist/esm/graphicLayer/BasePrimitiveInstance.js +0 -7
  13. package/dist/esm/graphicLayer/BaseSource.d.ts +1 -1
  14. package/dist/esm/graphicLayer/BoxPrimitiveInstance.d.ts +0 -1
  15. package/dist/esm/graphicLayer/BoxPrimitiveInstance.js +4 -8
  16. package/dist/esm/graphicLayer/EllipsePrimitiveInstance.d.ts +0 -1
  17. package/dist/esm/graphicLayer/EllipsePrimitiveInstance.js +5 -9
  18. package/dist/esm/graphicLayer/EllipsoidPrimitiveInstance.d.ts +0 -1
  19. package/dist/esm/graphicLayer/EllipsoidPrimitiveInstance.js +5 -9
  20. package/dist/esm/graphicLayer/GraphicLayerCollection.js +20 -27
  21. package/dist/esm/graphicLayer/ModelPrimitiveInstance.d.ts +0 -1
  22. package/dist/esm/graphicLayer/ModelPrimitiveInstance.js +0 -7
  23. package/dist/esm/graphicLayer/PolygonGroundPrimitiveImageMaterialInstance.js +5 -2
  24. package/dist/esm/graphicLayer/PolygonPrimitiveImageMaterialInstance.js +5 -2
  25. package/dist/esm/graphicLayer/PolygonPrimitiveInstance.d.ts +0 -1
  26. package/dist/esm/graphicLayer/PolygonPrimitiveInstance.js +5 -9
  27. package/dist/esm/graphicLayer/PolylineGroundPrimitiveInstance.d.ts +0 -1
  28. package/dist/esm/graphicLayer/PolylineGroundPrimitiveInstance.js +4 -8
  29. package/dist/esm/graphicLayer/PolylinePrimitiveInstance.d.ts +0 -1
  30. package/dist/esm/graphicLayer/PolylinePrimitiveInstance.js +4 -8
  31. package/dist/esm/graphicLayer/PolylineVolumePrimitiveInstance.d.ts +0 -1
  32. package/dist/esm/graphicLayer/PolylineVolumePrimitiveInstance.js +4 -8
  33. package/dist/esm/graphicLayer/WallPrimitiveInstance.d.ts +0 -1
  34. package/dist/esm/graphicLayer/WallPrimitiveInstance.js +4 -8
  35. package/dist/esm/index.d.ts +2 -0
  36. package/dist/esm/index.js +6 -2
  37. package/dist/esm/map/Map.d.ts +9 -0
  38. package/dist/esm/map/Map.js +115 -2
  39. package/dist/esm/material/AtmosphericDispersion.d.ts +71 -0
  40. package/dist/esm/material/AtmosphericDispersion.js +485 -33
  41. package/dist/esm/material/GlobalVolumetricCloud.d.ts +117 -0
  42. package/dist/esm/material/GlobalVolumetricCloud.js +219 -223
  43. package/dist/esm/material/WeatherEffects.d.ts +64 -14
  44. package/dist/esm/material/WeatherEffects.js +279 -95
  45. package/dist/esm/material/entity/ImageMaterialProperty.d.ts +1 -0
  46. package/dist/esm/material/shader/AtmosphericShader.glsl +244 -0
  47. package/dist/esm/material/shader/RainShader.glsl +44 -6
  48. package/dist/esm/material/shader/lightning.glsl +70 -0
  49. package/dist/esm/measure/BaseDraw.d.ts +1 -0
  50. package/dist/esm/measure/types.d.ts +1 -0
  51. package/dist/esm/measure/utils.d.ts +1 -0
  52. package/dist/esm/sceneFusion/Airway.d.ts +0 -0
  53. package/dist/esm/sceneFusion/Airway.js +692 -0
  54. package/dist/esm/tileLayer/ArcGisLayer.d.ts +1 -0
  55. package/dist/esm/tileLayer/ImageryLayer.d.ts +1 -0
  56. package/dist/esm/tileLayer/MvtVectorLoad.d.ts +13 -0
  57. package/dist/esm/tileLayer/MvtVectorLoad.js +245 -49
  58. package/dist/esm/tool/common.d.ts +1 -0
  59. package/dist/esm/tool/utils.d.ts +1 -0
  60. package/dist/esm/typings.d.ts +8 -0
  61. package/dist/esm/visualization/BaseHeatmap.d.ts +5 -0
  62. package/dist/esm/visualization/BaseHeatmap.js +54 -12
  63. package/dist/esm/visualization/Heatmap2d.d.ts +1 -0
  64. package/dist/esm/visualization/Heatmap2d.js +17 -26
  65. package/dist/esm/visualization/Heatmap3d.d.ts +8 -2
  66. package/dist/esm/visualization/Heatmap3d.js +195 -59
  67. package/dist/umd/deeptwins-engine-3d.min.js +1 -1
  68. package/package.json +1 -1
@@ -1,186 +1,225 @@
1
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
1
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
2
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
3
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
5
4
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6
5
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
7
6
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
7
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
8
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
9
9
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
10
- /**
11
- * 全球体积云类 - GlobalVolumetricCloud
12
- *
13
- * 一个用于在Cesium中创建和管理高质量体积云效果的封装类。
14
- * 基于PostProcessStage后处理技术实现的物理基于的体积云渲染系统,
15
- * 支持实时云形态变化、光照散射、体积阴影等高级特性。
16
- *
17
- * 功能特点:
18
- * - 基于物理的体积云渲染
19
- * - 实时风场模拟
20
- * - 可调节的云类型和特征
21
- * - 动态光照和阴影
22
- * - 性能优化的渲染管线
23
- *
24
- * 使用示例:
25
- * ```javascript
26
- * // 创建Cesium Viewer
27
- * const viewer = new Cesium.Viewer('cesiumContainer');
28
- *
29
- * // 初始化体积云系统
30
- * const clouds = new GlobalVolumetricCloud(viewer: viewer, {
31
- * cloudType: 0.5, // 混合积云和层云
32
- * cloudCover: 0.5, // 中等云量
33
- * cloudHeight: 5000.0, // 云层高度
34
- * densityMultiplier: 1.2, // 密度调整
35
- * windSpeedRatio: 0.5 // 风速
36
- * });
37
- *
38
- * // 更新云参数
39
- * clouds.updateParameters({
40
- * cloudType: 0.8, // 更多积云特征
41
- * cloudSharpness: 1.5 // 更清晰的云边界
42
- * });
43
- *
44
- * // 控制云显示
45
- * clouds.hide(); // 隐藏云
46
- * clouds.show(); // 显示云
47
- *
48
- * // 销毁云系统
49
- * clouds.destroy(); // 清理资源
50
- * ```
51
- */
10
+ import * as Cesium from 'deeptwins-cesium';
11
+ var DEFAULT_SKY_AMBIENT_COLOR = '#B4D9F3';
12
+ var DEFAULT_GROUND_AMBIENT_COLOR = '#d6d6d8';
13
+ var DEFAULT_WIND_VECTOR = new Cesium.Cartesian3(100, 0, 0);
14
+ var createDefaultCloudParams = function createDefaultCloudParams() {
15
+ return {
16
+ densityMultiplier: 1.5,
17
+ detailStrength: 0.69,
18
+ cloudSharpness: 1.032,
19
+ rainClouds: 0.45,
20
+ currentWindVectorWC: Cesium.Cartesian3.clone(DEFAULT_WIND_VECTOR),
21
+ cloudCover: 0.039,
22
+ cloudHeight: 8000.0,
23
+ cloudThickness: 1000.0,
24
+ absoluteMaxDistance: 50000000,
25
+ absorption: 0.004,
26
+ windSpeedRatio: 0.3,
27
+ scatteringCoefficient: 0.01,
28
+ illuminationCoefficient: 0.01,
29
+ cloudSeed: Math.random() * 100.0,
30
+ cloudType: 0,
31
+ cloudTurbulence: 0.5,
32
+ cloudClumping: 0.75,
33
+ cloudAnvil: 0,
34
+ skyAmbientColor: DEFAULT_SKY_AMBIENT_COLOR,
35
+ groundAmbientColor: DEFAULT_GROUND_AMBIENT_COLOR,
36
+ maxVisibleHeight: 30000
37
+ };
38
+ };
39
+
40
+ // 全球体积云
52
41
  var GlobalVolumetricCloud = /*#__PURE__*/function () {
53
- /**
54
- * 构造函数
55
- *
56
- * @param {Cesium.Viewer} viewer - Cesium查看器实例
57
- * @param {Object} options - 体积云配置参数对象
58
- * @param {number} [options.densityMultiplier=1.5] - 密度倍增器,影响整体云密度,推荐值范围: 0.5 ~ 3.0
59
- * @param {number} [options.detailStrength=0.69] - 细节强度,控制云内部结构复杂度,推荐值范围: 0.1 ~ 2.0
60
- * @param {number} [options.cloudSharpness=1.032] - 云边界锐度,控制云边缘清晰度,推荐值范围: 0.5 ~ 4.0
61
- * @param {number} [options.rainClouds=0.45] - 雨云特征强度,影响云的厚重感,推荐值范围: 0.0 ~ 1.0
62
- * @param {Cesium.Cartesian3} [options.currentWindVectorWC] - 风向向量,默认值为new Cesium.Cartesian3(100, 0, 0)
63
- * @param {number} [options.cloudCover=0.039] - 云覆盖比例,控制天空中云的覆盖面积
64
- * @param {number} [options.cloudHeight=8000.0] - 云层底部高度(米)
65
- * @param {number} [options.cloudThickness=1000.0] - 云层厚度(米)
66
- * @param {number} [options.absoluteMaxDistance=50000000] - 最大可视距离
67
- * @param {number} [options.absorption=0.004] - 吸收系数,控制光在云中的衰减
68
- * @param {number} [options.windSpeedRatio=0.3] - 风速比率,控制云移动速度
69
- * @param {number} [options.scatteringCoefficient=0.01] - 散射系数,影响光的散射强度
70
- * @param {number} [options.illuminationCoefficient=0.01] - 照明系数
71
- * @param {number} [options.cloudSeed=Math.random()*100] - 随机种子,影响云的形态分布
72
- * @param {number} [options.cloudType=0] - 云类型,0=层云, 1=积云,中间值为混合类型
73
- * @param {number} [options.cloudTurbulence=0.5] - 湍流强度,控制云的不规则程度
74
- * @param {number} [options.cloudClumping=0.75] - 团块程度,控制云的聚集特性
75
- * @param {number} [options.cloudAnvil=0] - 砧状云特征,控制特殊云形态
76
- * @param {string} [options.skyAmbientColor='#B4D9F3'] - 天空环境颜色
77
- * @param {string} [options.groundAmbientColor='#d6d6d8'] - 地面环境颜色
78
- */
79
- function GlobalVolumetricCloud(viewer) {
42
+ function GlobalVolumetricCloud(map) {
80
43
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
81
44
  _classCallCheck(this, GlobalVolumetricCloud);
82
- this.viewer = viewer.viewer;
83
-
84
- // 初始化体积云参数 - 确保包含所有原函数中的19个参数
85
- this.uniforms = {
86
- densityMultiplier: options.densityMultiplier || 1.5,
87
- // 密度倍增器,推荐值范围: 0.5 ~ 3.0
88
- detailStrength: options.detailStrength || 0.69,
89
- // 细节强度,推荐值范围: 0.1 ~ 2.0
90
- cloudSharpness: options.cloudSharpness || 1.032,
91
- // 云边界锐度,推荐值范围: 0.5 ~ 4.0
92
- rainClouds: options.rainClouds || 0.45,
93
- // 雨云特征,推荐值范围: 0.0 ~ 1.0
94
- currentWindVectorWC: options.currentWindVectorWC || new Cesium.Cartesian3(100, 0, 0),
95
- cloudCover: options.cloudCover || 0.039,
96
- // 云量
97
- cloudHeight: options.cloudHeight || 8000.0,
98
- // 以底部为基准
99
- cloudThickness: options.cloudThickness || 1000.0,
100
- // 云层厚度
101
- absoluteMaxDistance: options.absoluteMaxDistance || 50000000,
102
- // 最大可视距
103
- absorption: options.absorption || 0.004,
104
- // 吸收系数
105
- windSpeedRatio: options.windSpeedRatio || 0.3,
106
- //风速
107
- scatteringCoefficient: options.scatteringCoefficient || 0.01,
108
- // 散射系数
109
- illuminationCoefficient: options.illuminationCoefficient || 0.01,
110
- // 照明系数
111
- cloudSeed: options.cloudSeed || Math.random() * 100.0,
112
- // 随机种子
113
- cloudType: options.cloudType || 0,
114
- // 0=层云, 1=积云
115
- cloudTurbulence: options.cloudTurbulence || 0.5,
116
- // 湍流强度
117
- cloudClumping: options.cloudClumping || 0.75,
118
- // 团块程度
119
- cloudAnvil: options.cloudAnvil || 0,
120
- // 砧状云特征
121
- skyAmbientColor: options.skyAmbientColor || '#B4D9F3',
122
- // 原 vec3(0.705, 0.850, 0.952)
123
- groundAmbientColor: options.groundAmbientColor || '#d6d6d8' // 原 vec3(0.741, 0.898, 0.823)
124
- };
125
-
126
- // 颜色转换对象 - 保持与原函数一致的颜色处理
45
+ // 地图上下文
46
+ _defineProperty(this, "_mapContext", void 0);
47
+ // 当前生效的云参数
48
+ _defineProperty(this, "uniforms", void 0);
49
+ // 构造时的初始参数
50
+ _defineProperty(this, "originalOptions", void 0);
51
+ // 后处理阶段对象
52
+ _defineProperty(this, "postProcessStage", void 0);
53
+ // 天空环境光颜色
54
+ _defineProperty(this, "skyAmbientColor3", void 0);
55
+ // 地面环境光颜色
56
+ _defineProperty(this, "groundAmbientColor3", void 0);
57
+ this._mapContext = map._mapContext;
58
+ var viewer = this.getMap();
59
+ if (!viewer || _typeof(viewer) !== 'object') {
60
+ throw new Error('Invalid Cesium Viewer instance provided');
61
+ }
62
+ if (!viewer.scene || !viewer.scene.postProcessStages) {
63
+ throw new Error('Viewer instance must have valid scene and postProcessStages');
64
+ }
65
+ this.uniforms = this._buildUniforms(options);
66
+ this.originalOptions = this._cloneUniforms(this.uniforms);
67
+ this.postProcessStage = null;
127
68
  this.skyAmbientColor3 = {
128
- r: 0.705,
129
- g: 0.85,
130
- b: 0.952
69
+ r: 0,
70
+ g: 0,
71
+ b: 0
131
72
  };
132
73
  this.groundAmbientColor3 = {
133
- r: 0.839,
134
- g: 0.839,
135
- b: 0.847
74
+ r: 0,
75
+ g: 0,
76
+ b: 0
136
77
  };
137
-
138
- // 后处理阶段对象
139
- this.postProcessStage = null;
140
-
141
- // 保存原始选项用于重置
142
- this.originalOptions = _objectSpread({}, options);
78
+ this._syncAmbientColors();
143
79
 
144
80
  // 初始化云
145
81
  this.initialize();
146
82
  }
147
83
 
148
- /**
149
- * 初始化体积云系统
150
- *
151
- * 创建并配置体积云后处理阶段,设置所有着色器和uniforms参数。
152
- * 这是内部方法,通常由构造函数自动调用。
153
- *
154
- * @private
155
- */
84
+ // 获取地图实例
156
85
  _createClass(GlobalVolumetricCloud, [{
86
+ key: "getMap",
87
+ value: function getMap() {
88
+ return this._mapContext && this._mapContext.getMap();
89
+ }
90
+
91
+ // 克隆云参数,避免引用共享导致外部状态污染
92
+ }, {
93
+ key: "_cloneUniforms",
94
+ value: function _cloneUniforms(params) {
95
+ return _objectSpread(_objectSpread({}, params), {}, {
96
+ currentWindVectorWC: Cesium.Cartesian3.clone(params.currentWindVectorWC)
97
+ });
98
+ }
99
+
100
+ // 统一构建参数,支持保留0值并维持随机种子稳定
101
+ }, {
102
+ key: "_buildUniforms",
103
+ value: function _buildUniforms() {
104
+ var _options$densityMulti, _options$detailStreng, _options$cloudSharpne, _options$rainClouds, _options$cloudCover, _options$cloudHeight, _options$cloudThickne, _options$absoluteMaxD, _options$absorption, _options$windSpeedRat, _options$scatteringCo, _options$illumination, _options$cloudSeed, _options$cloudType, _options$cloudTurbule, _options$cloudClumpin, _options$cloudAnvil, _options$skyAmbientCo, _options$groundAmbien, _options$maxVisibleHe;
105
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
106
+ var baseParams = arguments.length > 1 ? arguments[1] : undefined;
107
+ var fallbackParams = baseParams ? this._cloneUniforms(baseParams) : createDefaultCloudParams();
108
+ var params = {
109
+ densityMultiplier: (_options$densityMulti = options.densityMultiplier) !== null && _options$densityMulti !== void 0 ? _options$densityMulti : fallbackParams.densityMultiplier,
110
+ detailStrength: (_options$detailStreng = options.detailStrength) !== null && _options$detailStreng !== void 0 ? _options$detailStreng : fallbackParams.detailStrength,
111
+ cloudSharpness: (_options$cloudSharpne = options.cloudSharpness) !== null && _options$cloudSharpne !== void 0 ? _options$cloudSharpne : fallbackParams.cloudSharpness,
112
+ rainClouds: (_options$rainClouds = options.rainClouds) !== null && _options$rainClouds !== void 0 ? _options$rainClouds : fallbackParams.rainClouds,
113
+ currentWindVectorWC: options.currentWindVectorWC ? Cesium.Cartesian3.clone(options.currentWindVectorWC) : Cesium.Cartesian3.clone(fallbackParams.currentWindVectorWC),
114
+ cloudCover: (_options$cloudCover = options.cloudCover) !== null && _options$cloudCover !== void 0 ? _options$cloudCover : fallbackParams.cloudCover,
115
+ cloudHeight: (_options$cloudHeight = options.cloudHeight) !== null && _options$cloudHeight !== void 0 ? _options$cloudHeight : fallbackParams.cloudHeight,
116
+ cloudThickness: (_options$cloudThickne = options.cloudThickness) !== null && _options$cloudThickne !== void 0 ? _options$cloudThickne : fallbackParams.cloudThickness,
117
+ absoluteMaxDistance: (_options$absoluteMaxD = options.absoluteMaxDistance) !== null && _options$absoluteMaxD !== void 0 ? _options$absoluteMaxD : fallbackParams.absoluteMaxDistance,
118
+ absorption: (_options$absorption = options.absorption) !== null && _options$absorption !== void 0 ? _options$absorption : fallbackParams.absorption,
119
+ windSpeedRatio: (_options$windSpeedRat = options.windSpeedRatio) !== null && _options$windSpeedRat !== void 0 ? _options$windSpeedRat : fallbackParams.windSpeedRatio,
120
+ scatteringCoefficient: (_options$scatteringCo = options.scatteringCoefficient) !== null && _options$scatteringCo !== void 0 ? _options$scatteringCo : fallbackParams.scatteringCoefficient,
121
+ illuminationCoefficient: (_options$illumination = options.illuminationCoefficient) !== null && _options$illumination !== void 0 ? _options$illumination : fallbackParams.illuminationCoefficient,
122
+ cloudSeed: (_options$cloudSeed = options.cloudSeed) !== null && _options$cloudSeed !== void 0 ? _options$cloudSeed : fallbackParams.cloudSeed,
123
+ cloudType: (_options$cloudType = options.cloudType) !== null && _options$cloudType !== void 0 ? _options$cloudType : fallbackParams.cloudType,
124
+ cloudTurbulence: (_options$cloudTurbule = options.cloudTurbulence) !== null && _options$cloudTurbule !== void 0 ? _options$cloudTurbule : fallbackParams.cloudTurbulence,
125
+ cloudClumping: (_options$cloudClumpin = options.cloudClumping) !== null && _options$cloudClumpin !== void 0 ? _options$cloudClumpin : fallbackParams.cloudClumping,
126
+ cloudAnvil: (_options$cloudAnvil = options.cloudAnvil) !== null && _options$cloudAnvil !== void 0 ? _options$cloudAnvil : fallbackParams.cloudAnvil,
127
+ skyAmbientColor: (_options$skyAmbientCo = options.skyAmbientColor) !== null && _options$skyAmbientCo !== void 0 ? _options$skyAmbientCo : fallbackParams.skyAmbientColor,
128
+ groundAmbientColor: (_options$groundAmbien = options.groundAmbientColor) !== null && _options$groundAmbien !== void 0 ? _options$groundAmbien : fallbackParams.groundAmbientColor,
129
+ maxVisibleHeight: (_options$maxVisibleHe = options.maxVisibleHeight) !== null && _options$maxVisibleHe !== void 0 ? _options$maxVisibleHe : fallbackParams.maxVisibleHeight
130
+ };
131
+
132
+ // 确保 maxVisibleHeight 大于 cloudHeight
133
+ return params.maxVisibleHeight > params.cloudHeight ? params : _objectSpread(_objectSpread({}, params), {}, {
134
+ maxVisibleHeight: params.cloudHeight + 10000
135
+ });
136
+ }
137
+
138
+ // 同步环境光颜色缓存,供shader uniforms实时读取
139
+ }, {
140
+ key: "_syncAmbientColors",
141
+ value: function _syncAmbientColors() {
142
+ this.skyAmbientColor3 = this._hexToRgb(this.uniforms.skyAmbientColor, DEFAULT_SKY_AMBIENT_COLOR);
143
+ this.groundAmbientColor3 = this._hexToRgb(this.uniforms.groundAmbientColor, DEFAULT_GROUND_AMBIENT_COLOR);
144
+ }
145
+
146
+ /**
147
+ * 初始化体积云系统
148
+ *
149
+ * 创建并配置体积云后处理阶段,设置所有着色器和uniforms参数。
150
+ * 这是内部方法,通常由构造函数自动调用。
151
+ *
152
+ * @private
153
+ */
154
+ }, {
157
155
  key: "initialize",
158
156
  value: function initialize() {
159
157
  var _this = this;
158
+ var map = this.getMap();
159
+ if (!map) return;
160
160
  var shader = this._createShader();
161
161
  this.postProcessStage = new Cesium.PostProcessStage({
162
162
  uniforms: {
163
163
  realPlanetRadius: function realPlanetRadius() {
164
164
  return _this._getRealPlanetRadius();
165
165
  },
166
- windVector: this.uniforms.currentWindVectorWC,
167
- cloudCover: this.uniforms.cloudCover,
168
- cloudHeight: this.uniforms.cloudHeight,
169
- cloudThickness: this.uniforms.cloudThickness,
170
- absoluteMaxDistance: this.uniforms.absoluteMaxDistance,
171
- absorption: this.uniforms.absorption,
172
- windSpeedRatio: this.uniforms.windSpeedRatio,
173
- scatteringCoefficient: this.uniforms.scatteringCoefficient,
174
- illuminationCoefficient: this.uniforms.illuminationCoefficient,
175
- cloudSeed: this.uniforms.cloudSeed,
176
- cloudType: this.uniforms.cloudType,
177
- cloudTurbulence: this.uniforms.cloudTurbulence,
178
- cloudClumping: this.uniforms.cloudClumping,
179
- cloudAnvil: this.uniforms.cloudAnvil,
180
- densityMultiplier: this.uniforms.densityMultiplier,
181
- detailStrength: this.uniforms.detailStrength,
182
- cloudSharpness: this.uniforms.cloudSharpness,
183
- rainClouds: this.uniforms.rainClouds,
166
+ windVector: function windVector() {
167
+ return _this.uniforms.currentWindVectorWC;
168
+ },
169
+ cloudCover: function cloudCover() {
170
+ return _this.uniforms.cloudCover;
171
+ },
172
+ cloudHeight: function cloudHeight() {
173
+ return _this.uniforms.cloudHeight;
174
+ },
175
+ cloudThickness: function cloudThickness() {
176
+ return _this.uniforms.cloudThickness;
177
+ },
178
+ absoluteMaxDistance: function absoluteMaxDistance() {
179
+ return _this.uniforms.absoluteMaxDistance;
180
+ },
181
+ absorption: function absorption() {
182
+ return _this.uniforms.absorption;
183
+ },
184
+ windSpeedRatio: function windSpeedRatio() {
185
+ return _this.uniforms.windSpeedRatio;
186
+ },
187
+ scatteringCoefficient: function scatteringCoefficient() {
188
+ return _this.uniforms.scatteringCoefficient;
189
+ },
190
+ illuminationCoefficient: function illuminationCoefficient() {
191
+ return _this.uniforms.illuminationCoefficient;
192
+ },
193
+ cloudSeed: function cloudSeed() {
194
+ return _this.uniforms.cloudSeed;
195
+ },
196
+ cloudType: function cloudType() {
197
+ return _this.uniforms.cloudType;
198
+ },
199
+ cloudTurbulence: function cloudTurbulence() {
200
+ return _this.uniforms.cloudTurbulence;
201
+ },
202
+ cloudClumping: function cloudClumping() {
203
+ return _this.uniforms.cloudClumping;
204
+ },
205
+ cloudAnvil: function cloudAnvil() {
206
+ return _this.uniforms.cloudAnvil;
207
+ },
208
+ maxVisibleHeight: function maxVisibleHeight() {
209
+ return _this.uniforms.maxVisibleHeight;
210
+ },
211
+ densityMultiplier: function densityMultiplier() {
212
+ return _this.uniforms.densityMultiplier;
213
+ },
214
+ detailStrength: function detailStrength() {
215
+ return _this.uniforms.detailStrength;
216
+ },
217
+ cloudSharpness: function cloudSharpness() {
218
+ return _this.uniforms.cloudSharpness;
219
+ },
220
+ rainClouds: function rainClouds() {
221
+ return _this.uniforms.rainClouds;
222
+ },
184
223
  skyAmbientColor: function skyAmbientColor() {
185
224
  return new Cesium.Cartesian3(_this.skyAmbientColor3.r, _this.skyAmbientColor3.g, _this.skyAmbientColor3.b);
186
225
  },
@@ -191,7 +230,7 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
191
230
  forcePowerOfTwo: true,
192
231
  fragmentShader: shader
193
232
  });
194
- this.viewer.scene.postProcessStages.add(this.postProcessStage);
233
+ map.scene.postProcessStages.add(this.postProcessStage);
195
234
  }
196
235
 
197
236
  /**
@@ -206,7 +245,7 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
206
245
  }, {
207
246
  key: "_createShader",
208
247
  value: function _createShader() {
209
- return "\n precision highp float;\n uniform float realPlanetRadius;\n uniform vec3 windVector;\n uniform float cloudCover;\n uniform float cloudHeight;\n uniform float cloudThickness;\n uniform float absoluteMaxDistance;\n uniform float absorption;\n uniform float windSpeedRatio;\n uniform float scatteringCoefficient;\n uniform float illuminationCoefficient;\n\n const float PI = 3.14159265359;\n const float TWO_PI = 6.28318530718;\n const float FOUR_PI = 12.5663706144;\n float cloudTop;\n\n #define CLOUDS_MAX_LOD 1\n #define CLOUDS_MARCH_STEP 120.0\n #define CLOUDS_DENS_MARCH_STEP 60.0\n #define MAXIMUM_CLOUDS_STEPS 256\n\n // \u4F53\u79EF\u4ECB\u8D28\u6838\u5FC3\u53C2\u6570\n uniform float cloudSeed;\n uniform float cloudType; // 0-1: \u5C42\u4E91\u5230\u79EF\u4E91\n uniform float cloudTurbulence; // \u6E4D\u6D41\u5F3A\u5EA6\n uniform float cloudClumping; // \u56E2\u5757\u7A0B\u5EA6\n uniform float cloudAnvil; // \u7827\u72B6\u4E91\u7279\u5F81\n uniform vec3 skyAmbientColor;\n uniform vec3 groundAmbientColor;\n\n // ===== \u65B0\u589E\u7684\u4F53\u79EF\u4ECB\u8D28\u53C2\u6570 =====\n uniform float densityMultiplier; // \u5BC6\u5EA6\u500D\u589E\u5668\n uniform float detailStrength; // \u7EC6\u8282\u5F3A\u5EA6\n uniform float cloudSharpness; // \u4E91\u8FB9\u754C\u9510\u5EA6\n uniform float rainClouds; // \u96E8\u4E91\u7279\u5F81\n\n // \u5C04\u7EBF\u4E0E\u7403\u4F53\u76F8\u4EA4\n vec2 raySphereIntersect(vec3 r0, vec3 rd, float sr) {\n float a = dot(rd, rd);\n float b = 2.0 * dot(rd, r0);\n float c = dot(r0, r0) - (sr * sr);\n float d = (b * b) - 4.0 * a * c;\n\n if (d < 0.0) return vec2(-1.0, -1.0);\n float squaredD = sqrt(d);\n\n return vec2((-b - squaredD) / (2.0 * a), (-b + squaredD) / (2.0 * a));\n }\n\n float hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * .1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n }\n\n float saturate(float value) {\n return clamp(value, 0.0, 1.0);\n }\n\n float isotropic() {\n return 0.07957747154594767;\n }\n\n // HG\u76F8\u4F4D\u51FD\u6570\n float HenyeyGreenstein(float cosTheta, float g) {\n float g2 = g * g;\n float denominator = 4.0 * PI * pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5);\n return (1.0 - g2) / max(denominator, 0.0001);\n }\n\n // \u6539\u8FDB\u7684\u76F8\u4F4D\u51FD\u6570 - \u66F4\u597D\u7684\u80CC\u5149\u6563\u5C04\n float improvedPhase(float cosTheta) {\n // \u4E3B\u524D\u5411\u6563\u5C04\u74E3 - \u9002\u5EA6\u6291\u5236\n float forwardLobe = HenyeyGreenstein(cosTheta, 0.4) * 0.4;\n\n // \u589E\u5F3A\u7684\u80CC\u5149\u6563\u5C04\u74E3 - \u63D0\u5347\u80CC\u5149\u4EAE\u5EA6\n float backwardLobe = HenyeyGreenstein(cosTheta, -0.3) * 0.4;\n\n // \u5404\u5411\u540C\u6027\u57FA\u7840\u6563\u5C04\n float isotropicPart = isotropic() * 0.2;\n\n return forwardLobe + backwardLobe + isotropicPart;\n }\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u4ECB\u8D28\u5BC6\u5EA6\u51FD\u6570 =====\n // \u67CF\u6797\u566A\u58F0\u51FD\u6570\n vec4 permute(vec4 x) { return mod(((x*34.0)+1.0)*x, 289.0); }\n vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\n float perlinNoise(vec3 P) {\n vec3 i0 = floor(P);\n vec3 f0 = fract(P);\n vec3 f = f0 * f0 * (3.0 - 2.0 * f0);\n vec4 ix = vec4(i0.x, i0.x + 1.0, i0.x, i0.x + 1.0);\n vec4 iy = vec4(i0.y, i0.y, i0.y + 1.0, i0.y + 1.0);\n vec4 iz0 = vec4(i0.z);\n vec4 iz1 = iz0 + 1.0;\n\n vec4 ixy = permute(permute(ix) + iy);\n vec4 ixy0 = permute(ixy + iz0);\n vec4 ixy1 = permute(ixy + iz1);\n\n vec4 gx0 = ixy0 / 7.0;\n vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;\n gx0 = fract(gx0) - 0.5;\n vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);\n vec4 sz0 = step(gz0, vec4(0.0));\n gx0 -= sz0 * (step(0.0, gx0) - 0.5);\n gy0 -= sz0 * (step(0.0, gy0) - 0.5);\n\n vec4 gx1 = ixy1 / 7.0;\n vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;\n gx1 = fract(gx1) - 0.5;\n vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);\n vec4 sz1 = step(gz1, vec4(0.0));\n gx1 -= sz1 * (step(0.0, gx1) - 0.5);\n gy1 -= sz1 * (step(0.0, gy1) - 0.5);\n\n vec3 g000 = vec3(gx0.x, gy0.x, gz0.x);\n vec3 g100 = vec3(gx0.y, gy0.y, gz0.y);\n vec3 g010 = vec3(gx0.z, gy0.z, gz0.z);\n vec3 g110 = vec3(gx0.w, gy0.w, gz0.w);\n vec3 g001 = vec3(gx1.x, gy1.x, gz1.x);\n vec3 g101 = vec3(gx1.y, gy1.y, gz1.y);\n vec3 g011 = vec3(gx1.z, gy1.z, gz1.z);\n vec3 g111 = vec3(gx1.w, gy1.w, gz1.w);\n\n vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));\n g000 *= norm0.x; g010 *= norm0.y;\n g100 *= norm0.z; g110 *= norm0.w;\n vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));\n g001 *= norm1.x; g011 *= norm1.y;\n g101 *= norm1.z; g111 *= norm1.w;\n\n float n000 = dot(g000, f0);\n float n100 = dot(g100, f0 - vec3(1.0, 0.0, 0.0));\n float n010 = dot(g010, f0 - vec3(0.0, 1.0, 0.0));\n float n110 = dot(g110, f0 - vec3(1.0, 1.0, 0.0));\n float n001 = dot(g001, f0 - vec3(0.0, 0.0, 1.0));\n float n101 = dot(g101, f0 - vec3(1.0, 0.0, 1.0));\n float n011 = dot(g011, f0 - vec3(0.0, 1.0, 1.0));\n float n111 = dot(g111, f0 - vec3(1.0, 1.0, 1.0));\n\n vec4 n_z0 = mix(vec4(n000, n100, n010, n110),\n vec4(n001, n101, n011, n111), f.z);\n vec2 n_z1 = mix(n_z0.xy, n_z0.zw, f.y);\n float n = mix(n_z1.x, n_z1.y, f.x);\n\n return 2.2 * n;\n }\n // FBM\u51FD\u6570\n float fBm(vec3 p, int octaves, float persistence, float lacunarity) {\n float value = 0.0;\n float amplitude = 1.0;\n float frequency = 1.0;\n float maxValue = 0.0;\n\n for (int i = 0; i < octaves; i++) {\n value += amplitude * perlinNoise(p * frequency);\n maxValue += amplitude;\n amplitude *= persistence;\n frequency *= lacunarity;\n }\n\n return value / maxValue;\n }\n // \u57DF\u626D\u66F2\u566A\u58F0\n float domainWarpedNoise(vec3 p, float intensity) {\n vec3 q = vec3(\n perlinNoise(p),\n perlinNoise(p + vec3(123.4, 234.5, 345.6)),\n perlinNoise(p + vec3(234.5, 345.6, 456.7))\n );\n vec3 r = vec3(\n perlinNoise(p + 1.0 * q + vec3(123.4, 234.5, 345.6)),\n perlinNoise(p + 1.0 * q + vec3(234.5, 345.6, 456.7)),\n perlinNoise(p + 1.0 * q + vec3(345.6, 456.7, 567.8))\n );\n return perlinNoise(p + intensity * r);\n }\n\n // Worley\u566A\u58F0\n float worleyNoise(vec3 p, float scale) {\n vec3 i = floor(p * scale);\n vec3 f = fract(p * scale);\n\n float minDist1 = 1.0;\n float minDist2 = 1.0;\n\n for (int x = -1; x <= 1; x++) {\n for (int y = -1; y <= 1; y++) {\n for (int z = -1; z <= 1; z++) {\n vec3 neighbor = vec3(float(x), float(y), float(z));\n vec3 random = fract(sin(dot(i + neighbor, vec3(127.1, 311.7, 74.7))) *\n vec3(43758.5453, 22578.1459, 19632.7411));\n vec3 point = neighbor + random - f;\n float dist = length(point);\n\n if (dist < minDist1) {\n minDist2 = minDist1;\n minDist1 = dist;\n } else if (dist < minDist2) {\n minDist2 = dist;\n }\n }\n }\n }\n\n return minDist2 - minDist1;\n }\n // \u4E91\u5C42\u9AD8\u5EA6\u5206\u5E03\u51FD\u6570\n float cloudHeightProfile(float heightRatio, float cloudType) {\n // \u5C42\u4E91 - \u5747\u5300\u5206\u5E03\n if (cloudType < 0.3) {\n return 1.0;\n }\n // \u79EF\u4E91 - \u4E2D\u95F4\u539A\uFF0C\u4E0A\u4E0B\u8584\n else if (cloudType < 0.7) {\n float profile = 1.0 - 4.0 * pow(heightRatio - 0.5, 2.0);\n return max(profile, 0.1);\n }\n // \u7827\u72B6\u4E91 - \u4E0A\u90E8\u6269\u5C55\n else {\n float anvilProfile = 1.0 - pow(heightRatio, 2.0);\n return max(anvilProfile, 0.2);\n }\n }\n\n // \u96E8\u4E91\u5BC6\u5EA6\u7279\u5F81\n float rainCloudDensity(float baseDensity, float heightRatio, float rainFactor) {\n if (rainFactor < 0.1) return baseDensity;\n\n // \u96E8\u4E91\u5E95\u90E8\u66F4\u5BC6\u96C6\n float rainProfile = 1.0 + rainFactor * (1.0 - heightRatio) * 2.0;\n return baseDensity * rainProfile;\n }\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u4ECB\u8D28\u5149\u7167\u6A21\u578B =====\n\n const float preBaseScale = 0.0003;\n const float preFineScale = 0.0003 * 16.0;\n float baseScale = 0.0003;\n // ===== \u8865\u5168\u7684\u4E91\u6735\u5BC6\u5EA6\u51FD\u6570 =====\n float cloudDensity(vec3 p, vec3 windVector, inout float heightRatio) {\n float finalCoverage = cloudCover;\n if (finalCoverage <= 0.001) {\n return 0.0;\n }\n\n float height = length(p) - realPlanetRadius;\n heightRatio = clamp((height - cloudHeight) / cloudThickness, 0.0, 1.0);\n\n // \u57FA\u7840\u9AD8\u5EA6\u56E0\u5B50\n float hLower = cloudHeight;\n float hUpper = cloudHeight + cloudThickness;\n float heightFactor = smoothstep(hLower, hLower + 0.2 * cloudThickness, height) *\n (1.0 - smoothstep(hUpper - 0.2 * cloudThickness, hUpper, height));\n\n vec3 seedOffset = vec3(cloudSeed * 100.0, 0.0, cloudSeed * 50.0);\n vec3 animatedPos = p + windVector * windSpeedRatio + seedOffset;\n\n // \u57FA\u7840\u5F62\u72B6\u566A\u58F0\n float baseShape = fBm(animatedPos * preBaseScale, 4, 0.5, 2.0);\n\n // \u57DF\u626D\u66F2\u589E\u52A0\u7EC6\u8282\n float warpIntensity = mix(0.1, 0.8, cloudTurbulence);\n float baseShape0 = fBm(animatedPos * preBaseScale, 3, 0.5, 2.0);\n float warped = domainWarpedNoise(animatedPos * (preBaseScale * 0.5), warpIntensity * 0.7);\n baseShape = mix(baseShape0, warped, 0.25);\n\n // Worley\u566A\u58F0\u521B\u5EFA\u56E2\u5757\u7ED3\u6784\n float worleyScale = mix(0.0002, 0.0008, cloudClumping);\n float worleyPattern = worleyNoise(animatedPos, worleyScale);\n worleyPattern = saturate(worleyPattern * 1.2 + 0.7);\n\n // \u6839\u636E\u4E91\u7C7B\u578B\u6DF7\u5408\n float cumulusFactor = cloudType;\n float stratusFactor = 1.0 - cloudType;\n\n float cumulusShape = baseShape * worleyPattern;\n cumulusShape = mix(cumulusShape, baseShape, 0.3);\n\n float stratusShape = baseShape * 0.8;\n\n float cloudPattern = mix(stratusShape, cumulusShape, cumulusFactor);\n\n // \u7827\u72B6\u4E91\u7279\u5F81\n float anvilFactor = cloudAnvil * pow(heightRatio, 2.0);\n if (anvilFactor > 0.01) {\n float anvilNoise = fBm(animatedPos * baseScale * 0.3, 3, 0.6, 2.0);\n cloudPattern = mix(cloudPattern, anvilNoise, anvilFactor * 0.5);\n }\n\n // \u7EC6\u8282\u4FB5\u8680\n float fineScale = baseScale * 16.0;\n float fineDetail = fBm(animatedPos * fineScale, 2, 0.7, 2.5);\n float erosionIntensity = mix(0.1, 0.4, cumulusFactor) * detailStrength;\n float erosion = fineDetail * erosionIntensity;\n\n // \u57FA\u7840\u5BC6\u5EA6\u8BA1\u7B97\n float baseDensity = cloudPattern - erosion;\n float coverageThreshold = mix(0.1, -0.3, cloudCover * (0.5 + cumulusFactor * 0.5));\n float dens = saturate(baseDensity - coverageThreshold);\n\n // \u9510\u5316\u8FB9\u754C\n float sharpness = mix(1.2, 2.0, cumulusFactor) * cloudSharpness;\n dens = pow(dens, sharpness);\n\n // \u5E94\u7528\u9AD8\u5EA6\u5206\u5E03\n float verticalProfile = cloudHeightProfile(heightRatio, cloudType);\n dens *= heightFactor * cloudCover * verticalProfile;\n\n // \u5E94\u7528\u96E8\u4E91\u7279\u5F81\n dens = rainCloudDensity(dens, heightRatio, rainClouds);\n\n // \u6700\u7EC8\u5BC6\u5EA6\u8C03\u6574\n dens *= densityMultiplier;\n dens = max(dens, 0.0);\n\n return dens;\n }\n float cloudDensityFast(vec3 p)\n {\n float h = length(p) - realPlanetRadius;\n float heightRatio = clamp((h - cloudHeight) / cloudThickness, 0.0, 1.0);\n\n // \u53EA\u505A\u6700\u57FA\u7840\u7684 shape\uFF0C\u4E0D\u505A Worley\u3001\u4E0D\u505A domain warp\uFF0C\u4E0D\u505A erosion\n float n = perlinNoise(p * 0.00035);\n n = n * n * 1.2; // \u7B80\u5355\u5F3A\u5316\n\n // \u9AD8\u5EA6\u5206\u5E03\n float profile = cloudHeightProfile(heightRatio, cloudType);\n\n return saturate(n * profile * cloudCover * densityMultiplier * 0.8);\n }\n // \u4F53\u79EF\u9634\u5F71\u51FD\u6570 - \u6A21\u62DF\u5149\u7EBF\u5728\u4E91\u5185\u7684\u8870\u51CF\n float volumetricShadow(vec3 p, vec3 lightDir, float stepSize, int steps) {\n float shadow = 1.0;\n vec3 currentPos = p;\n\n for (int i = 0; i < steps; i++) {\n currentPos += lightDir * stepSize;\n float heightRatioDummy;\n float shadowDensity = cloudDensityFast(currentPos);\n\n // \u6307\u6570\u8870\u51CF\u6A21\u62DF\u5149\u7EBF\u5728\u4E91\u5185\u7684\u5438\u6536\n shadow *= exp(-shadowDensity * stepSize * absorption * 2.0);\n\n if (shadow < 0.01) break;\n }\n\n return shadow;\n }\n\n // \u6539\u8FDB\u7684\u73AF\u5883\u5149\u7167\u51FD\u6570\n vec3 calculateAmbientLight(float heightRatio, float dens, float dotLightRay) {\n // \u57FA\u7840\u73AF\u5883\u5149 - \u6839\u636E\u9AD8\u5EA6\u6DF7\u5408\u5730\u9762\u548C\u5929\u7A7A\u989C\u8272\n vec3 baseAmbient = mix(groundAmbientColor, skyAmbientColor, heightRatio);\n\n // \u5BC6\u5EA6\u76F8\u5173\u73AF\u5883\u5149 - \u8584\u4E91\u533A\u57DF\u66F4\u4EAE\n float densityFactor = 1.0 - exp(-dens * 2.0);\n baseAmbient *= (1.0 + densityFactor * 0.5);\n\n // \u80CC\u5149\u589E\u5F3A - \u5F53\u89C6\u7EBF\u4E0E\u5149\u6E90\u65B9\u5411\u63A5\u8FD1\u53CD\u5411\u65F6\n float backLightFactor = smoothstep(-0.8, -0.2, dotLightRay);\n vec3 backLightBoost = skyAmbientColor * backLightFactor * 0.8;\n\n return baseAmbient + backLightBoost;\n }\n\n // \u6539\u8FDB\u7684\u591A\u6563\u5C04\u6A21\u62DF\n float calculateMultiScatter(float dens, float heightRatio, float dotLightRay) {\n // \u57FA\u7840\u591A\u6563\u5C04\n float baseMultiScatter = pow(1.0 - exp(-dens * 1.5), 1.5) * 0.4;\n\n // \u80CC\u5149\u533A\u57DF\u989D\u5916\u591A\u6563\u5C04\n float backScatterBoost = smoothstep(-0.6, 0.0, dotLightRay) * 0.3;\n\n // \u9AD8\u7A7A\u533A\u57DF\u6563\u5C04\u589E\u5F3A\n float heightScatter = heightRatio * 0.2;\n\n return baseMultiScatter + backScatterBoost + heightScatter;\n }\n\n float distanceQualityR = 0.00005;\n float minDistance = 10.0;\n\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u6E32\u67D3\u6838\u5FC3\u51FD\u6570 =====\n vec4 calculate_clouds(vec3 start, vec3 dir, float maxDistance, vec3 light_dir, vec3 wind) {\n vec4 cloud = vec4(0.0, 0.0, 0.0, 1.0);\n float cloudTopRadius = realPlanetRadius + cloudHeight + cloudThickness;\n vec2 toTop = raySphereIntersect(start, dir, cloudTopRadius);\n float cloudBaseRadius = realPlanetRadius + cloudHeight;\n vec2 toCloudBase = raySphereIntersect(start, dir, cloudBaseRadius);\n float startHeight = length(start) - realPlanetRadius;\n\n float tmin = 0.0;\n float tmax = maxDistance;\n cloudTop = cloudHeight + cloudThickness;\n\n // \u8BA1\u7B97\u5C04\u7EBF\u4E0E\u4E91\u5C42\u7684\u4EA4\u70B9\n if (startHeight > cloudTop) {\n if (toTop.x < 0.0) return vec4(0.0);\n tmin = toTop.x;\n if (toCloudBase.x > 0.0) {\n tmax = min(toCloudBase.x, maxDistance);\n } else {\n tmax = min(toTop.y, maxDistance);\n }\n } else if (startHeight < cloudHeight) {\n tmin = toCloudBase.y;\n tmax = min(toTop.y, maxDistance);\n } else {\n if (toCloudBase.x > 0.0) {\n tmax = min(toCloudBase.x, maxDistance);\n } else {\n tmax = min(toTop.y, maxDistance);\n }\n }\n\n tmin = max(tmin, minDistance);\n tmax = min(tmax, absoluteMaxDistance);\n\n if (tmax < tmin) return vec4(0.0);\n\n float rayLength = tmax - tmin;\n float thicknessFactor = cloudThickness / 500.0;\n float baseStepSize = mix(CLOUDS_MARCH_STEP, CLOUDS_MARCH_STEP * 1.5, saturate(thicknessFactor - 1.0));\n\n float maxEffectiveSteps = min(float(MAXIMUM_CLOUDS_STEPS), 200.0 + cloudThickness * 0.2);\n float adaptiveSteps = min(maxEffectiveSteps, rayLength / baseStepSize);\n\n float longMarchStep = rayLength / adaptiveSteps;\n longMarchStep = max(longMarchStep, baseStepSize);\n\n float shortMarchStep = CLOUDS_DENS_MARCH_STEP;\n float numberApproachSteps = (longMarchStep / shortMarchStep) * 1.5;\n\n float distance = tmin;\n\n float jitter = hash12(gl_FragCoord.xy) * 1.2;\n distance += jitter * longMarchStep;\n\n bool inCloud = false;\n float stepsBeforeExitingCloud = 0.0;\n int actualSteps = 0;\n\n // \u9884\u8BA1\u7B97\u5149\u7167\u53C2\u6570\n vec3 sunColor = normalize(czm_lightColor);\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u4ECB\u8D28\u5149\u7167\u8BA1\u7B97 =====\n float dotLightRay = dot(dir, light_dir);\n for (int i = 0; i < MAXIMUM_CLOUDS_STEPS; i++) {\n if (distance > tmax) break;\n if (actualSteps > int(adaptiveSteps)) break;\n\n vec3 position = start + dir * distance;\n float heightRatio;\n float marchStep = inCloud ? shortMarchStep : longMarchStep;\n float dens = cloudDensity(position, wind, heightRatio);\n\n // \u7A7A\u7A7A\u95F4\u8DF3\u8FC7\u4F18\u5316\n if (dens < 0.005) {\n if (inCloud) {\n if (stepsBeforeExitingCloud > 0.0) {\n stepsBeforeExitingCloud -= 1.0;\n } else {\n inCloud = false;\n marchStep = longMarchStep * 2.0;\n }\n }\n distance += marchStep;\n actualSteps++;\n continue;\n }\n\n // \u8FDB\u5165\u4E91\u5C42\u68C0\u6D4B\n if (!inCloud) {\n inCloud = true;\n stepsBeforeExitingCloud = numberApproachSteps;\n distance = max(tmin, distance - longMarchStep);\n continue;\n }\n\n // \u4F53\u79EF\u9634\u5F71\n float shadow = volumetricShadow(position, light_dir, shortMarchStep * 2.0, 8);\n\n // \u4F7F\u7528\u6539\u8FDB\u7684\u76F8\u4F4D\u51FD\u6570\n float sunPhase = improvedPhase(dotLightRay);\n float ambientPhase = isotropic();\n\n // \u9633\u5149\u5F3A\u5EA6\n float sunIntensity = smoothstep(0.0, 0.4, 1.0 - dens) * 0.6 * shadow;\n\n // \u73AF\u5883\u5149\u7167\n vec3 ambientLight = calculateAmbientLight(heightRatio, dens, dotLightRay);\n float ambientIntensity = 2.5;\n\n // \u591A\u6563\u5C04\n float multiScatter = calculateMultiScatter(dens, heightRatio, dotLightRay);\n\n // \u76F4\u63A5\u5149\u7167\n vec3 directLight = sunPhase * sunColor * sunIntensity * 0.5;\n\n // \u73AF\u5883\u5149\u7167\u6563\u5C04\n vec3 ambientScattering = ambientPhase * ambientLight * ambientIntensity * (1.0 + multiScatter);\n\n // \u4FA7\u5149\u548C\u80CC\u5149\u589E\u5F3A\n float sideBackLight = smoothstep(-0.5, 0.3, dotLightRay) * 0.4;\n ambientScattering += ambientLight * sideBackLight * multiScatter;\n\n // \u7EC4\u5408\u5149\u7167\n vec3 stepScattering = cloud.a * scatteringCoefficient * marchStep *\n (directLight + ambientScattering);\n\n // \u80FD\u91CF\u9650\u5236\n float maxStepBrightness = 0.25;\n stepScattering = min(stepScattering, vec3(maxStepBrightness));\n\n cloud.rgb += stepScattering;\n\n // \u900F\u660E\u5EA6\u8BA1\u7B97 - \u4F53\u79EF\u4ECB\u8D28\u7684\u6D88\u5149\n float extinctionCoeff = absorption * (0.8 + 0.2 * dens) * (0.6 + dens*0.4);\n cloud.a *= exp(-extinctionCoeff * marchStep);\n\n // \u63D0\u524D\u7EC8\u6B62\n if (cloud.a < 0.01) {\n cloud.a = 0.0;\n break;\n }\n\n distance += marchStep;\n actualSteps++;\n }\n\n // \u8272\u8C03\u6620\u5C04\n cloud.rgb = cloud.rgb / (cloud.rgb + vec3(0.8));\n\n // \u4EAE\u5EA6\u9650\u5236\n float maxChannel = max(cloud.rgb.r, max(cloud.rgb.g, cloud.rgb.b));\n if (maxChannel > 0.7) {\n float compression = smoothstep(0.7, 1.0, maxChannel) * 0.3;\n cloud.rgb = mix(cloud.rgb, cloud.rgb * (1.0 - compression), compression);\n }\n\n return vec4(cloud.rgb, 1.0 - cloud.a);\n }\n\n uniform sampler2D colorTexture;\n in vec2 v_textureCoordinates;\n\n void main() {\n vec4 color = texture(colorTexture, v_textureCoordinates);\n vec4 rawDepthColor = texture(czm_globeDepthTexture, v_textureCoordinates);\n\n float depth = czm_unpackDepth(rawDepthColor);\n if (depth == 0.0) {\n depth = 1.0;\n }\n\n vec4 positionEC = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);\n vec4 worldCoordinate = czm_inverseView * positionEC;\n vec3 vWorldPosition = worldCoordinate.xyz / worldCoordinate.w;\n vec3 posToEye = vWorldPosition - czm_viewerPositionWC;\n vec3 direction = normalize(posToEye);\n vec3 lightDirection = normalize(czm_sunPositionWC);\n float distance = length(posToEye);\n\n if (depth == 1.0) {\n distance = absoluteMaxDistance;\n }\n\n vec3 wind = windVector * czm_frameNumber * windSpeedRatio;\n vec4 clouds = calculate_clouds(\n czm_viewerPositionWC,\n direction,\n distance,\n lightDirection,\n wind\n );\n\n color = mix(color, clouds, clouds.a);\n out_FragColor = color;\n }\n ";
248
+ return "\n precision highp float;\n uniform float realPlanetRadius;\n uniform vec3 windVector;\n uniform float cloudCover;\n uniform float cloudHeight;\n uniform float cloudThickness;\n uniform float absoluteMaxDistance;\n uniform float absorption;\n uniform float windSpeedRatio;\n uniform float scatteringCoefficient;\n uniform float illuminationCoefficient;\n\n const float PI = 3.14159265359;\n const float TWO_PI = 6.28318530718;\n const float FOUR_PI = 12.5663706144;\n float cloudTop;\n\n #define CLOUDS_MAX_LOD 1\n #define CLOUDS_MARCH_STEP 120.0\n #define CLOUDS_DENS_MARCH_STEP 60.0\n #define MAXIMUM_CLOUDS_STEPS 256\n\n // \u4F53\u79EF\u4ECB\u8D28\u6838\u5FC3\u53C2\u6570\n uniform float cloudSeed;\n uniform float cloudType; // 0-1: \u5C42\u4E91\u5230\u79EF\u4E91\n uniform float cloudTurbulence; // \u6E4D\u6D41\u5F3A\u5EA6\n uniform float cloudClumping; // \u56E2\u5757\u7A0B\u5EA6\n uniform float cloudAnvil; // \u7827\u72B6\u4E91\u7279\u5F81\n uniform float maxVisibleHeight; // \u6700\u5927\u53EF\u89C6\u9AD8\u5EA6\n uniform vec3 skyAmbientColor;\n uniform vec3 groundAmbientColor;\n\n // ===== \u65B0\u589E\u7684\u4F53\u79EF\u4ECB\u8D28\u53C2\u6570 =====\n uniform float densityMultiplier; // \u5BC6\u5EA6\u500D\u589E\u5668\n uniform float detailStrength; // \u7EC6\u8282\u5F3A\u5EA6\n uniform float cloudSharpness; // \u4E91\u8FB9\u754C\u9510\u5EA6\n uniform float rainClouds; // \u96E8\u4E91\u7279\u5F81\n\n // \u5C04\u7EBF\u4E0E\u7403\u4F53\u76F8\u4EA4\n vec2 raySphereIntersect(vec3 r0, vec3 rd, float sr) {\n float a = dot(rd, rd);\n float b = 2.0 * dot(rd, r0);\n float c = dot(r0, r0) - (sr * sr);\n float d = (b * b) - 4.0 * a * c;\n\n if (d < 0.0) return vec2(-1.0, -1.0);\n float squaredD = sqrt(d);\n\n return vec2((-b - squaredD) / (2.0 * a), (-b + squaredD) / (2.0 * a));\n }\n\n float hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * .1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n }\n\n float saturate(float value) {\n return clamp(value, 0.0, 1.0);\n }\n\n float isotropic() {\n return 0.07957747154594767;\n }\n\n // HG\u76F8\u4F4D\u51FD\u6570\n float HenyeyGreenstein(float cosTheta, float g) {\n float g2 = g * g;\n float denominator = 4.0 * PI * pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5);\n return (1.0 - g2) / max(denominator, 0.0001);\n }\n\n // \u6539\u8FDB\u7684\u76F8\u4F4D\u51FD\u6570 - \u66F4\u597D\u7684\u80CC\u5149\u6563\u5C04\n float improvedPhase(float cosTheta) {\n // \u4E3B\u524D\u5411\u6563\u5C04\u74E3 - \u9002\u5EA6\u6291\u5236\n float forwardLobe = HenyeyGreenstein(cosTheta, 0.4) * 0.4;\n\n // \u589E\u5F3A\u7684\u80CC\u5149\u6563\u5C04\u74E3 - \u63D0\u5347\u80CC\u5149\u4EAE\u5EA6\n float backwardLobe = HenyeyGreenstein(cosTheta, -0.3) * 0.4;\n\n // \u5404\u5411\u540C\u6027\u57FA\u7840\u6563\u5C04\n float isotropicPart = isotropic() * 0.2;\n\n return forwardLobe + backwardLobe + isotropicPart;\n }\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u4ECB\u8D28\u5BC6\u5EA6\u51FD\u6570 =====\n // \u67CF\u6797\u566A\u58F0\u51FD\u6570\n vec4 permute(vec4 x) { return mod(((x*34.0)+1.0)*x, 289.0); }\n vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\n float perlinNoise(vec3 P) {\n vec3 i0 = floor(P);\n vec3 f0 = fract(P);\n vec3 f = f0 * f0 * (3.0 - 2.0 * f0);\n vec4 ix = vec4(i0.x, i0.x + 1.0, i0.x, i0.x + 1.0);\n vec4 iy = vec4(i0.y, i0.y, i0.y + 1.0, i0.y + 1.0);\n vec4 iz0 = vec4(i0.z);\n vec4 iz1 = iz0 + 1.0;\n\n vec4 ixy = permute(permute(ix) + iy);\n vec4 ixy0 = permute(ixy + iz0);\n vec4 ixy1 = permute(ixy + iz1);\n\n vec4 gx0 = ixy0 / 7.0;\n vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;\n gx0 = fract(gx0) - 0.5;\n vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);\n vec4 sz0 = step(gz0, vec4(0.0));\n gx0 -= sz0 * (step(0.0, gx0) - 0.5);\n gy0 -= sz0 * (step(0.0, gy0) - 0.5);\n\n vec4 gx1 = ixy1 / 7.0;\n vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;\n gx1 = fract(gx1) - 0.5;\n vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);\n vec4 sz1 = step(gz1, vec4(0.0));\n gx1 -= sz1 * (step(0.0, gx1) - 0.5);\n gy1 -= sz1 * (step(0.0, gy1) - 0.5);\n\n vec3 g000 = vec3(gx0.x, gy0.x, gz0.x);\n vec3 g100 = vec3(gx0.y, gy0.y, gz0.y);\n vec3 g010 = vec3(gx0.z, gy0.z, gz0.z);\n vec3 g110 = vec3(gx0.w, gy0.w, gz0.w);\n vec3 g001 = vec3(gx1.x, gy1.x, gz1.x);\n vec3 g101 = vec3(gx1.y, gy1.y, gz1.y);\n vec3 g011 = vec3(gx1.z, gy1.z, gz1.z);\n vec3 g111 = vec3(gx1.w, gy1.w, gz1.w);\n\n vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));\n g000 *= norm0.x; g010 *= norm0.y;\n g100 *= norm0.z; g110 *= norm0.w;\n vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));\n g001 *= norm1.x; g011 *= norm1.y;\n g101 *= norm1.z; g111 *= norm1.w;\n\n float n000 = dot(g000, f0);\n float n100 = dot(g100, f0 - vec3(1.0, 0.0, 0.0));\n float n010 = dot(g010, f0 - vec3(0.0, 1.0, 0.0));\n float n110 = dot(g110, f0 - vec3(1.0, 1.0, 0.0));\n float n001 = dot(g001, f0 - vec3(0.0, 0.0, 1.0));\n float n101 = dot(g101, f0 - vec3(1.0, 0.0, 1.0));\n float n011 = dot(g011, f0 - vec3(0.0, 1.0, 1.0));\n float n111 = dot(g111, f0 - vec3(1.0, 1.0, 1.0));\n\n vec4 n_z0 = mix(vec4(n000, n100, n010, n110),\n vec4(n001, n101, n011, n111), f.z);\n vec2 n_z1 = mix(n_z0.xy, n_z0.zw, f.y);\n float n = mix(n_z1.x, n_z1.y, f.x);\n\n return 2.2 * n;\n }\n // FBM\u51FD\u6570\n float fBm(vec3 p, int octaves, float persistence, float lacunarity) {\n float value = 0.0;\n float amplitude = 1.0;\n float frequency = 1.0;\n float maxValue = 0.0;\n\n for (int i = 0; i < octaves; i++) {\n value += amplitude * perlinNoise(p * frequency);\n maxValue += amplitude;\n amplitude *= persistence;\n frequency *= lacunarity;\n }\n\n return value / maxValue;\n }\n // \u57DF\u626D\u66F2\u566A\u58F0\n float domainWarpedNoise(vec3 p, float intensity) {\n vec3 q = vec3(\n perlinNoise(p),\n perlinNoise(p + vec3(123.4, 234.5, 345.6)),\n perlinNoise(p + vec3(234.5, 345.6, 456.7))\n );\n vec3 r = vec3(\n perlinNoise(p + 1.0 * q + vec3(123.4, 234.5, 345.6)),\n perlinNoise(p + 1.0 * q + vec3(234.5, 345.6, 456.7)),\n perlinNoise(p + 1.0 * q + vec3(345.6, 456.7, 567.8))\n );\n return perlinNoise(p + intensity * r);\n }\n\n // Worley\u566A\u58F0\n float worleyNoise(vec3 p, float scale) {\n vec3 i = floor(p * scale);\n vec3 f = fract(p * scale);\n\n float minDist1 = 1.0;\n float minDist2 = 1.0;\n\n for (int x = -1; x <= 1; x++) {\n for (int y = -1; y <= 1; y++) {\n for (int z = -1; z <= 1; z++) {\n vec3 neighbor = vec3(float(x), float(y), float(z));\n vec3 random = fract(sin(dot(i + neighbor, vec3(127.1, 311.7, 74.7))) *\n vec3(43758.5453, 22578.1459, 19632.7411));\n vec3 point = neighbor + random - f;\n float dist = length(point);\n\n if (dist < minDist1) {\n minDist2 = minDist1;\n minDist1 = dist;\n } else if (dist < minDist2) {\n minDist2 = dist;\n }\n }\n }\n }\n\n return minDist2 - minDist1;\n }\n // \u4E91\u5C42\u9AD8\u5EA6\u5206\u5E03\u51FD\u6570\n float cloudHeightProfile(float heightRatio, float cloudType) {\n // \u5C42\u4E91 - \u5747\u5300\u5206\u5E03\n if (cloudType < 0.3) {\n return 1.0;\n }\n // \u79EF\u4E91 - \u4E2D\u95F4\u539A\uFF0C\u4E0A\u4E0B\u8584\n else if (cloudType < 0.7) {\n float profile = 1.0 - 4.0 * pow(heightRatio - 0.5, 2.0);\n return max(profile, 0.1);\n }\n // \u7827\u72B6\u4E91 - \u4E0A\u90E8\u6269\u5C55\n else {\n float anvilProfile = 1.0 - pow(heightRatio, 2.0);\n return max(anvilProfile, 0.2);\n }\n }\n\n // \u96E8\u4E91\u5BC6\u5EA6\u7279\u5F81\n float rainCloudDensity(float baseDensity, float heightRatio, float rainFactor) {\n if (rainFactor < 0.1) return baseDensity;\n\n // \u96E8\u4E91\u5E95\u90E8\u66F4\u5BC6\u96C6\n float rainProfile = 1.0 + rainFactor * (1.0 - heightRatio) * 2.0;\n return baseDensity * rainProfile;\n }\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u4ECB\u8D28\u5149\u7167\u6A21\u578B =====\n\n const float preBaseScale = 0.0003;\n const float preFineScale = 0.0003 * 16.0;\n float baseScale = 0.0003;\n // ===== \u8865\u5168\u7684\u4E91\u6735\u5BC6\u5EA6\u51FD\u6570 =====\n float cloudDensity(vec3 p, vec3 windVector, inout float heightRatio) {\n float finalCoverage = cloudCover;\n if (finalCoverage <= 0.001) {\n return 0.0;\n }\n\n float height = length(p) - realPlanetRadius;\n heightRatio = clamp((height - cloudHeight) / cloudThickness, 0.0, 1.0);\n\n // \u57FA\u7840\u9AD8\u5EA6\u56E0\u5B50\n float hLower = cloudHeight;\n float hUpper = cloudHeight + cloudThickness;\n float heightFactor = smoothstep(hLower, hLower + 0.2 * cloudThickness, height) *\n (1.0 - smoothstep(hUpper - 0.2 * cloudThickness, hUpper, height));\n\n vec3 seedOffset = vec3(cloudSeed * 100.0, 0.0, cloudSeed * 50.0);\n vec3 animatedPos = p + windVector * windSpeedRatio + seedOffset;\n\n // \u57FA\u7840\u5F62\u72B6\u566A\u58F0\n float baseShape = fBm(animatedPos * preBaseScale, 4, 0.5, 2.0);\n\n // \u57DF\u626D\u66F2\u589E\u52A0\u7EC6\u8282\n float warpIntensity = mix(0.1, 0.8, cloudTurbulence);\n float baseShape0 = fBm(animatedPos * preBaseScale, 3, 0.5, 2.0);\n float warped = domainWarpedNoise(animatedPos * (preBaseScale * 0.5), warpIntensity * 0.7);\n baseShape = mix(baseShape0, warped, 0.25);\n\n // Worley\u566A\u58F0\u521B\u5EFA\u56E2\u5757\u7ED3\u6784\n float worleyScale = mix(0.0002, 0.0008, cloudClumping);\n float worleyPattern = worleyNoise(animatedPos, worleyScale);\n worleyPattern = saturate(worleyPattern * 1.2 + 0.7);\n\n // \u6839\u636E\u4E91\u7C7B\u578B\u6DF7\u5408\n float cumulusFactor = cloudType;\n float stratusFactor = 1.0 - cloudType;\n\n float cumulusShape = baseShape * worleyPattern;\n cumulusShape = mix(cumulusShape, baseShape, 0.3);\n\n float stratusShape = baseShape * 0.8;\n\n float cloudPattern = mix(stratusShape, cumulusShape, cumulusFactor);\n\n // \u7827\u72B6\u4E91\u7279\u5F81\n float anvilFactor = cloudAnvil * pow(heightRatio, 2.0);\n if (anvilFactor > 0.01) {\n float anvilNoise = fBm(animatedPos * baseScale * 0.3, 3, 0.6, 2.0);\n cloudPattern = mix(cloudPattern, anvilNoise, anvilFactor * 0.5);\n }\n\n // \u7EC6\u8282\u4FB5\u8680\n float fineScale = baseScale * 16.0;\n float fineDetail = fBm(animatedPos * fineScale, 2, 0.7, 2.5);\n float erosionIntensity = mix(0.1, 0.4, cumulusFactor) * detailStrength;\n float erosion = fineDetail * erosionIntensity;\n\n // \u57FA\u7840\u5BC6\u5EA6\u8BA1\u7B97\n float baseDensity = cloudPattern - erosion;\n float coverageThreshold = mix(0.1, -0.3, cloudCover * (0.5 + cumulusFactor * 0.5));\n float dens = saturate(baseDensity - coverageThreshold);\n\n // \u9510\u5316\u8FB9\u754C\n float sharpness = mix(1.2, 2.0, cumulusFactor) * cloudSharpness;\n dens = pow(dens, sharpness);\n\n // \u5E94\u7528\u9AD8\u5EA6\u5206\u5E03\n float verticalProfile = cloudHeightProfile(heightRatio, cloudType);\n dens *= heightFactor * cloudCover * verticalProfile;\n\n // \u5E94\u7528\u96E8\u4E91\u7279\u5F81\n dens = rainCloudDensity(dens, heightRatio, rainClouds);\n\n // \u6700\u7EC8\u5BC6\u5EA6\u8C03\u6574\n dens *= densityMultiplier;\n dens = max(dens, 0.0);\n\n return dens;\n }\n float cloudDensityFast(vec3 p)\n {\n float h = length(p) - realPlanetRadius;\n float heightRatio = clamp((h - cloudHeight) / cloudThickness, 0.0, 1.0);\n\n // \u53EA\u505A\u6700\u57FA\u7840\u7684 shape\uFF0C\u4E0D\u505A Worley\u3001\u4E0D\u505A domain warp\uFF0C\u4E0D\u505A erosion\n float n = perlinNoise(p * 0.00035);\n n = n * n * 1.2; // \u7B80\u5355\u5F3A\u5316\n\n // \u9AD8\u5EA6\u5206\u5E03\n float profile = cloudHeightProfile(heightRatio, cloudType);\n\n return saturate(n * profile * cloudCover * densityMultiplier * 0.8);\n }\n // \u4F53\u79EF\u9634\u5F71\u51FD\u6570 - \u6A21\u62DF\u5149\u7EBF\u5728\u4E91\u5185\u7684\u8870\u51CF\n float volumetricShadow(vec3 p, vec3 lightDir, float stepSize, int steps) {\n float shadow = 1.0;\n vec3 currentPos = p;\n\n for (int i = 0; i < steps; i++) {\n currentPos += lightDir * stepSize;\n float heightRatioDummy;\n float shadowDensity = cloudDensityFast(currentPos);\n\n // \u6307\u6570\u8870\u51CF\u6A21\u62DF\u5149\u7EBF\u5728\u4E91\u5185\u7684\u5438\u6536\n shadow *= exp(-shadowDensity * stepSize * absorption * 2.0);\n\n if (shadow < 0.01) break;\n }\n\n return shadow;\n }\n\n // \u6539\u8FDB\u7684\u73AF\u5883\u5149\u7167\u51FD\u6570\n vec3 calculateAmbientLight(float heightRatio, float dens, float dotLightRay) {\n // \u57FA\u7840\u73AF\u5883\u5149 - \u6839\u636E\u9AD8\u5EA6\u6DF7\u5408\u5730\u9762\u548C\u5929\u7A7A\u989C\u8272\n vec3 baseAmbient = mix(groundAmbientColor, skyAmbientColor, heightRatio);\n\n // \u5BC6\u5EA6\u76F8\u5173\u73AF\u5883\u5149 - \u8584\u4E91\u533A\u57DF\u66F4\u4EAE\n float densityFactor = 1.0 - exp(-dens * 2.0);\n baseAmbient *= (1.0 + densityFactor * 0.5);\n\n // \u80CC\u5149\u589E\u5F3A - \u5F53\u89C6\u7EBF\u4E0E\u5149\u6E90\u65B9\u5411\u63A5\u8FD1\u53CD\u5411\u65F6\n float backLightFactor = smoothstep(-0.8, -0.2, dotLightRay);\n vec3 backLightBoost = skyAmbientColor * backLightFactor * 0.8;\n\n return baseAmbient + backLightBoost;\n }\n\n // \u6539\u8FDB\u7684\u591A\u6563\u5C04\u6A21\u62DF\n float calculateMultiScatter(float dens, float heightRatio, float dotLightRay) {\n // \u57FA\u7840\u591A\u6563\u5C04\n float baseMultiScatter = pow(1.0 - exp(-dens * 1.5), 1.5) * 0.4;\n\n // \u80CC\u5149\u533A\u57DF\u989D\u5916\u591A\u6563\u5C04\n float backScatterBoost = smoothstep(-0.6, 0.0, dotLightRay) * 0.3;\n\n // \u9AD8\u7A7A\u533A\u57DF\u6563\u5C04\u589E\u5F3A\n float heightScatter = heightRatio * 0.2;\n\n return baseMultiScatter + backScatterBoost + heightScatter;\n }\n\n float distanceQualityR = 0.00005;\n float minDistance = 10.0;\n\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u6E32\u67D3\u6838\u5FC3\u51FD\u6570 =====\n vec4 calculate_clouds(vec3 start, vec3 dir, float maxDistance, vec3 light_dir, vec3 wind) {\n vec4 cloud = vec4(0.0, 0.0, 0.0, 1.0);\n float cloudTopRadius = realPlanetRadius + cloudHeight + cloudThickness;\n vec2 toTop = raySphereIntersect(start, dir, cloudTopRadius);\n float cloudBaseRadius = realPlanetRadius + cloudHeight;\n vec2 toCloudBase = raySphereIntersect(start, dir, cloudBaseRadius);\n float startHeight = length(start) - realPlanetRadius;\n\n float tmin = 0.0;\n float tmax = maxDistance;\n cloudTop = cloudHeight + cloudThickness;\n\n // \u8BA1\u7B97\u5C04\u7EBF\u4E0E\u4E91\u5C42\u7684\u4EA4\u70B9\n if (startHeight > cloudTop) {\n if (toTop.x < 0.0) return vec4(0.0);\n tmin = toTop.x;\n if (toCloudBase.x > 0.0) {\n tmax = min(toCloudBase.x, maxDistance);\n } else {\n tmax = min(toTop.y, maxDistance);\n }\n } else if (startHeight < cloudHeight) {\n tmin = toCloudBase.y;\n tmax = min(toTop.y, maxDistance);\n } else {\n if (toCloudBase.x > 0.0) {\n tmax = min(toCloudBase.x, maxDistance);\n } else {\n tmax = min(toTop.y, maxDistance);\n }\n }\n\n tmin = max(tmin, minDistance);\n tmax = min(tmax, absoluteMaxDistance);\n\n if (tmax < tmin) return vec4(0.0);\n\n float rayLength = tmax - tmin;\n float thicknessFactor = cloudThickness / 500.0;\n float baseStepSize = mix(CLOUDS_MARCH_STEP, CLOUDS_MARCH_STEP * 1.5, saturate(thicknessFactor - 1.0));\n\n float maxEffectiveSteps = min(float(MAXIMUM_CLOUDS_STEPS), 200.0 + cloudThickness * 0.2);\n float adaptiveSteps = min(maxEffectiveSteps, rayLength / baseStepSize);\n\n float longMarchStep = rayLength / adaptiveSteps;\n longMarchStep = max(longMarchStep, baseStepSize);\n\n float shortMarchStep = CLOUDS_DENS_MARCH_STEP;\n float numberApproachSteps = (longMarchStep / shortMarchStep) * 1.5;\n\n float distance = tmin;\n\n float jitter = hash12(gl_FragCoord.xy) * 1.2;\n distance += jitter * longMarchStep;\n\n bool inCloud = false;\n float stepsBeforeExitingCloud = 0.0;\n int actualSteps = 0;\n\n // \u9884\u8BA1\u7B97\u5149\u7167\u53C2\u6570\n vec3 sunColor = normalize(czm_lightColor);\n // ===== \u8865\u5168\u7684\u4F53\u79EF\u4ECB\u8D28\u5149\u7167\u8BA1\u7B97 =====\n float dotLightRay = dot(dir, light_dir);\n for (int i = 0; i < MAXIMUM_CLOUDS_STEPS; i++) {\n if (distance > tmax) break;\n if (actualSteps > int(adaptiveSteps)) break;\n\n vec3 position = start + dir * distance;\n float heightRatio;\n float marchStep = inCloud ? shortMarchStep : longMarchStep;\n float dens = cloudDensity(position, wind, heightRatio);\n\n // \u7A7A\u7A7A\u95F4\u8DF3\u8FC7\u4F18\u5316\n if (dens < 0.005) {\n if (inCloud) {\n if (stepsBeforeExitingCloud > 0.0) {\n stepsBeforeExitingCloud -= 1.0;\n } else {\n inCloud = false;\n marchStep = longMarchStep * 2.0;\n }\n }\n distance += marchStep;\n actualSteps++;\n continue;\n }\n\n // \u8FDB\u5165\u4E91\u5C42\u68C0\u6D4B\n if (!inCloud) {\n inCloud = true;\n stepsBeforeExitingCloud = numberApproachSteps;\n distance = max(tmin, distance - longMarchStep);\n continue;\n }\n\n // \u4F53\u79EF\u9634\u5F71\n float shadow = volumetricShadow(position, light_dir, shortMarchStep * 2.0, 8);\n\n // \u4F7F\u7528\u6539\u8FDB\u7684\u76F8\u4F4D\u51FD\u6570\n float sunPhase = improvedPhase(dotLightRay);\n float ambientPhase = isotropic();\n\n // \u9633\u5149\u5F3A\u5EA6\n float sunIntensity = smoothstep(0.0, 0.4, 1.0 - dens) * 0.6 * shadow;\n\n // \u73AF\u5883\u5149\u7167\n vec3 ambientLight = calculateAmbientLight(heightRatio, dens, dotLightRay);\n float ambientIntensity = 2.5;\n\n // \u591A\u6563\u5C04\n float multiScatter = calculateMultiScatter(dens, heightRatio, dotLightRay);\n\n // \u76F4\u63A5\u5149\u7167\n vec3 directLight = sunPhase * sunColor * sunIntensity * 0.5;\n\n // \u73AF\u5883\u5149\u7167\u6563\u5C04\n vec3 ambientScattering = ambientPhase * ambientLight * ambientIntensity * (1.0 + multiScatter);\n\n // \u4FA7\u5149\u548C\u80CC\u5149\u589E\u5F3A\n float sideBackLight = smoothstep(-0.5, 0.3, dotLightRay) * 0.4;\n ambientScattering += ambientLight * sideBackLight * multiScatter;\n\n // \u7EC4\u5408\u5149\u7167\n vec3 stepScattering = cloud.a * scatteringCoefficient * marchStep *\n (directLight + ambientScattering);\n\n // \u80FD\u91CF\u9650\u5236\n float maxStepBrightness = 0.25;\n stepScattering = min(stepScattering, vec3(maxStepBrightness));\n\n cloud.rgb += stepScattering;\n\n // \u900F\u660E\u5EA6\u8BA1\u7B97 - \u4F53\u79EF\u4ECB\u8D28\u7684\u6D88\u5149\n float extinctionCoeff = absorption * (0.8 + 0.2 * dens) * (0.6 + dens*0.4);\n cloud.a *= exp(-extinctionCoeff * marchStep);\n\n // \u63D0\u524D\u7EC8\u6B62\n if (cloud.a < 0.01) {\n cloud.a = 0.0;\n break;\n }\n\n distance += marchStep;\n actualSteps++;\n }\n\n // \u8272\u8C03\u6620\u5C04\n cloud.rgb = cloud.rgb / (cloud.rgb + vec3(0.8));\n\n // \u4EAE\u5EA6\u9650\u5236\n float maxChannel = max(cloud.rgb.r, max(cloud.rgb.g, cloud.rgb.b));\n if (maxChannel > 0.7) {\n float compression = smoothstep(0.7, 1.0, maxChannel) * 0.3;\n cloud.rgb = mix(cloud.rgb, cloud.rgb * (1.0 - compression), compression);\n }\n\n return vec4(cloud.rgb, 1.0 - cloud.a);\n }\n\n uniform sampler2D colorTexture;\n in vec2 v_textureCoordinates;\n\n void main() {\n vec4 color = texture(colorTexture, v_textureCoordinates);\n\n // \u8D85\u8FC7\u6700\u5927\u53EF\u89C6\u9AD8\u5EA6\u5219\u8DF3\u8FC7\u4E91\u6E32\u67D3\n float viewerHeight = length(czm_viewerPositionWC) - realPlanetRadius;\n if (viewerHeight > maxVisibleHeight) {\n out_FragColor = color;\n return;\n }\n // \u63A5\u8FD1\u6700\u5927\u53EF\u89C6\u9AD8\u5EA6\u65F6\u5E73\u6ED1\u6DE1\u51FA\n float heightFade = 1.0 - smoothstep(maxVisibleHeight - 1000.0, maxVisibleHeight, viewerHeight);\n\n vec4 rawDepthColor = texture(czm_globeDepthTexture, v_textureCoordinates);\n\n float depth = czm_unpackDepth(rawDepthColor);\n if (depth == 0.0) {\n depth = 1.0;\n }\n\n vec4 positionEC = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);\n vec4 worldCoordinate = czm_inverseView * positionEC;\n vec3 vWorldPosition = worldCoordinate.xyz / worldCoordinate.w;\n vec3 posToEye = vWorldPosition - czm_viewerPositionWC;\n vec3 direction = normalize(posToEye);\n vec3 lightDirection = normalize(czm_sunPositionWC);\n float distance = length(posToEye);\n\n if (depth == 1.0) {\n distance = absoluteMaxDistance;\n }\n\n vec3 wind = windVector * czm_frameNumber * windSpeedRatio;\n vec4 clouds = calculate_clouds(\n czm_viewerPositionWC,\n direction,\n distance,\n lightDirection,\n wind\n );\n\n color = mix(color, clouds, clouds.a * heightFade);\n out_FragColor = color;\n }\n ";
210
249
  }
211
250
 
212
251
  /**
@@ -217,8 +256,10 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
217
256
  }, {
218
257
  key: "_getRealPlanetRadius",
219
258
  value: function _getRealPlanetRadius() {
220
- if (this.viewer && this.viewer.scene && this.viewer.scene.globe) {
221
- return this.viewer.scene.globe.ellipsoid.maximumRadius;
259
+ var _map$scene;
260
+ var map = this.getMap();
261
+ if (map !== null && map !== void 0 && (_map$scene = map.scene) !== null && _map$scene !== void 0 && _map$scene.globe) {
262
+ return map.scene.globe.ellipsoid.maximumRadius;
222
263
  }
223
264
  return 6378137.0; // 默认地球赤道半径
224
265
  }
@@ -230,25 +271,10 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
230
271
  }, {
231
272
  key: "updateParameters",
232
273
  value: function updateParameters(params) {
233
- if (!params || !this.postProcessStage) return;
234
-
235
- // 更新uniforms参数
236
- for (var key in params) {
237
- if (this.uniforms.hasOwnProperty(key)) {
238
- this.uniforms[key] = params[key];
239
-
240
- // 特殊处理颜色参数
241
- if (key === 'skyAmbientColor' && typeof params[key] === 'string') {
242
- this.skyAmbientColor3 = this._hexToRgb(params[key]);
243
- } else if (key === 'groundAmbientColor' && typeof params[key] === 'string') {
244
- this.groundAmbientColor3 = this._hexToRgb(params[key]);
245
- }
246
- // 更新后处理阶段的uniforms
247
- if (this.postProcessStage.uniforms[key] !== undefined) {
248
- this.postProcessStage.uniforms[key] = params[key];
249
- }
250
- }
251
- }
274
+ if (!params || _typeof(params) !== 'object') return this;
275
+ this.uniforms = this._buildUniforms(params, this.uniforms);
276
+ this._syncAmbientColors();
277
+ return this;
252
278
  }
253
279
 
254
280
  /**
@@ -259,14 +285,14 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
259
285
  */
260
286
  }, {
261
287
  key: "_hexToRgb",
262
- value: function _hexToRgb(hex) {
263
- // 移除#号
264
- hex = hex.replace('#', '');
288
+ value: function _hexToRgb(hex, fallbackHex) {
289
+ var normalizedHex = hex.replace('#', '').trim();
290
+ var safeHex = /^[0-9a-fA-F]{6}$/.test(normalizedHex) ? normalizedHex : fallbackHex.replace('#', '');
265
291
 
266
292
  // 解析RGB值
267
- var r = parseInt(hex.substring(0, 2), 16) / 255;
268
- var g = parseInt(hex.substring(2, 4), 16) / 255;
269
- var b = parseInt(hex.substring(4, 6), 16) / 255;
293
+ var r = parseInt(safeHex.substring(0, 2), 16) / 255;
294
+ var g = parseInt(safeHex.substring(2, 4), 16) / 255;
295
+ var b = parseInt(safeHex.substring(4, 6), 16) / 255;
270
296
  return {
271
297
  r: r,
272
298
  g: g,
@@ -280,43 +306,9 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
280
306
  }, {
281
307
  key: "resetParameters",
282
308
  value: function resetParameters() {
283
- this.uniforms = {
284
- densityMultiplier: this.originalOptions.densityMultiplier || 1.5,
285
- detailStrength: this.originalOptions.detailStrength || 0.69,
286
- cloudSharpness: this.originalOptions.cloudSharpness || 1.032,
287
- rainClouds: this.originalOptions.rainClouds || 0.45,
288
- currentWindVectorWC: this.originalOptions.currentWindVectorWC || new Cesium.Cartesian3(100, 0, 0),
289
- cloudCover: this.originalOptions.cloudCover || 0.039,
290
- cloudHeight: this.originalOptions.cloudHeight || 8000.0,
291
- cloudThickness: this.originalOptions.cloudThickness || 1000.0,
292
- absoluteMaxDistance: this.originalOptions.absoluteMaxDistance || 50000000,
293
- absorption: this.originalOptions.absorption || 0.004,
294
- windSpeedRatio: this.originalOptions.windSpeedRatio || 0.3,
295
- scatteringCoefficient: this.originalOptions.scatteringCoefficient || 0.01,
296
- illuminationCoefficient: this.originalOptions.illuminationCoefficient || 0.01,
297
- cloudSeed: this.originalOptions.cloudSeed || Math.random() * 100.0,
298
- cloudType: this.originalOptions.cloudType || 0,
299
- cloudTurbulence: this.originalOptions.cloudTurbulence || 0.5,
300
- cloudClumping: this.originalOptions.cloudClumping || 0.75,
301
- cloudAnvil: this.originalOptions.cloudAnvil || 0,
302
- skyAmbientColor: this.originalOptions.skyAmbientColor || '#B4D9F3',
303
- groundAmbientColor: this.originalOptions.groundAmbientColor || '#d6d6d8'
304
- };
305
-
306
- // 重置颜色对象
307
- this.skyAmbientColor3 = {
308
- r: 0.705,
309
- g: 0.85,
310
- b: 0.952
311
- };
312
- this.groundAmbientColor3 = {
313
- r: 0.839,
314
- g: 0.839,
315
- b: 0.847
316
- };
317
-
318
- // 更新后处理阶段的参数
319
- this.updateParameters(this.uniforms);
309
+ this.uniforms = this._cloneUniforms(this.originalOptions);
310
+ this._syncAmbientColors();
311
+ return this;
320
312
  }
321
313
 
322
314
  /**
@@ -331,6 +323,7 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
331
323
  if (this.postProcessStage) {
332
324
  this.postProcessStage.enabled = true;
333
325
  }
326
+ return this;
334
327
  }
335
328
 
336
329
  /**
@@ -345,6 +338,7 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
345
338
  if (this.postProcessStage) {
346
339
  this.postProcessStage.enabled = false;
347
340
  }
341
+ return this;
348
342
  }
349
343
 
350
344
  /**
@@ -356,8 +350,10 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
356
350
  }, {
357
351
  key: "destroy",
358
352
  value: function destroy() {
359
- if (this.postProcessStage && this.viewer.scene.postProcessStages.contains(this.postProcessStage)) {
360
- this.viewer.scene.postProcessStages.remove(this.postProcessStage);
353
+ var _map$scene2;
354
+ var map = this.getMap();
355
+ if (this.postProcessStage && map !== null && map !== void 0 && (_map$scene2 = map.scene) !== null && _map$scene2 !== void 0 && _map$scene2.postProcessStages.contains(this.postProcessStage)) {
356
+ map.scene.postProcessStages.remove(this.postProcessStage);
361
357
  this.postProcessStage = null;
362
358
  }
363
359
  }
@@ -373,7 +369,7 @@ var GlobalVolumetricCloud = /*#__PURE__*/function () {
373
369
  }, {
374
370
  key: "getParameters",
375
371
  value: function getParameters() {
376
- return _objectSpread({}, this.uniforms);
372
+ return this._cloneUniforms(this.uniforms);
377
373
  }
378
374
  }]);
379
375
  return GlobalVolumetricCloud;