Skip to content

Commit

Permalink
feat: add domain and displayRange options for wind layer
Browse files Browse the repository at this point in the history
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
  • Loading branch information
hongfaqiu committed Oct 30, 2024
1 parent db3ce04 commit e8f6f63
Show file tree
Hide file tree
Showing 14 changed files with 223 additions and 49 deletions.
7 changes: 7 additions & 0 deletions example/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# example

## 0.4.1

### Patch Changes

- Updated dependencies
- [email protected]

## 0.4.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.4.0",
"version": "0.4.1",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
107 changes: 106 additions & 1 deletion example/src/components/ControlPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { Card, Slider, Switch, Space, Tooltip, Typography, Form } from 'antd';
import { Card, Slider, Switch, Space, Tooltip, Typography, Form, InputNumber } from 'antd';
import { WindLayer, WindLayerOptions } from 'cesium-wind-layer';
import { QuestionCircleOutlined } from '@ant-design/icons';
import ColorTableInput from './ColorTableInput';
Expand Down Expand Up @@ -392,6 +392,111 @@ export const ControlPanel: React.FC<ControlPanelProps> = ({
unCheckedChildren="Global"
/>
</CompactFormItem>

<CompactFormItem
label={renderLabel(
'Speed Range',
'Controls the speed range for rendering and display.'
)}
>
<Space direction="vertical" style={{ width: '100%' }} size={8}>
<div>
<Text type="secondary" style={{ fontSize: '12px', marginBottom: '4px', display: 'block' }}>
Rendering Range
</Text>
<div style={{ display: 'flex', gap: '8px' }}>
<div style={{ flex: 1 }}>
<CompactFormItem
name={['domain', 'min']}
label={
<Text type="secondary" style={{ fontSize: '12px' }}>
Min
</Text>
}
style={{ marginBottom: 0 }}
>
<InputNumber
min={0}
max={50}
step={0.1}
style={{ width: '100px' }}
placeholder="Min"
precision={1}
/>
</CompactFormItem>
</div>
<div style={{ flex: 1 }}>
<CompactFormItem
name={['domain', 'max']}
label={
<Text type="secondary" style={{ fontSize: '12px' }}>
Max
</Text>
}
style={{ marginBottom: 0 }}
>
<InputNumber
min={0}
max={50}
step={0.1}
style={{ width: '100px' }}
placeholder="Max"
precision={1}
/>
</CompactFormItem>
</div>
</div>
</div>

<div>
<Text type="secondary" style={{ fontSize: '12px', marginBottom: '4px', display: 'block' }}>
Display Range
</Text>
<div style={{ display: 'flex', gap: '8px' }}>
<div style={{ flex: 1 }}>
<CompactFormItem
name={['displayRange', 'min']}
label={
<Text type="secondary" style={{ fontSize: '12px' }}>
Min
</Text>
}
style={{ marginBottom: 0 }}
>
<InputNumber
min={0}
max={50}
step={0.1}
style={{ width: '100px' }}
placeholder="Min"
precision={1}
/>
</CompactFormItem>
</div>
<div style={{ flex: 1 }}>
<CompactFormItem
name={['displayRange', 'max']}
label={
<Text type="secondary" style={{ fontSize: '12px' }}>
Max
</Text>
}
style={{ marginBottom: 0 }}
>
<InputNumber
min={0}
max={50}
step={0.1}
style={{ width: '100px' }}
placeholder="Max"
precision={1}
/>
</CompactFormItem>
</div>
</div>
</div>
</Space>
</CompactFormItem>
</Space>
</Form>
</CardContent>
Expand Down
4 changes: 4 additions & 0 deletions example/src/pages/earth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const defaultOptions: Partial<WindLayerOptions> = {
colors: colorSchemes[3].colors,
flipY: true,
useViewerBounds: true,
domain: {
min: 0,
max: 8,
},
};

export function Earth() {
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.7.0

### Minor Changes

- 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

## 0.6.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.6.0",
"version": "0.7.0",
"publishConfig": {
"access": "public"
},
Expand Down
33 changes: 19 additions & 14 deletions packages/cesium-wind-layer/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ 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: 10.0, // Width of particle trails
speedFactor: 1.0, // Speed multiplier
dropRate: 0.003, // Rate at which particles are dropped
dropRateBump: 0.001, // Additional drop rate for slow particles
colors: ['white'], // Colors for particles
flipY: false // Flip Y coordinates if needed
speedFactor: 1.0, // Speed multiplier
dropRate: 0.003, // Rate at which particles are dropped
dropRateBump: 0.001, // Additional drop rate for slow particles
colors: ['white'], // Colors for particles
flipY: false, // Flip Y coordinates if needed
domain: undefined // Optional: domain for speed
});
```

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

```typescript
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: 10.0)
speedFactor: number; // Speed multiplier (default: 1.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)
particlesTextureSize: number; // Size of the particle texture. Determines the maximum number of particles (size squared). Default is 100.
particleHeight: number; // Height of particles above the ground in meters. Default is 0.
lineWidth: number; // Width of particle trails in pixels. Default is 10.0.
speedFactor: number; // Factor to adjust the speed of particles. Default is 1.0.
dropRate: number; // Rate at which particles are dropped (reset). Default is 0.003.
dropRateBump: number; // Additional drop rate for slow-moving particles. Default is 0.001.
colors: string[]; // Array of colors for particles. Can be used to create color gradients. Default is ['white'].
flipY: boolean; // Whether to flip the Y-axis of the wind data. Default is false.
useViewerBounds: boolean; // Whether to use the viewer bounds to generate particles. Default is false.
domain?: { // Controls the speed rendering range. Default is undefined.
min?: number; // Minimum speed value for rendering
max?: number; // Maximum speed value for rendering
};
}
```

Expand Down
21 changes: 13 additions & 8 deletions packages/cesium-wind-layer/readme.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ const windData = {

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

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

Expand Down
15 changes: 8 additions & 7 deletions packages/cesium-wind-layer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ export class WindLayer {
lineWidth: 10.0,
colors: ['white'],
flipY: false,
useViewerBounds: false // 默认使用全局范围
useViewerBounds: false,
domain: undefined,
displayRange: undefined
}

viewer: Viewer;
Expand Down Expand Up @@ -109,8 +111,7 @@ export class WindLayer {
}

private processWindData(windData: WindData): Required<WindData> {
if (windData.speed?.min === undefined || windData.speed?.max === undefined) {
console.info('no speed data, calculate speed...');
if (windData.speed?.min === undefined || windData.speed?.max === undefined || windData.speed.array === undefined) {
const speed = {
array: new Float32Array(windData.u.array.length),
min: Number.MAX_VALUE,
Expand All @@ -123,11 +124,9 @@ export class WindLayer {
speed.max = Math.max(speed.max, speed.array[i]);
}
}
return {
...windData,
speed
}
windData = { ...windData, speed };
}

return windData as Required<WindData>;
}

Expand Down Expand Up @@ -295,6 +294,7 @@ export class WindLayer {
* @param {WindData} data - The new wind data to apply.
*/
updateWindData(data: WindData): void {
if (this._isDestroyed) return;
this.windData = this.processWindData(data);
this.particleSystem.computing.updateWindData(this.windData);
this.viewer.scene.requestRender();
Expand All @@ -307,6 +307,7 @@ export class WindLayer {
* @param {Partial<WindLayerOptions>} options - The new options to apply.
*/
updateOptions(options: Partial<WindLayerOptions>): void {
if (this._isDestroyed) return;
this.options = { ...this.options, ...options };
this.particleSystem.changeOptions(options);
this.viewer.scene.requestRender();
Expand Down
14 changes: 8 additions & 6 deletions packages/cesium-wind-layer/src/shaders/calculateSpeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,16 @@ vec2 calculateSpeedByRungeKutta2(vec2 lonLat) {
}
float calculateWindNorm(vec2 speed) {
vec3 percent = vec3(0.0);
vec2 calculateWindNorm(vec2 speed) {
float speedLength = length(speed.xy);
if(speedLength == 0.0){
return 0.0;
return vec2(0.0);
}
return (speedLength - speedRange.x) / (speedRange.y - speedRange.x);
// Clamp speedLength to range
float clampedSpeed = clamp(speedLength, speedRange.x, speedRange.y);
float normalizedSpeed = (clampedSpeed - speedRange.x) / (speedRange.y - speedRange.x);
return vec2(speedLength, normalizedSpeed);
}
out vec4 fragColor;
Expand All @@ -136,7 +138,7 @@ void main() {
vec2 speed = calculateSpeedByRungeKutta2(lonLat);
vec2 speedInLonLat = convertSpeedUnitToLonLat(lonLat, speed);
vec3 particleSpeed = vec3(speedInLonLat, calculateWindNorm(speed / speedScaleFactor));
fragColor = vec4(speedInLonLat, calculateWindNorm(speedOrigin), 0.0);
vec4 particleSpeed = vec4(speedInLonLat, calculateWindNorm(speed / speedScaleFactor));
fragColor = vec4(speedInLonLat, calculateWindNorm(speedOrigin));
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ out vec4 fragColor;
void main() {
vec2 nextParticle = texture(nextParticlesPosition, v_textureCoordinates).rg;
vec3 nextSpeed = texture(particlesSpeed, v_textureCoordinates).rgb;
float speedNorm = nextSpeed.b;
vec4 nextSpeed = texture(particlesSpeed, v_textureCoordinates);
float speedNorm = nextSpeed.a;
float particleDropRate = dropRate + dropRateBump * speedNorm;
vec2 seed1 = nextParticle.xy + v_textureCoordinates;
vec2 seed2 = nextSpeed.xy + v_textureCoordinates;
vec2 seed2 = nextSpeed.rg + v_textureCoordinates;
vec2 randomParticle = generateRandomParticle(seed1);
float randomNumber = rand(seed2, normalRange);
Expand Down
Loading

0 comments on commit e8f6f63

Please sign in to comment.