Skip to content

Commit 5b863cf

Browse files
committed
feat: add useViewerBounds option and improve UI
- Add useViewerBounds option to control particle generation range - Move layer visibility control to title bar - Update default line width to 10.0 - Add base pixel size offset to prevent particles from being too small - Update types and documentation
1 parent 0705ec4 commit 5b863cf

File tree

14 files changed

+145
-103
lines changed

14 files changed

+145
-103
lines changed

example/CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# example
22

3+
## 0.3.0
4+
5+
### Minor Changes
6+
7+
- feat: add useViewerBounds option and improve UI
8+
9+
- Add useViewerBounds option to control particle generation range
10+
- Move layer visibility control to title bar
11+
- Update default line width to 10.0
12+
- Add base pixel size offset to prevent particles from being too small
13+
- Update types and documentation
14+
15+
### Patch Changes
16+
17+
- Updated dependencies
18+
- cesium-wind-layer@0.4.0
19+
320
## 0.2.0
421

522
### Minor Changes

example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "example",
33
"private": true,
4-
"version": "0.2.0",
4+
"version": "0.3.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

example/src/components/ControlPanel.tsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import ColorTableInput from './ColorTableInput';
66
import styled from 'styled-components';
77
import { GithubOutlined } from '@ant-design/icons';
88
import { ZoomInOutlined } from '@ant-design/icons';
9+
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
910

1011
const { Text } = Typography;
1112

@@ -252,6 +253,7 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
252253
});
253254

254255
const [collapsed, setCollapsed] = useState(false);
256+
const [visible, setVisible] = useState(true);
255257

256258
useEffect(() => {
257259
setOptions({
@@ -286,6 +288,18 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
286288
<CardTitle onClick={() => setCollapsed(!collapsed)}>
287289
<TitleText>Wind Layer Controls</TitleText>
288290
<TitleActions>
291+
<TitleButton
292+
onClick={(e) => {
293+
e.stopPropagation();
294+
setVisible(!visible);
295+
if (windLayer) {
296+
windLayer.show = !visible;
297+
}
298+
}}
299+
title={visible ? "Hide Wind Layer" : "Show Wind Layer"}
300+
>
301+
{visible ? <EyeOutlined /> : <EyeInvisibleOutlined />}
302+
</TitleButton>
289303
<TitleButton
290304
onClick={(e) => {
291305
e.stopPropagation();
@@ -350,7 +364,7 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
350364
'Width of particle trails in pixels. Controls the width of the particles.'
351365
)}
352366
>
353-
<Slider min={0.1} max={10} step={0.1} />
367+
<Slider min={0.1} max={100} step={0.1} />
354368
</CompactFormItem>
355369

356370
<CompactFormItem
@@ -414,21 +428,17 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
414428
</CompactFormItem>
415429

416430
<CompactFormItem
431+
name="useViewerBounds"
417432
label={renderLabel(
418-
'Layer Visibility',
419-
'Toggle the visibility of the wind layer'
433+
'Use Viewer Bounds',
434+
'Generate particles within the current view bounds instead of the entire wind field.'
420435
)}
436+
valuePropName="checked"
421437
>
422438
<Switch
423-
defaultChecked
424439
size="small"
425-
onChange={(checked: boolean) => {
426-
if (windLayer) {
427-
windLayer.show = checked;
428-
}
429-
}}
430-
checkedChildren="Visible"
431-
unCheckedChildren="Hidden"
440+
checkedChildren="View Bounds"
441+
unCheckedChildren="Global"
432442
/>
433443
</CompactFormItem>
434444

example/src/pages/earth.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const defaultOptions: Partial<WindLayerOptions> = {
1919
particleHeight: 1000,
2020
dropRateBump: 0.01,
2121
speedFactor: 10.0,
22-
lineWidth: 3.0,
22+
lineWidth: 10.0,
2323
colors: colorSchemes[2].colors,
2424
flipY: true,
2525
};
@@ -63,6 +63,8 @@ export function Earth() {
6363
viewerRef.current.scene.globe.depthTestAgainstTerrain = true;
6464
// Optional: Add exaggeration to make terrain features more visible
6565
viewerRef.current.scene.verticalExaggeration = 2;
66+
viewerRef.current.sceneModePicker.viewModel.duration = 0;
67+
6668
// Load wind data
6769
const loadWindData = async () => {
6870
// Skip if wind layer already exists or viewer is not initialized

packages/cesium-wind-layer/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# cesium-wind-layer
22

3+
## 0.4.0
4+
5+
### Minor Changes
6+
7+
- feat: add useViewerBounds option and improve UI
8+
9+
- Add useViewerBounds option to control particle generation range
10+
- Move layer visibility control to title bar
11+
- Update default line width to 10.0
12+
- Add base pixel size offset to prevent particles from being too small
13+
- Update types and documentation
14+
315
## 0.3.0
416

517
### Minor Changes

packages/cesium-wind-layer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cesium-wind-layer",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"publishConfig": {
55
"access": "public"
66
},

packages/cesium-wind-layer/readme.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ A Cesium plugin for GPU-accelerated visualization of wind field data with partic
2525
- ⚡️ Real-time wind field visualization using particle system
2626
- 🚀 GPU-accelerated particle computation and rendering
2727
- 🎨 Customizable particle appearance and behavior
28-
- 🌍 Support for both 2D and 3D views
2928
- 🏔️ Terrain occlusion support, particles are blocked by terrain
3029

3130
## 📦 Installation
@@ -71,7 +70,7 @@ const windData = {
7170
const windLayer = new WindLayer(viewer, windData, {
7271
particlesTextureSize: 100, // Size of the particle texture. Determines the maximum number of particles (size squared).
7372
particleHeight: 1000, // Height of particles above ground
74-
lineWidth: 3.0, // Width of particle trails
73+
lineWidth: 10.0, // Width of particle trails
7574
speedFactor: 10.0, // Speed multiplier
7675
dropRate: 0.003, // Rate at which particles are dropped
7776
dropRateBump: 0.001, // Additional drop rate for slow particles
@@ -92,12 +91,13 @@ Main class for wind visualization.
9291
interface WindLayerOptions {
9392
particlesTextureSize: number; // Size of the particle texture. Determines the maximum number of particles (size squared). (default: 100)
9493
particleHeight: number; // Height of particles (default: 0)
95-
lineWidth: number; // Width of particle lines (default: 3.0)
94+
lineWidth: number; // Width of particle lines (default: 10.0)
9695
speedFactor: number; // Speed multiplier (default: 10.0)
9796
dropRate: number; // Particle drop rate (default: 0.003)
9897
dropRateBump: number; // Additional drop rate (default: 0.001)
9998
colors: string[]; // Array of colors for particles
10099
flipY: boolean; // Flip Y coordinates (default: false)
100+
useViewerBounds: boolean; // Use viewer bounds to generate particles (default: false)
101101
}
102102
```
103103

packages/cesium-wind-layer/readme.zh-CN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
- ⚡️ 使用粒子系统实现实时风场可视化
2626
- 🚀 GPU 加速的粒子计算和渲染
2727
- 🎨 可自定义粒子外观和行为
28-
- 🌍 支持 2D 和 3D 视图
2928
- 🏔️ 支持地形遮挡,粒子会被地形阻挡
3029

3130
## 📦 安装
@@ -71,7 +70,7 @@ const windData = {
7170
const windLayer = new WindLayer(viewer, windData, {
7271
particlesTextureSize: 256, // 粒子系统的纹理大小
7372
particleHeight: 1000, // 粒子距地面高度
74-
lineWidth: 3.0, // 粒子轨迹宽度
73+
lineWidth: 10.0, // 粒子轨迹宽度
7574
speedFactor: 10.0, // 速度倍数
7675
dropRate: 0.003, // 粒子消失率
7776
dropRateBump: 0.001, // 慢速粒子的额外消失率
@@ -98,6 +97,7 @@ interface WindLayerOptions {
9897
dropRateBump: number; // 额外消失率(默认:0.001)
9998
colors: string[]; // 粒子颜色数组
10099
flipY: boolean; // 是否翻转 Y 坐标(默认:false)
100+
useViewerBounds: boolean; // 是否使用视域范围生成粒子(默认:false)
101101
}
102102
```
103103

packages/cesium-wind-layer/src/index.ts

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {
22
Viewer,
33
Scene,
44
Cartesian2,
5-
Event,
65
Cartesian3,
76
BoundingSphere,
87
Ellipsoid,
@@ -33,12 +32,13 @@ export class WindLayer {
3332
static defaultOptions: WindLayerOptions = {
3433
particlesTextureSize: 100,
3534
particleHeight: 0,
36-
lineWidth: 3.0,
35+
lineWidth: 10.0,
3736
speedFactor: 10,
3837
dropRate: 0.003,
3938
dropRateBump: 0.001,
4039
colors: ['white'],
41-
flipY: false
40+
flipY: false,
41+
useViewerBounds: false // 默认使用全局范围
4242
}
4343

4444
viewer: Viewer;
@@ -51,14 +51,8 @@ export class WindLayer {
5151
pixelSize: number;
5252
sceneMode: SceneMode;
5353
};
54-
private preUpdateEvent: Event;
55-
private postUpdateEvent: Event;
5654
private _isDestroyed: boolean = false;
5755
private primitives: any[] = [];
58-
private moveStartFun: () => void;
59-
private moveEndFun: () => void;
60-
private resizeFun: () => void;
61-
private preRenderFun: () => void;
6256

6357
/**
6458
* WindLayer class for visualizing wind field data with particle animation in Cesium.
@@ -75,6 +69,7 @@ export class WindLayer {
7569
* @param {number} [options.dropRateBump=0.001] - Additional drop rate for slow-moving particles.
7670
* @param {string[]} [options.colors=['white']] - Array of colors for particles. Can be used to create color gradients.
7771
* @param {boolean} [options.flipY=false] - Whether to flip the Y-axis of the wind data.
72+
* @param {boolean} [options.useViewerBounds=false] - Whether to use the viewer bounds to generate particles.
7873
*/
7974
constructor(viewer: Viewer, windData: WindData, options?: Partial<WindLayerOptions>) {
8075
this.show = true;
@@ -84,63 +79,29 @@ export class WindLayer {
8479
this.windData = windData;
8580

8681
this.viewerParameters = {
87-
lonRange: new Cartesian2(0, 0),
88-
latRange: new Cartesian2(0, 0),
89-
pixelSize: 0.0,
82+
lonRange: new Cartesian2(-180, 180),
83+
latRange: new Cartesian2(-90, 90),
84+
pixelSize: 2000.0,
9085
sceneMode: this.scene.mode
9186
};
9287
this.updateViewerParameters();
9388

94-
this.preUpdateEvent = new Event();
95-
this.postUpdateEvent = new Event();
96-
9789
this.particleSystem = new WindParticleSystem(this.scene.context, windData, this.options, this.viewerParameters);
98-
this.particleSystem.applyViewerParameters(this.viewerParameters);
9990
this.add();
10091

101-
this.moveStartFun = this.onMoveStart.bind(this);
102-
this.moveEndFun = this.onMoveEnd.bind(this);
103-
this.resizeFun = this.onResize.bind(this);
104-
this.preRenderFun = this.onPreRender.bind(this);
105-
10692
this.setupEventListeners();
10793
}
10894

10995
private setupEventListeners(): void {
110-
this.viewer.camera.moveStart.addEventListener(this.moveStartFun);
111-
this.viewer.camera.moveEnd.addEventListener(this.moveEndFun);
112-
this.scene.preRender.addEventListener(this.preRenderFun);
113-
window.addEventListener("resize", this.resizeFun);
96+
this.viewer.camera.changed.addEventListener(this.updateViewerParameters.bind(this));
97+
this.scene.morphComplete.addEventListener(this.updateViewerParameters.bind(this));
98+
window.addEventListener("resize", this.updateViewerParameters.bind(this));
11499
}
115100

116101
private removeEventListeners(): void {
117-
this.viewer.camera.moveStart.removeEventListener(this.moveStartFun);
118-
this.viewer.camera.moveEnd.removeEventListener(this.moveEndFun);
119-
window.removeEventListener("resize", this.resizeFun);
120-
this.scene.preRender.removeEventListener(this.preRenderFun);
121-
}
122-
123-
private onMoveStart(): void {
124-
}
125-
126-
private onMoveEnd(): void {
127-
// this.updateViewerParameters();
128-
// this.particleSystem.applyViewerParameters(this.viewerParameters);
129-
}
130-
131-
private onResize(): void {
132-
this._resized = true;
133-
this.remove();
134-
}
135-
136-
private onPreRender(): void {
137-
this.preUpdateEvent.raiseEvent();
138-
this.postUpdateEvent.raiseEvent();
139-
if (this._resized) {
140-
this.particleSystem.canvasResize(this.scene.context);
141-
this.add();
142-
this._resized = false;
143-
}
102+
this.viewer.camera.changed.removeEventListener(this.updateViewerParameters.bind(this));
103+
this.scene.morphComplete.removeEventListener(this.updateViewerParameters.bind(this));
104+
window.removeEventListener("resize", this.updateViewerParameters.bind(this));
144105
}
145106

146107
private updateViewerParameters(): void {
@@ -163,16 +124,19 @@ export class WindLayer {
163124
this.viewerParameters.latRange = latRange;
164125
}
165126

166-
const pixelSize = this.viewer.camera.getPixelSize(
127+
const rawPixelSize = this.viewer.camera.getPixelSize(
167128
new BoundingSphere(Cartesian3.ZERO, Ellipsoid.WGS84.maximumRadius),
168129
this.viewer.scene.drawingBufferWidth,
169130
this.viewer.scene.drawingBufferHeight
170131
);
132+
const pixelSize = rawPixelSize + 100;
133+
171134
if (pixelSize > 0) {
172135
this.viewerParameters.pixelSize = pixelSize;
173136
}
174137

175138
this.viewerParameters.sceneMode = this.scene.mode;
139+
this.particleSystem?.applyViewerParameters(this.viewerParameters);
176140
}
177141

178142
/**
@@ -243,4 +207,4 @@ export class WindLayer {
243207

244208
}
245209

246-
export type { WindLayerOptions, WindData };
210+
export type { WindLayerOptions, WindData };

packages/cesium-wind-layer/src/shaders/postProcessingPosition.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ uniform float randomCoefficient;
2121
uniform float dropRate;
2222
uniform float dropRateBump;
2323
24+
// 添加新的 uniform 变量
25+
uniform bool useViewerBounds;
26+
2427
in vec2 v_textureCoordinates;
2528
2629
vec2 mapPositionToNormalizedIndex2D(vec2 lonLat) {
@@ -58,8 +61,18 @@ bool particleNoSpeed(vec2 particle) {
5861
}
5962
6063
vec2 generateRandomParticle(vec2 seed) {
61-
float randomLon = rand(seed, dataLonRange);
62-
float randomLat = rand(-seed, dataLatRange);
64+
vec2 range;
65+
float randomLon, randomLat;
66+
67+
if (useViewerBounds) {
68+
// 在当前视域范围内生成粒子
69+
randomLon = rand(seed, lonRange);
70+
randomLat = rand(-seed, latRange);
71+
} else {
72+
// 在数据范围内生成粒子
73+
randomLon = rand(seed, dataLonRange);
74+
randomLat = rand(-seed, dataLatRange);
75+
}
6376
6477
return vec2(randomLon, randomLat);
6578
}
@@ -87,4 +100,4 @@ void main() {
87100
fragColor = vec4(nextParticle, 0.0, 0.0);
88101
}
89102
}
90-
`;
103+
`;

0 commit comments

Comments
 (0)