Skip to content

Commit

Permalink
feat: add useViewerBounds option and improve UI
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
hongfaqiu committed Oct 25, 2024
1 parent 0705ec4 commit 5b863cf
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 103 deletions.
17 changes: 17 additions & 0 deletions example/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# example

## 0.3.0

### Minor Changes

- 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

### Patch Changes

- Updated dependencies
- [email protected]

## 0.2.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "example",
"private": true,
"version": "0.2.0",
"version": "0.3.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
32 changes: 21 additions & 11 deletions example/src/components/ControlPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ColorTableInput from './ColorTableInput';
import styled from 'styled-components';
import { GithubOutlined } from '@ant-design/icons';
import { ZoomInOutlined } from '@ant-design/icons';
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';

const { Text } = Typography;

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

const [collapsed, setCollapsed] = useState(false);
const [visible, setVisible] = useState(true);

useEffect(() => {
setOptions({
Expand Down Expand Up @@ -286,6 +288,18 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
<CardTitle onClick={() => setCollapsed(!collapsed)}>
<TitleText>Wind Layer Controls</TitleText>
<TitleActions>
<TitleButton
onClick={(e) => {
e.stopPropagation();
setVisible(!visible);
if (windLayer) {
windLayer.show = !visible;
}
}}
title={visible ? "Hide Wind Layer" : "Show Wind Layer"}
>
{visible ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</TitleButton>
<TitleButton
onClick={(e) => {
e.stopPropagation();
Expand Down Expand Up @@ -350,7 +364,7 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
'Width of particle trails in pixels. Controls the width of the particles.'
)}
>
<Slider min={0.1} max={10} step={0.1} />
<Slider min={0.1} max={100} step={0.1} />
</CompactFormItem>

<CompactFormItem
Expand Down Expand Up @@ -414,21 +428,17 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
</CompactFormItem>

<CompactFormItem
name="useViewerBounds"
label={renderLabel(
'Layer Visibility',
'Toggle the visibility of the wind layer'
'Use Viewer Bounds',
'Generate particles within the current view bounds instead of the entire wind field.'
)}
valuePropName="checked"
>
<Switch
defaultChecked
size="small"
onChange={(checked: boolean) => {
if (windLayer) {
windLayer.show = checked;
}
}}
checkedChildren="Visible"
unCheckedChildren="Hidden"
checkedChildren="View Bounds"
unCheckedChildren="Global"
/>
</CompactFormItem>

Expand Down
4 changes: 3 additions & 1 deletion example/src/pages/earth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const defaultOptions: Partial<WindLayerOptions> = {
particleHeight: 1000,
dropRateBump: 0.01,
speedFactor: 10.0,
lineWidth: 3.0,
lineWidth: 10.0,
colors: colorSchemes[2].colors,
flipY: true,
};
Expand Down Expand Up @@ -63,6 +63,8 @@ export function Earth() {
viewerRef.current.scene.globe.depthTestAgainstTerrain = true;
// Optional: Add exaggeration to make terrain features more visible
viewerRef.current.scene.verticalExaggeration = 2;
viewerRef.current.sceneModePicker.viewModel.duration = 0;

// Load wind data
const loadWindData = async () => {
// Skip if wind layer already exists or viewer is not initialized
Expand Down
12 changes: 12 additions & 0 deletions packages/cesium-wind-layer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# cesium-wind-layer

## 0.4.0

### Minor Changes

- 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

## 0.3.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/cesium-wind-layer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cesium-wind-layer",
"version": "0.3.0",
"version": "0.4.0",
"publishConfig": {
"access": "public"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/cesium-wind-layer/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ A Cesium plugin for GPU-accelerated visualization of wind field data with partic
- ⚡️ Real-time wind field visualization using particle system
- 🚀 GPU-accelerated particle computation and rendering
- 🎨 Customizable particle appearance and behavior
- 🌍 Support for both 2D and 3D views
- 🏔️ Terrain occlusion support, particles are blocked by terrain

## 📦 Installation
Expand Down Expand Up @@ -71,7 +70,7 @@ const windData = {
const windLayer = new WindLayer(viewer, windData, {
particlesTextureSize: 100, // Size of the particle texture. Determines the maximum number of particles (size squared).
particleHeight: 1000, // Height of particles above ground
lineWidth: 3.0, // Width of particle trails
lineWidth: 10.0, // Width of particle trails
speedFactor: 10.0, // Speed multiplier
dropRate: 0.003, // Rate at which particles are dropped
dropRateBump: 0.001, // Additional drop rate for slow particles
Expand All @@ -92,12 +91,13 @@ Main class for wind visualization.
interface WindLayerOptions {
particlesTextureSize: number; // Size of the particle texture. Determines the maximum number of particles (size squared). (default: 100)
particleHeight: number; // Height of particles (default: 0)
lineWidth: number; // Width of particle lines (default: 3.0)
lineWidth: number; // Width of particle lines (default: 10.0)
speedFactor: number; // Speed multiplier (default: 10.0)
dropRate: number; // Particle drop rate (default: 0.003)
dropRateBump: number; // Additional drop rate (default: 0.001)
colors: string[]; // Array of colors for particles
flipY: boolean; // Flip Y coordinates (default: false)
useViewerBounds: boolean; // Use viewer bounds to generate particles (default: false)
}
```

Expand Down
4 changes: 2 additions & 2 deletions packages/cesium-wind-layer/readme.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
- ⚡️ 使用粒子系统实现实时风场可视化
- 🚀 GPU 加速的粒子计算和渲染
- 🎨 可自定义粒子外观和行为
- 🌍 支持 2D 和 3D 视图
- 🏔️ 支持地形遮挡,粒子会被地形阻挡

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

Expand Down
72 changes: 18 additions & 54 deletions packages/cesium-wind-layer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
Viewer,
Scene,
Cartesian2,
Event,
Cartesian3,
BoundingSphere,
Ellipsoid,
Expand Down Expand Up @@ -33,12 +32,13 @@ export class WindLayer {
static defaultOptions: WindLayerOptions = {
particlesTextureSize: 100,
particleHeight: 0,
lineWidth: 3.0,
lineWidth: 10.0,
speedFactor: 10,
dropRate: 0.003,
dropRateBump: 0.001,
colors: ['white'],
flipY: false
flipY: false,
useViewerBounds: false // 默认使用全局范围
}

viewer: Viewer;
Expand All @@ -51,14 +51,8 @@ export class WindLayer {
pixelSize: number;
sceneMode: SceneMode;
};
private preUpdateEvent: Event;
private postUpdateEvent: Event;
private _isDestroyed: boolean = false;
private primitives: any[] = [];
private moveStartFun: () => void;
private moveEndFun: () => void;
private resizeFun: () => void;
private preRenderFun: () => void;

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

this.viewerParameters = {
lonRange: new Cartesian2(0, 0),
latRange: new Cartesian2(0, 0),
pixelSize: 0.0,
lonRange: new Cartesian2(-180, 180),
latRange: new Cartesian2(-90, 90),
pixelSize: 2000.0,
sceneMode: this.scene.mode
};
this.updateViewerParameters();

this.preUpdateEvent = new Event();
this.postUpdateEvent = new Event();

this.particleSystem = new WindParticleSystem(this.scene.context, windData, this.options, this.viewerParameters);
this.particleSystem.applyViewerParameters(this.viewerParameters);
this.add();

this.moveStartFun = this.onMoveStart.bind(this);
this.moveEndFun = this.onMoveEnd.bind(this);
this.resizeFun = this.onResize.bind(this);
this.preRenderFun = this.onPreRender.bind(this);

this.setupEventListeners();
}

private setupEventListeners(): void {
this.viewer.camera.moveStart.addEventListener(this.moveStartFun);
this.viewer.camera.moveEnd.addEventListener(this.moveEndFun);
this.scene.preRender.addEventListener(this.preRenderFun);
window.addEventListener("resize", this.resizeFun);
this.viewer.camera.changed.addEventListener(this.updateViewerParameters.bind(this));
this.scene.morphComplete.addEventListener(this.updateViewerParameters.bind(this));
window.addEventListener("resize", this.updateViewerParameters.bind(this));
}

private removeEventListeners(): void {
this.viewer.camera.moveStart.removeEventListener(this.moveStartFun);
this.viewer.camera.moveEnd.removeEventListener(this.moveEndFun);
window.removeEventListener("resize", this.resizeFun);
this.scene.preRender.removeEventListener(this.preRenderFun);
}

private onMoveStart(): void {
}

private onMoveEnd(): void {
// this.updateViewerParameters();
// this.particleSystem.applyViewerParameters(this.viewerParameters);
}

private onResize(): void {
this._resized = true;
this.remove();
}

private onPreRender(): void {
this.preUpdateEvent.raiseEvent();
this.postUpdateEvent.raiseEvent();
if (this._resized) {
this.particleSystem.canvasResize(this.scene.context);
this.add();
this._resized = false;
}
this.viewer.camera.changed.removeEventListener(this.updateViewerParameters.bind(this));
this.scene.morphComplete.removeEventListener(this.updateViewerParameters.bind(this));
window.removeEventListener("resize", this.updateViewerParameters.bind(this));
}

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

const pixelSize = this.viewer.camera.getPixelSize(
const rawPixelSize = this.viewer.camera.getPixelSize(
new BoundingSphere(Cartesian3.ZERO, Ellipsoid.WGS84.maximumRadius),
this.viewer.scene.drawingBufferWidth,
this.viewer.scene.drawingBufferHeight
);
const pixelSize = rawPixelSize + 100;

if (pixelSize > 0) {
this.viewerParameters.pixelSize = pixelSize;
}

this.viewerParameters.sceneMode = this.scene.mode;
this.particleSystem?.applyViewerParameters(this.viewerParameters);
}

/**
Expand Down Expand Up @@ -243,4 +207,4 @@ export class WindLayer {

}

export type { WindLayerOptions, WindData };
export type { WindLayerOptions, WindData };
19 changes: 16 additions & 3 deletions packages/cesium-wind-layer/src/shaders/postProcessingPosition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ uniform float randomCoefficient;
uniform float dropRate;
uniform float dropRateBump;
// 添加新的 uniform 变量
uniform bool useViewerBounds;
in vec2 v_textureCoordinates;
vec2 mapPositionToNormalizedIndex2D(vec2 lonLat) {
Expand Down Expand Up @@ -58,8 +61,18 @@ bool particleNoSpeed(vec2 particle) {
}
vec2 generateRandomParticle(vec2 seed) {
float randomLon = rand(seed, dataLonRange);
float randomLat = rand(-seed, dataLatRange);
vec2 range;
float randomLon, randomLat;
if (useViewerBounds) {
// 在当前视域范围内生成粒子
randomLon = rand(seed, lonRange);
randomLat = rand(-seed, latRange);
} else {
// 在数据范围内生成粒子
randomLon = rand(seed, dataLonRange);
randomLat = rand(-seed, dataLatRange);
}
return vec2(randomLon, randomLat);
}
Expand Down Expand Up @@ -87,4 +100,4 @@ void main() {
fragColor = vec4(nextParticle, 0.0, 0.0);
}
}
`;
`;
Loading

0 comments on commit 5b863cf

Please sign in to comment.