Skip to content

Commit c0020ed

Browse files
author
RSamaium
committed
feat: add fog effects to Weather component with shader optimizations
- Enhanced the Weather component to support fog effects alongside existing rain and snow options, including customizable parameters for density, speed, and height. - Introduced a new fog shader with optimizations for performance and realism, including dynamic height concentration and improved visual quality. - Updated documentation to include detailed guidelines for fog parameters and examples for various fog scenarios. - Refactored existing rain and snow shaders for better performance and consistency across weather effects. - Modified sample application to demonstrate the new fog effect in a canvas environment.
1 parent 6f09b46 commit c0020ed

File tree

6 files changed

+543
-98
lines changed

6 files changed

+543
-98
lines changed

docs/presets/weather.md

Lines changed: 136 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
## Overview
66

7-
The Weather component creates realistic weather effects using WebGL shaders. It supports multiple weather types including rain and snow, with customizable parameters for wind influence, density, and speed control. The effects are inspired by Zelda-style weather systems and provide beautiful, performant weather overlays for your games.
7+
The Weather component creates realistic weather effects using WebGL shaders. It supports multiple weather types including rain, snow, and fog, with customizable parameters for wind influence, density, and speed control. The effects are inspired by Zelda-style weather systems and provide beautiful, performant weather overlays for your games.
88

99
## Features
1010

11-
- **Multiple Weather Effects**: Support for rain and snow with different visual characteristics
11+
- **Multiple Weather Effects**: Support for rain, snow, and fog with different visual characteristics
1212
- **Procedural Generation**: Weather particles are generated using hash functions for natural randomness
1313
- **Wind Simulation**: Particles are affected by wind direction and strength as they fall
1414
- **Density Control**: Adjust the number of visible particles from light to heavy weather
@@ -27,6 +27,9 @@ The Weather component creates realistic weather effects using WebGL shaders. It
2727

2828
<!-- Basic snow with default settings -->
2929
<Weather effect="snow" />
30+
31+
<!-- Basic fog with default settings -->
32+
<Weather effect="fog" />
3033
</Canvas>
3134

3235
<script>
@@ -52,6 +55,9 @@ The Weather component creates realistic weather effects using WebGL shaders. It
5255
windStrength={0.6}
5356
density={300}
5457
/>
58+
59+
<!-- Misty fog for atmospheric scenes -->
60+
<Weather effect="fog" speed={0.03} density={0.8} height={0.2} />
5561
</Canvas>
5662
```
5763

@@ -96,6 +102,24 @@ You can configure weather effects with static values for consistent behavior:
96102
density={60}
97103
windStrength={0.2}
98104
/>
105+
106+
<!-- Misty valley fog -->
107+
<Weather
108+
effect="fog"
109+
speed={0.03}
110+
windDirection={0.5}
111+
density={0.8}
112+
height={0.2}
113+
/>
114+
115+
<!-- Thick ground fog -->
116+
<Weather
117+
effect="fog"
118+
speed={0.02}
119+
windDirection={0.3}
120+
density={1.2}
121+
height={0.0}
122+
/>
99123
</Canvas>
100124
```
101125

@@ -117,11 +141,15 @@ You can configure weather effects with static values for consistent behavior:
117141
- 0.4-0.6 = Moderate wind
118142
- 0.7-1.0 = Strong wind/storm
119143

120-
**Density**: Number of visible particles
121-
- 50-100 = Light weather (sparse)
122-
- 100-200 = Normal weather
123-
- 200-300 = Heavy weather
124-
- 300-400 = Extreme weather (may impact performance)
144+
**Density**: Number of visible particles (or fog intensity for fog effect)
145+
- Rain/Snow: 50-100 = Light weather (sparse), 100-200 = Normal weather, 200-300 = Heavy weather, 300-400 = Extreme weather
146+
- Fog: 0.3-0.6 = Light mist, 0.6-1.0 = Moderate fog, 1.0-1.5 = Thick fog, 1.5-2.0 = Dense fog
147+
148+
**Height** (Fog only): Controls where fog concentrates vertically
149+
- 0.0 = Ground-level fog (concentrates at bottom)
150+
- 0.2-0.4 = Low-lying fog
151+
- 0.5 = Mid-height fog
152+
- 0.6-1.0 = High fog (distributed more evenly)
125153

126154
### Dynamic Control with Signals
127155

@@ -183,6 +211,22 @@ Use signals to create interactive weather systems that respond to game events or
183211
weatherDensity.set(80)
184212
}
185213
214+
// Control fog dynamically
215+
function startFog() {
216+
currentEffect.set('fog')
217+
weatherSpeed.set(0.03)
218+
windDirection.set(0.5)
219+
weatherDensity.set(0.8)
220+
}
221+
222+
function thickGroundFog() {
223+
currentEffect.set('fog')
224+
weatherSpeed.set(0.02)
225+
windDirection.set(0.3)
226+
weatherDensity.set(1.5)
227+
// height would be set via a separate signal if needed
228+
}
229+
186230
// Example: Change weather based on game state
187231
function onEnterWinterArea() {
188232
currentEffect.set('snow')
@@ -230,16 +274,23 @@ function enterStormZone() {
230274
<Weather effect="rain" speed={0.6} density={100} />
231275
```
232276

277+
**Atmospheric Fog**: Use fog for mysterious or moody scenes
278+
```html
279+
<!-- Valley mist for mysterious atmosphere -->
280+
<Weather effect="fog" speed={0.03} density={0.8} height={0.1} />
281+
```
282+
233283
## Props
234284

235285
| Prop | Type | Required | Default | Description |
236286
|------|------|----------|---------|-------------|
237-
| effect | `string` | No | 'rain' | Weather effect type: `'rain'` or `'snow'` |
238-
| speed | `number` \| `Signal<number>` | No | 0.5 | Falling speed multiplier (0.1 = slow, 2.0 = fast) |
287+
| effect | `string` | No | 'rain' | Weather effect type: `'rain'`, `'snow'`, or `'fog'` |
288+
| speed | `number` \| `Signal<number>` | No | 0.5 | Falling/movement speed multiplier (0.1 = slow, 2.0 = fast). For fog, use lower values (0.01-0.05) |
239289
| windDirection | `number` \| `Signal<number>` | No | 0.0 | Wind direction (-1.0 = left, 0.0 = none, 1.0 = right) |
240-
| windStrength | `number` \| `Signal<number>` | No | 0.2 | Wind strength (0.0 = no wind, 1.0 = maximum) |
241-
| density | `number` \| `Signal<number>` | No | 180.0 | Particle density (50-400, affects visible particle count) |
242-
| maxDrops | `number` \| `Signal<number>` | No | 60.0 | Maximum number of particles (30-150 for snow, 10-200 for rain) |
290+
| windStrength | `number` \| `Signal<number>` | No | 0.2 | Wind strength (0.0 = no wind, 1.0 = maximum). Not used for fog |
291+
| density | `number` \| `Signal<number>` | No | 180.0 | Particle density for rain/snow (50-400) or fog intensity (0.3-2.0) |
292+
| maxDrops | `number` \| `Signal<number>` | No | 60.0 | Maximum number of particles (30-150 for snow, 10-200 for rain). Not used for fog |
293+
| height | `number` \| `Signal<number>` | No | 0.2 | Fog height parameter (0.0 = bottom/concentrated, 1.0 = top/distributed). Only used for fog |
243294
| resolution | `Array<number>` \| `Signal<Array<number>>` | No | [1000, 1000] | Screen resolution `[width, height]` for proper scaling |
244295

245296
### Prop Examples
@@ -256,7 +307,7 @@ function enterStormZone() {
256307
density={densitySignal}
257308
/>
258309

259-
<!-- Full configuration -->
310+
<!-- Full configuration for rain -->
260311
<Weather
261312
effect="rain"
262313
speed={1.2}
@@ -266,15 +317,31 @@ function enterStormZone() {
266317
maxDrops={80}
267318
resolution={[1920, 1080]}
268319
/>
320+
321+
<!-- Full configuration for fog -->
322+
<Weather
323+
effect="fog"
324+
speed={0.03}
325+
windDirection={0.5}
326+
density={0.8}
327+
height={0.2}
328+
resolution={[1920, 1080]}
329+
/>
269330
```
270331

271332
## Parameter Guidelines
272333

273334
### Speed
274-
- **0.1 - 0.3**: Light precipitation (gentle rain or snow)
275-
- **0.4 - 0.7**: Normal weather
276-
- **0.8 - 1.2**: Heavy weather
277-
- **1.3 - 2.0**: Extreme weather (storm or blizzard)
335+
- **Rain/Snow:**
336+
- **0.1 - 0.3**: Light precipitation (gentle rain or snow)
337+
- **0.4 - 0.7**: Normal weather
338+
- **0.8 - 1.2**: Heavy weather
339+
- **1.3 - 2.0**: Extreme weather (storm or blizzard)
340+
- **Fog:**
341+
- **0.01 - 0.02**: Very slow, almost static mist
342+
- **0.02 - 0.04**: Slow, gentle movement
343+
- **0.04 - 0.06**: Moderate fog movement
344+
- **0.06 - 0.1**: Fast-moving fog/mist
278345

279346
### Wind Direction
280347
- **-1.0**: Strong wind from right to left
@@ -290,10 +357,22 @@ function enterStormZone() {
290357
- **0.7 - 1.0**: Strong wind/storm
291358

292359
### Density
293-
- **50 - 100**: Light weather, sparse particles
294-
- **100 - 200**: Normal weather
295-
- **200 - 300**: Heavy weather
296-
- **300 - 400**: Extreme weather (downpour or heavy snow)
360+
- **Rain/Snow:**
361+
- **50 - 100**: Light weather, sparse particles
362+
- **100 - 200**: Normal weather
363+
- **200 - 300**: Heavy weather
364+
- **300 - 400**: Extreme weather (downpour or heavy snow)
365+
- **Fog:**
366+
- **0.3 - 0.6**: Light mist, subtle atmosphere
367+
- **0.6 - 1.0**: Moderate fog, visible mist
368+
- **1.0 - 1.5**: Thick fog, limited visibility
369+
- **1.5 - 2.0**: Dense fog, very limited visibility
370+
371+
### Height (Fog only)
372+
- **0.0 - 0.2**: Ground-level fog (valley effect, concentrates at bottom)
373+
- **0.2 - 0.4**: Low-lying fog
374+
- **0.4 - 0.6**: Mid-height fog
375+
- **0.6 - 1.0**: High fog (distributed more evenly across screen)
297376

298377
## Performance Notes
299378

@@ -358,12 +437,35 @@ Here are pre-configured weather scenarios you can use directly or as starting po
358437
<Weather effect="snow" speed={1.6} windDirection={0.3} windStrength={0.5} density={350} />
359438
```
360439

440+
### Fog Presets
441+
442+
```html
443+
<!-- Light Valley Mist - Subtle, atmospheric -->
444+
<Weather effect="fog" speed={0.02} windDirection={0.3} density={0.5} height={0.1} />
445+
446+
<!-- Ground Fog - Low-lying, concentrated at bottom -->
447+
<Weather effect="fog" speed={0.03} windDirection={0.5} density={0.8} height={0.0} />
448+
449+
<!-- Thick Mist - Moderate visibility reduction -->
450+
<Weather effect="fog" speed={0.04} windDirection={0.4} density={1.0} height={0.2} />
451+
452+
<!-- Dense Fog - Heavy visibility reduction -->
453+
<Weather effect="fog" speed={0.03} windDirection={0.6} density={1.5} height={0.3} />
454+
455+
<!-- High Altitude Fog - Distributed evenly -->
456+
<Weather effect="fog" speed={0.02} windDirection={0.2} density={0.7} height={0.7} />
457+
458+
<!-- Moving Mist - Faster movement -->
459+
<Weather effect="fog" speed={0.06} windDirection={0.8} density={0.9} height={0.2} />
460+
```
461+
361462
### Tips for Choosing Presets
362463

363-
- **Atmospheric Background**: Use light presets (density 60-100) for subtle ambiance
364-
- **Gameplay Events**: Use medium presets (density 150-250) for weather-related gameplay
365-
- **Dramatic Moments**: Use heavy presets (density 280-380) for cutscenes or intense moments
366-
- **Performance**: Lower density (60-120) for mobile devices or when many effects are active
464+
- **Atmospheric Background**: Use light presets (density 60-100 for rain/snow, 0.3-0.6 for fog) for subtle ambiance
465+
- **Gameplay Events**: Use medium presets (density 150-250 for rain/snow, 0.7-1.0 for fog) for weather-related gameplay
466+
- **Dramatic Moments**: Use heavy presets (density 280-380 for rain/snow, 1.2-1.5 for fog) for cutscenes or intense moments
467+
- **Performance**: Lower density (60-120 for rain/snow, 0.3-0.6 for fog) for mobile devices or when many effects are active
468+
- **Fog Specific**: Use ground fog (height 0.0-0.2) for valley/mountain scenes, high fog (height 0.6-1.0) for atmospheric backgrounds
367469

368470
## Technical Details
369471

@@ -383,4 +485,12 @@ The Weather component uses specialized fragment shaders for each effect:
383485
4. **Optimizes rendering** using efficient GPU calculations
384486
5. **Supports real-time updates** through uniform buffer updates
385487

386-
Both shaders render approximately 150-200 potential particles per frame, with the actual visible count controlled by the density parameter.
488+
### Fog Shader
489+
1. **Generates organic fog layers** using fractal noise (FBM) for natural cloud-like shapes
490+
2. **Creates multiple fog layers** with depth perception and overlapping patterns
491+
3. **Simulates natural movement** with wind direction and vertical wave oscillations
492+
4. **Applies height-based concentration** for valley effect (fog gathers at bottom)
493+
5. **Optimizes rendering** using efficient GPU calculations with multiple layered passes
494+
6. **Supports real-time updates** through uniform buffer updates
495+
496+
Both rain and snow shaders render approximately 150-200 potential particles per frame, with the actual visible count controlled by the density parameter. The fog shader uses 4 overlapping layers with fractal noise generation for organic, realistic fog patterns.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { GlProgram } from "pixi.js";
2+
3+
export function createFogShader(): GlProgram {
4+
5+
const vertexSrc = /* glsl */`
6+
precision mediump float;
7+
attribute vec2 aPosition;
8+
attribute vec2 aUV;
9+
varying vec2 vUV;
10+
void main() {
11+
vUV = aUV;
12+
gl_Position = vec4(aPosition, 0.0, 1.0);
13+
}
14+
`;
15+
16+
const fragmentSrc = /* glsl */`
17+
precision mediump float;
18+
varying vec2 vUV;
19+
20+
uniform float uTime;
21+
uniform vec2 uResolution;
22+
23+
uniform float uSpeed; // movement
24+
uniform float uScale; // detail scale
25+
uniform float uDensity; // opacity
26+
27+
// ------------------- noise -----------------------------------
28+
29+
float hash(vec2 p) {
30+
return fract(sin(dot(p, vec2(127.1,311.7))) * 43758.5453);
31+
}
32+
33+
float noise(vec2 p) {
34+
vec2 i = floor(p);
35+
vec2 f = fract(p);
36+
vec2 u = f*f*(3.0 - 2.0*f);
37+
return mix(
38+
mix(hash(i + vec2(0.,0.)), hash(i + vec2(1.,0.)), u.x),
39+
mix(hash(i + vec2(0.,1.)), hash(i + vec2(1.,1.)), u.x),
40+
u.y
41+
);
42+
}
43+
44+
float fbm(vec2 p){
45+
float v = 0.0;
46+
float a = 0.5;
47+
for(int i = 0; i < 5; i++){
48+
v += a * noise(p);
49+
p *= 2.0;
50+
a *= 0.5;
51+
}
52+
return v;
53+
}
54+
55+
// --------------------------------------------------------------
56+
57+
void main() {
58+
59+
vec2 uv = gl_FragCoord.xy / uResolution.xy;
60+
61+
float fog = 0.0;
62+
63+
// -------- multi-layer fog ----------------------
64+
65+
for(int i = 0; i < 3; i++){
66+
float layer = float(i);
67+
68+
vec2 p = uv;
69+
70+
float scale = uScale * (1.0 + layer * 0.6);
71+
float t = uTime * uSpeed * (0.3 + layer * 0.4);
72+
73+
// drift
74+
p.x += t * 0.2;
75+
p.y += sin(t + p.x * 2.0) * 0.03;
76+
77+
// extra wave motion
78+
p.x += cos(p.y * 2.5 + t) * 0.03;
79+
80+
fog += fbm(p * scale) * (1.0 - layer * 0.25);
81+
}
82+
83+
// normalize & threshold
84+
fog = smoothstep(0.25, 0.8, fog);
85+
86+
// -------------- vertical fade (optional) -----------------
87+
88+
float height = uv.y;
89+
fog *= (1.0 - height * 0.3);
90+
91+
// -------------- density handling -------------------------
92+
93+
float density = clamp(uDensity, 0.0, 1.0);
94+
95+
// alpha based on fog intensity (soft)
96+
float alpha = fog * density * 0.8;
97+
98+
// -------------- fog color -----------------------
99+
100+
vec3 baseColor = vec3(0.92, 0.94, 0.96);
101+
102+
// slight variation
103+
float v = fbm(uv * 2.0 + uTime * 0.1) * 0.05;
104+
105+
vec3 color = baseColor + v;
106+
107+
// modulate brightness by fog value: bright in high density
108+
color *= (0.6 + fog * 0.4);
109+
110+
// ---------- result ---------------------------------
111+
112+
gl_FragColor = vec4(color, alpha);
113+
}
114+
`;
115+
116+
return new GlProgram({
117+
vertex: vertexSrc,
118+
fragment: fragmentSrc
119+
});
120+
}

0 commit comments

Comments
 (0)