Skip to content

Commit e8f6f63

Browse files
committed
feat: add domain and displayRange options for wind layer
Changes: 1. domain controls the rendering range for color mapping 2. displayRange controls particle visibility 3. Both options fallback to data's min/max when undefined 4. Early visibility check in fragment shader for better performance
1 parent db3ce04 commit e8f6f63

File tree

14 files changed

+223
-49
lines changed

14 files changed

+223
-49
lines changed

example/CHANGELOG.md

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

3+
## 0.4.1
4+
5+
### Patch Changes
6+
7+
- Updated dependencies
8+
- cesium-wind-layer@0.7.0
9+
310
## 0.4.0
411

512
### 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.4.0",
4+
"version": "0.4.1",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

example/src/components/ControlPanel.tsx

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, useState } from 'react';
2-
import { Card, Slider, Switch, Space, Tooltip, Typography, Form } from 'antd';
2+
import { Card, Slider, Switch, Space, Tooltip, Typography, Form, InputNumber } from 'antd';
33
import { WindLayer, WindLayerOptions } from 'cesium-wind-layer';
44
import { QuestionCircleOutlined } from '@ant-design/icons';
55
import ColorTableInput from './ColorTableInput';
@@ -392,6 +392,111 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
392392
unCheckedChildren="Global"
393393
/>
394394
</CompactFormItem>
395+
396+
<CompactFormItem
397+
label={renderLabel(
398+
'Speed Range',
399+
'Controls the speed range for rendering and display.'
400+
)}
401+
>
402+
<Space direction="vertical" style={{ width: '100%' }} size={8}>
403+
<div>
404+
<Text type="secondary" style={{ fontSize: '12px', marginBottom: '4px', display: 'block' }}>
405+
Rendering Range
406+
</Text>
407+
<div style={{ display: 'flex', gap: '8px' }}>
408+
<div style={{ flex: 1 }}>
409+
<CompactFormItem
410+
name={['domain', 'min']}
411+
label={
412+
<Text type="secondary" style={{ fontSize: '12px' }}>
413+
Min
414+
</Text>
415+
}
416+
style={{ marginBottom: 0 }}
417+
>
418+
<InputNumber
419+
min={0}
420+
max={50}
421+
step={0.1}
422+
style={{ width: '100px' }}
423+
placeholder="Min"
424+
precision={1}
425+
/>
426+
</CompactFormItem>
427+
</div>
428+
<div style={{ flex: 1 }}>
429+
<CompactFormItem
430+
name={['domain', 'max']}
431+
label={
432+
<Text type="secondary" style={{ fontSize: '12px' }}>
433+
Max
434+
</Text>
435+
}
436+
style={{ marginBottom: 0 }}
437+
>
438+
<InputNumber
439+
min={0}
440+
max={50}
441+
step={0.1}
442+
style={{ width: '100px' }}
443+
placeholder="Max"
444+
precision={1}
445+
/>
446+
</CompactFormItem>
447+
</div>
448+
</div>
449+
</div>
450+
451+
<div>
452+
<Text type="secondary" style={{ fontSize: '12px', marginBottom: '4px', display: 'block' }}>
453+
Display Range
454+
</Text>
455+
<div style={{ display: 'flex', gap: '8px' }}>
456+
<div style={{ flex: 1 }}>
457+
<CompactFormItem
458+
name={['displayRange', 'min']}
459+
label={
460+
<Text type="secondary" style={{ fontSize: '12px' }}>
461+
Min
462+
</Text>
463+
}
464+
style={{ marginBottom: 0 }}
465+
>
466+
<InputNumber
467+
min={0}
468+
max={50}
469+
step={0.1}
470+
style={{ width: '100px' }}
471+
placeholder="Min"
472+
precision={1}
473+
/>
474+
</CompactFormItem>
475+
</div>
476+
<div style={{ flex: 1 }}>
477+
<CompactFormItem
478+
name={['displayRange', 'max']}
479+
label={
480+
<Text type="secondary" style={{ fontSize: '12px' }}>
481+
Max
482+
</Text>
483+
}
484+
style={{ marginBottom: 0 }}
485+
>
486+
<InputNumber
487+
min={0}
488+
max={50}
489+
step={0.1}
490+
style={{ width: '100px' }}
491+
placeholder="Max"
492+
precision={1}
493+
/>
494+
</CompactFormItem>
495+
</div>
496+
</div>
497+
</div>
498+
</Space>
499+
</CompactFormItem>
395500
</Space>
396501
</Form>
397502
</CardContent>

example/src/pages/earth.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ const defaultOptions: Partial<WindLayerOptions> = {
3232
colors: colorSchemes[3].colors,
3333
flipY: true,
3434
useViewerBounds: true,
35+
domain: {
36+
min: 0,
37+
max: 8,
38+
},
3539
};
3640

3741
export function Earth() {

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.7.0
4+
5+
### Minor Changes
6+
7+
- feat: add domain and displayRange options for wind layer
8+
Changes:
9+
10+
1. domain controls the rendering range for color mapping
11+
2. displayRange controls particle visibility
12+
3. Both options fallback to data's min/max when undefined
13+
4. Early visibility check in fragment shader for better performance
14+
315
## 0.6.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.6.0",
3+
"version": "0.7.0",
44
"publishConfig": {
55
"access": "public"
66
},

packages/cesium-wind-layer/readme.md

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,12 @@ const windLayer = new WindLayer(viewer, windData, {
7070
particlesTextureSize: 100, // Size of the particle texture. Determines the maximum number of particles (size squared).
7171
particleHeight: 1000, // Height of particles above ground
7272
lineWidth: 10.0, // Width of particle trails
73-
speedFactor: 1.0, // Speed multiplier
74-
dropRate: 0.003, // Rate at which particles are dropped
75-
dropRateBump: 0.001, // Additional drop rate for slow particles
76-
colors: ['white'], // Colors for particles
77-
flipY: false // Flip Y coordinates if needed
73+
speedFactor: 1.0, // Speed multiplier
74+
dropRate: 0.003, // Rate at which particles are dropped
75+
dropRateBump: 0.001, // Additional drop rate for slow particles
76+
colors: ['white'], // Colors for particles
77+
flipY: false, // Flip Y coordinates if needed
78+
domain: undefined // Optional: domain for speed
7879
});
7980
```
8081

@@ -88,15 +89,19 @@ Main class for wind visualization.
8889

8990
```typescript
9091
interface WindLayerOptions {
91-
particlesTextureSize: number; // Size of the particle texture. Determines the maximum number of particles (size squared). (default: 100)
92-
particleHeight: number; // Height of particles (default: 0)
93-
lineWidth: number; // Width of particle lines (default: 10.0)
94-
speedFactor: number; // Speed multiplier (default: 1.0)
95-
dropRate: number; // Particle drop rate (default: 0.003)
96-
dropRateBump: number; // Additional drop rate (default: 0.001)
97-
colors: string[]; // Array of colors for particles
98-
flipY: boolean; // Flip Y coordinates (default: false)
99-
useViewerBounds: boolean; // Use viewer bounds to generate particles (default: false)
92+
particlesTextureSize: number; // Size of the particle texture. Determines the maximum number of particles (size squared). Default is 100.
93+
particleHeight: number; // Height of particles above the ground in meters. Default is 0.
94+
lineWidth: number; // Width of particle trails in pixels. Default is 10.0.
95+
speedFactor: number; // Factor to adjust the speed of particles. Default is 1.0.
96+
dropRate: number; // Rate at which particles are dropped (reset). Default is 0.003.
97+
dropRateBump: number; // Additional drop rate for slow-moving particles. Default is 0.001.
98+
colors: string[]; // Array of colors for particles. Can be used to create color gradients. Default is ['white'].
99+
flipY: boolean; // Whether to flip the Y-axis of the wind data. Default is false.
100+
useViewerBounds: boolean; // Whether to use the viewer bounds to generate particles. Default is false.
101+
domain?: { // Controls the speed rendering range. Default is undefined.
102+
min?: number; // Minimum speed value for rendering
103+
max?: number; // Maximum speed value for rendering
104+
};
100105
}
101106
```
102107

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,15 @@ const windData = {
6767

6868
// 使用配置创建风场图层
6969
const windLayer = new WindLayer(viewer, windData, {
70-
particlesTextureSize: 100, // 粒子系统的纹理大小
71-
particleHeight: 1000, // 粒子距地面高度
72-
lineWidth: 10.0, // 粒子轨迹宽度
73-
speedFactor: 1.0, // 速度倍数
70+
particlesTextureSize: 100, // 粒子系统的纹理大小
71+
particleHeight: 1000, // 粒子距地面高度
72+
lineWidth: 10.0, // 粒子轨迹宽度
73+
speedFactor: 1.0, // 速度倍数
7474
dropRate: 0.003, // 粒子消失率
7575
dropRateBump: 0.001, // 慢速粒子的额外消失率
7676
colors: ['white'], // 粒子颜色
77-
flipY: false // 是否翻转 Y 坐标
77+
flipY: false, // 是否翻转 Y 坐标
78+
domain: undefined // 速度渲染范围
7879
});
7980
```
8081

@@ -90,13 +91,17 @@ const windLayer = new WindLayer(viewer, windData, {
9091
interface WindLayerOptions {
9192
particlesTextureSize: number; // 粒子纹理大小,决定粒子最大数量(size * size)(默认:100)
9293
particleHeight: number; // 粒子距地面高度(默认:0)
93-
lineWidth: number; // 粒子线宽(默认:3.0)
94+
lineWidth: number; // 粒子线宽(默认:10.0)
9495
speedFactor: number; // 速度倍数(默认:1.0)
9596
dropRate: number; // 粒子消失率(默认:0.003)
96-
dropRateBump: number; // 额外消失率(默认:0.001
97-
colors: string[]; // 粒子颜色数组
97+
dropRateBump: number; // 额外消失率(默认:0.01
98+
colors: string[]; // 粒子颜色数组(默认:['white'])
9899
flipY: boolean; // 是否翻转 Y 坐标(默认:false)
99100
useViewerBounds: boolean; // 是否使用视域范围生成粒子(默认:false)
101+
domain?: { // 速度渲染范围(默认:undefined)
102+
min?: number; // 最小速度值
103+
max?: number; // 最大速度值
104+
};
100105
}
101106
```
102107

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ export class WindLayer {
4040
lineWidth: 10.0,
4141
colors: ['white'],
4242
flipY: false,
43-
useViewerBounds: false // 默认使用全局范围
43+
useViewerBounds: false,
44+
domain: undefined,
45+
displayRange: undefined
4446
}
4547

4648
viewer: Viewer;
@@ -109,8 +111,7 @@ export class WindLayer {
109111
}
110112

111113
private processWindData(windData: WindData): Required<WindData> {
112-
if (windData.speed?.min === undefined || windData.speed?.max === undefined) {
113-
console.info('no speed data, calculate speed...');
114+
if (windData.speed?.min === undefined || windData.speed?.max === undefined || windData.speed.array === undefined) {
114115
const speed = {
115116
array: new Float32Array(windData.u.array.length),
116117
min: Number.MAX_VALUE,
@@ -123,11 +124,9 @@ export class WindLayer {
123124
speed.max = Math.max(speed.max, speed.array[i]);
124125
}
125126
}
126-
return {
127-
...windData,
128-
speed
129-
}
127+
windData = { ...windData, speed };
130128
}
129+
131130
return windData as Required<WindData>;
132131
}
133132

@@ -295,6 +294,7 @@ export class WindLayer {
295294
* @param {WindData} data - The new wind data to apply.
296295
*/
297296
updateWindData(data: WindData): void {
297+
if (this._isDestroyed) return;
298298
this.windData = this.processWindData(data);
299299
this.particleSystem.computing.updateWindData(this.windData);
300300
this.viewer.scene.requestRender();
@@ -307,6 +307,7 @@ export class WindLayer {
307307
* @param {Partial<WindLayerOptions>} options - The new options to apply.
308308
*/
309309
updateOptions(options: Partial<WindLayerOptions>): void {
310+
if (this._isDestroyed) return;
310311
this.options = { ...this.options, ...options };
311312
this.particleSystem.changeOptions(options);
312313
this.viewer.scene.requestRender();

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,16 @@ vec2 calculateSpeedByRungeKutta2(vec2 lonLat) {
117117
}
118118
119119
120-
float calculateWindNorm(vec2 speed) {
121-
vec3 percent = vec3(0.0);
120+
vec2 calculateWindNorm(vec2 speed) {
122121
float speedLength = length(speed.xy);
123122
if(speedLength == 0.0){
124-
return 0.0;
123+
return vec2(0.0);
125124
}
126125
127-
return (speedLength - speedRange.x) / (speedRange.y - speedRange.x);
126+
// Clamp speedLength to range
127+
float clampedSpeed = clamp(speedLength, speedRange.x, speedRange.y);
128+
float normalizedSpeed = (clampedSpeed - speedRange.x) / (speedRange.y - speedRange.x);
129+
return vec2(speedLength, normalizedSpeed);
128130
}
129131
130132
out vec4 fragColor;
@@ -136,7 +138,7 @@ void main() {
136138
vec2 speed = calculateSpeedByRungeKutta2(lonLat);
137139
vec2 speedInLonLat = convertSpeedUnitToLonLat(lonLat, speed);
138140
139-
vec3 particleSpeed = vec3(speedInLonLat, calculateWindNorm(speed / speedScaleFactor));
140-
fragColor = vec4(speedInLonLat, calculateWindNorm(speedOrigin), 0.0);
141+
vec4 particleSpeed = vec4(speedInLonLat, calculateWindNorm(speed / speedScaleFactor));
142+
fragColor = vec4(speedInLonLat, calculateWindNorm(speedOrigin));
141143
}
142144
`;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ out vec4 fragColor;
5656
5757
void main() {
5858
vec2 nextParticle = texture(nextParticlesPosition, v_textureCoordinates).rg;
59-
vec3 nextSpeed = texture(particlesSpeed, v_textureCoordinates).rgb;
60-
float speedNorm = nextSpeed.b;
59+
vec4 nextSpeed = texture(particlesSpeed, v_textureCoordinates);
60+
float speedNorm = nextSpeed.a;
6161
float particleDropRate = dropRate + dropRateBump * speedNorm;
6262
6363
vec2 seed1 = nextParticle.xy + v_textureCoordinates;
64-
vec2 seed2 = nextSpeed.xy + v_textureCoordinates;
64+
vec2 seed2 = nextSpeed.rg + v_textureCoordinates;
6565
vec2 randomParticle = generateRandomParticle(seed1);
6666
float randomNumber = rand(seed2, normalRange);
6767

0 commit comments

Comments
 (0)