1
\$\begingroup\$

How can I implement a blizzard/snowstorm effect in a 2D platformer? I have a particle system for snow particles, but I need some kind of windblown texture similar to this as well: How do I create this windblown snow effect?

Could I generate a windblown texture using perlin noise in Photoshop or something and sample it similar to the answer in this question about fog? How to create a 2D fog shader?

In that case it would have to be more dense than the fog texture, so holes don't appear that you can peak through when sampling the texture.

BTW I have a wind speed variable for my snow particles, could that be used for the windblown texture as well somehow?

\$\endgroup\$
4
  • \$\begingroup\$ It sounds like you understand all the core components and techniques you need, you just need some guidance with the execution details. To get into that kind of detail, we'll need to see a visual target for what your final result should look like in 2D (not 3D like the linked question). Do you have some concept art or examples from other 2D media you could show us, so we have a clear idea of what you have in mind? \$\endgroup\$
    – DMGregory
    Oct 9, 2018 at 13:36
  • \$\begingroup\$ That's the problem. I haven't been able to find a perfect example. Maybe this: connorlinning.com/wp-content/uploads/2016/08/gif17.gif but it looks a bit too misty/too much like steam from a hot bath or something, it should look more like snow and it shouldn't just slowly scroll across, but look like it's being blown powerfully with the force of the wind. The way it's done in Skyrim might be a good example: thumbs.gfycat.com/… \$\endgroup\$
    – Martin
    Oct 9, 2018 at 14:37
  • \$\begingroup\$ @DMGregory Hi dear DMGregory I need your help.I like to answer this question and help this user with all my heart but I haven't clue.I can't understand what he want exactly please help me to understand. \$\endgroup\$ Oct 10, 2018 at 17:42
  • \$\begingroup\$ @SeyedMortezaKamali As I've said already: I do not clearly understand what this user needs - that's why I asked for more details. I don't even know whether they're looking for a full-screen effect or something localized to the edges of the ground/platforms. Your best bet is to continue asking the user to clarify their needs, or to wait for another user to come along with an insight that we're both missing. \$\endgroup\$
    – DMGregory
    Oct 10, 2018 at 21:43

2 Answers 2

4
\$\begingroup\$

Making Snow by particle system

as you mentioned in your question you need some noisy windblown. particle system have part that called noise that you can moving your particles based on noise.

enter image description here

2D Snow

you can easily make 2D snow effect by offsetting snowTexture by time.

enter image description here

Shader "Hidden/SimpleSnow"
{
    Properties
    {
        _SnowTexture ("SnowTexture", 2D) = "white" {}
        _OffsetDirection("OffsetDirection",Vector) = (1,2,0,0)
        _NoiseMask("NoiseMask",2D) = "white"{}
        _Speed("Speed",Float) = 2
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _SnowTexture,_NoiseMask;
            float4 _OffsetDirection;
            float _Speed;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 uvnoise : TEXCOORD1;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float2 uvnoise : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                v.uv += _OffsetDirection.xy * _Time.x * _Speed + sin(_Time.x);
                o.uv = v.uv;
                o.uvnoise = v.uvnoise;
                return o;
            }



            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_SnowTexture, i.uv);
                col *= tex2D(_NoiseMask,i.uvnoise);
                return col;
            }
            ENDCG
        }
    }
}

also to making hot bath effect you can make cloud noise and use it:

enter image description here

Shader "Hidden/HotBath"
{
    Properties
    {
        _CloudNoiseMask("CloudNoiseMask",2D) = "white"{}
        _OffsetDirection("OffsetDirection",Vector) = (1,0,0,0)
        _Alpha("Alpha",Range(0,1)) = 0.5
        _Speed("Speed",Float) = 2
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        Blend One One

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _CloudNoiseMask;
            float4 _OffsetDirection;
            float _Speed;
            float _Alpha;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                v.uv += _OffsetDirection.xy * _Time.x * _Speed;
                o.uv = v.uv;
                return o;
            }



            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_CloudNoiseMask, i.uv);
                col = smoothstep(0.05,0.9,col);
                return float4(col.rgb,col.r)*_Alpha;
            }
            ENDCG
        }
    }
}

another way is making snow effect by shader:

enter image description here

 //source: https://www.shadertoy.com/view/ldsGDn
    Shader "Snow"
    {
        Properties
        {
            LAYERS("Layers",Int) = 100
            DEPTH("Depth",Range(0.0,1.0)) = 0.2
            WIDTH("Width",Range(0.0,2.0)) = 0.9 
            SPEED("Speed",Range(0.0,2.0)) = 0.9                  
        }
        Subshader
        {
            Pass
            {
                CGPROGRAM
                #pragma vertex vertex_shader
                #pragma fragment pixel_shader
                #pragma target 3.0

                int LAYERS ;
                float DEPTH,WIDTH,SPEED ;
                static const float3x3 p = float3x3(13.323122,23.5112,21.71123,21.1212,28.7312,11.9312,21.8112,14.7212,61.3934);

                struct custom_type
                {
                    float4 vertex : SV_POSITION;
                    float2 uv : TEXCOORD0;
                };

                custom_type vertex_shader (float4 vertex : POSITION, float2 uv : TEXCOORD0)
                {
                    custom_type vs;
                    vs.vertex = UnityObjectToClipPos (vertex);
                    vs.uv = uv;
                    return vs;
                }

                float4 pixel_shader (custom_type ps) : COLOR
                {
                    float2 uv = ps.uv.xy;
                    float3 acc = float3(0.0,0.0,0.0);
                    float dof = 5.*sin(_Time.g*.1);
                    for (int i=0;i<LAYERS;i++) 
                    {
                        float f = float(i);
                        float2 q = uv*(1.+f*DEPTH);
                        q += float2(q.y*(WIDTH*fmod(f*7.238917,1.)-WIDTH*.5),SPEED*_Time.g/(1.+f*DEPTH*.03));
                        float3 n = float3(floor(q),31.189+f);
                        float3 m = floor(n)*.00001 + frac(n);
                        float3 mp = (31415.9+m)/frac(mul(m,p));
                        float3 r = frac(mp);
                        float2 s = abs(fmod(q,1.)-0.5+0.9*r.xy-0.45);
                        s += 0.01*abs(2.*frac(10.*q.yx)-1.0); 
                        float d = .6*max(s.x-s.y,s.x+s.y)+max(s.x,s.y)-.01;
                        float edge = .005+.05*min(.5*abs(f-5.-dof),1.);
                        float t = smoothstep(edge,-edge,d)*(r.x/(1.+.02*f*DEPTH));
                        acc += float3(t,t,t);
                    }
                    return float4(float3(acc),1.0);     
                }
                ENDCG
            }
        }
    }

Generating Perlin noise by shader :

You can use noise to make a procedural shape:

capture

Here's a Fractal Brownian Motion (FBM) tutorial.

Shader "Smkgames/FbmNoise"
{
Properties
{
_TileAndOffset("Tile and Offset",Vector) = (1,1,0,0)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};


float4 _TileAndOffset;
float _Step,_Min,_Ma;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv*_TileAndOffset.xy+_TileAndOffset.zw;
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}

// Author @patriciogv - 2015
// http://patriciogonzalezvivo.com

float random (in float2 st) {
return frac(sin(dot(st.xy,
                    float2(12.9898,78.233)))*
    43758.5453123);
}

// Based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float noise (in float2 st) {
float2 i = floor(st);
float2 f = frac(st);

// Four corners in 2D of a tile
float a = random(i);
float b = random(i + float2(1.0, 0.0));
float c = random(i + float2(0.0, 1.0));
float d = random(i + float2(1.0, 1.0));

float2 u = f * f * (3.0 - 2.0 * f);

return lerp(a, b, u.x) +
        (c - a)* u.y * (1.0 - u.x) +
        (d - b) * u.x * u.y;
}

#define OCTAVES 6
float fbm (in float2 st) {
// Initial values
float value = 0.0;
float amplitude = .5;
float frequency = 0.;
//
// Loop of octaves
for (int i = 0; i < OCTAVES; i++) {
    value += amplitude * noise(st);
    st *= 2.;
    amplitude *= .5;
}
return value;
}

        fixed4 frag (v2f i) : SV_Target
        {


float2 st =i.uv;

float3 color = float3(0,0,0);
color += fbm(st*3.0);
return float4(color,1.0);

        }
ENDCG
}
}
}

The FBM above shouldn't be used directly in to your shader because it has many GPU calculations and decreases performance. Instead of using directly, you can render the result to a texture with RenderTexture.

Shadertoy uses multiple passes, one per "buffer". As the name indicates, this pass stores the results in a buffer, which is just a texture. Unity will let you render to textures too.

2018-01-26_10-18-20

also this tutorial will learn you how to generate perlin noise.

\$\endgroup\$
9
  • \$\begingroup\$ Thank you, but I already have a snow particle system, I just need the windblown snow texture. And I DON'T want it to be misty like a hot bath and it SHOULDN'T just scroll slowly past, that was my critique of the gif I linked in my previous comment. \$\endgroup\$
    – Martin
    Oct 10, 2018 at 6:06
  • \$\begingroup\$ To the person who upvoted this: This answer may have helped you personally by chance and it is detailed and well written, but he didn't read my question properly (almost read it opposite) and it doesn't answer any question I have posed. There are dozens of articles and questions about creating a simple snow effect or creating mist with Perlin Noise. \$\endgroup\$
    – Martin
    Oct 10, 2018 at 6:51
  • \$\begingroup\$ @Martin oh sorry I read the question quickly so I thought you wanted something like that animated gif, I will update my answer \$\endgroup\$ Oct 10, 2018 at 11:02
  • \$\begingroup\$ Thanks, but I'm using my own simple particle system and I'm not asking how to move them randomly or based on noise. What I need is a way to generate a texture using perlin noise that looks like a veil of millions of teeny tiny snow particles (like in a snowstorm). Then from a shader, sample it or offset it using a time variable (I'm unsure of how to do this with the effect I'm trying to achieve instead of something like fog) by a certain wind speed, so achieving a windblown snow effect that is hard to see through. The texture is generated using Python or something, not during runtime. \$\endgroup\$
    – Martin
    Oct 10, 2018 at 11:39
  • \$\begingroup\$ TLDR: My question does not concern particles, I need a way to generate a "snowstorm veil" texture using perlin noise using an external script and then in the game have a shader sample the texture to create the windblown effect. \$\endgroup\$
    – Martin
    Oct 10, 2018 at 11:44
1
\$\begingroup\$

I figured it out. You can create a blizzard/snowstorm effect using different windblown particles like here: https://www.unrealengine.com/marketplace/supergenius-weather-fx, this is used for pretty much all 3D games, but it requires a fancy particle system. The following is a simpler, cheaper method for 2D: https://assetstore.unity.com/packages/vfx/shaders/fullscreen-camera-effects/simple-2d-fog-storm-smoke-115617

example video

You can use this system both for a blizzard, fog, sandstorm, etc. effect by tuning the different shader parameters. The only asset you're interested in from this package is the shader "D2FogsNoiseTex.shader" it's in GLSL, but can be translated to any other shader language and used in any engine or framework. It takes a noise texture and applies the Perlin Noise algorithm to it using the shader parameters and scrolls it at a certain velocity.

To make it look like a blizzard the most important things are tinting it white and setting horizontal and vertical speed quite high. Make it be affected by wind direction and speed: Set horizontal and vertical speed to your normalized wind direction multiplied by wind speed. Size should be small and the density should be high.

Finally, add your own snow particles and make them be affected by the wind direction and speed as well. This will give a pretty convincing blizzard effect IMO.

Optional: Generate a texture with Perlin Noise

If you're unsatisfied with the look of the final texture being rendered on screen, you could use an external script with Python for example and generate a more specialized blizzard noise texture and edit the shader, so it doesn't apply the Perlin Algorithm, or simply edit the shader to give a different output from the noise texture.

Result (without snow particles):

Video

Settings

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .