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.
- package/dist/esm/constant.d.ts +10 -0
- package/dist/esm/constant.js +10 -1
- package/dist/esm/drawCommand/viewShed/RectangularSensorPrimitive.d.ts +1 -0
- package/dist/esm/drawCommand/viewShed/ViewShedAnalyserLayer.d.ts +1 -0
- package/dist/esm/drawer/common.d.ts +1 -0
- package/dist/esm/drawer/coordinate.d.ts +1 -0
- package/dist/esm/drawer/index.d.ts +1 -1
- package/dist/esm/drawer/shape/BaseShape.d.ts +1 -0
- package/dist/esm/graphicLayer/BaseLayer.d.ts +23 -0
- package/dist/esm/graphicLayer/BaseLayer.js +387 -65
- package/dist/esm/graphicLayer/BasePrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/BasePrimitiveInstance.js +0 -7
- package/dist/esm/graphicLayer/BaseSource.d.ts +1 -1
- package/dist/esm/graphicLayer/BoxPrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/BoxPrimitiveInstance.js +4 -8
- package/dist/esm/graphicLayer/EllipsePrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/EllipsePrimitiveInstance.js +5 -9
- package/dist/esm/graphicLayer/EllipsoidPrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/EllipsoidPrimitiveInstance.js +5 -9
- package/dist/esm/graphicLayer/GraphicLayerCollection.js +20 -27
- package/dist/esm/graphicLayer/ModelPrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/ModelPrimitiveInstance.js +0 -7
- package/dist/esm/graphicLayer/PolygonGroundPrimitiveImageMaterialInstance.js +5 -2
- package/dist/esm/graphicLayer/PolygonPrimitiveImageMaterialInstance.js +5 -2
- package/dist/esm/graphicLayer/PolygonPrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/PolygonPrimitiveInstance.js +5 -9
- package/dist/esm/graphicLayer/PolylineGroundPrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/PolylineGroundPrimitiveInstance.js +4 -8
- package/dist/esm/graphicLayer/PolylinePrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/PolylinePrimitiveInstance.js +4 -8
- package/dist/esm/graphicLayer/PolylineVolumePrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/PolylineVolumePrimitiveInstance.js +4 -8
- package/dist/esm/graphicLayer/WallPrimitiveInstance.d.ts +0 -1
- package/dist/esm/graphicLayer/WallPrimitiveInstance.js +4 -8
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +6 -2
- package/dist/esm/map/Map.d.ts +9 -0
- package/dist/esm/map/Map.js +115 -2
- package/dist/esm/material/AtmosphericDispersion.d.ts +71 -0
- package/dist/esm/material/AtmosphericDispersion.js +485 -33
- package/dist/esm/material/GlobalVolumetricCloud.d.ts +117 -0
- package/dist/esm/material/GlobalVolumetricCloud.js +219 -223
- package/dist/esm/material/WeatherEffects.d.ts +64 -14
- package/dist/esm/material/WeatherEffects.js +279 -95
- package/dist/esm/material/entity/ImageMaterialProperty.d.ts +1 -0
- package/dist/esm/material/shader/AtmosphericShader.glsl +244 -0
- package/dist/esm/material/shader/RainShader.glsl +44 -6
- package/dist/esm/material/shader/lightning.glsl +70 -0
- package/dist/esm/measure/BaseDraw.d.ts +1 -0
- package/dist/esm/measure/types.d.ts +1 -0
- package/dist/esm/measure/utils.d.ts +1 -0
- package/dist/esm/sceneFusion/Airway.d.ts +0 -0
- package/dist/esm/sceneFusion/Airway.js +692 -0
- package/dist/esm/tileLayer/ArcGisLayer.d.ts +1 -0
- package/dist/esm/tileLayer/ImageryLayer.d.ts +1 -0
- package/dist/esm/tileLayer/MvtVectorLoad.d.ts +13 -0
- package/dist/esm/tileLayer/MvtVectorLoad.js +245 -49
- package/dist/esm/tool/common.d.ts +1 -0
- package/dist/esm/tool/utils.d.ts +1 -0
- package/dist/esm/typings.d.ts +8 -0
- package/dist/esm/visualization/BaseHeatmap.d.ts +5 -0
- package/dist/esm/visualization/BaseHeatmap.js +54 -12
- package/dist/esm/visualization/Heatmap2d.d.ts +1 -0
- package/dist/esm/visualization/Heatmap2d.js +17 -26
- package/dist/esm/visualization/Heatmap3d.d.ts +8 -2
- package/dist/esm/visualization/Heatmap3d.js +195 -59
- package/dist/umd/deeptwins-engine-3d.min.js +1 -1
- 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
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
//
|
|
85
|
-
this
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
|
129
|
-
g: 0
|
|
130
|
-
b: 0
|
|
69
|
+
r: 0,
|
|
70
|
+
g: 0,
|
|
71
|
+
b: 0
|
|
131
72
|
};
|
|
132
73
|
this.groundAmbientColor3 = {
|
|
133
|
-
r: 0
|
|
134
|
-
g: 0
|
|
135
|
-
b: 0
|
|
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:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
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
|
-
|
|
221
|
-
|
|
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 ||
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
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(
|
|
268
|
-
var g = parseInt(
|
|
269
|
-
var b = parseInt(
|
|
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
|
-
|
|
285
|
-
|
|
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
|
-
|
|
360
|
-
|
|
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
|
|
372
|
+
return this._cloneUniforms(this.uniforms);
|
|
377
373
|
}
|
|
378
374
|
}]);
|
|
379
375
|
return GlobalVolumetricCloud;
|