waving flag shader: feedback please!

hi, i’ve just written my first shader, it’s for displaying a waving flag. here’s the code:

if someone with more experience could check my code and has any suggestions on how to improve it, i’d be very grateful

Shader "Selfmade/FlagWave" 
{

Properties 
{
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTex ("Texture", 2D) = "white" { }
}

SubShader 
{
    Pass
    {
    	CULL Off
    	
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "UnityCG.cginc"
		#include "AutoLight.cginc"
		
		float4 _Color;
		sampler2D _MainTex;
		
		//float4 _Time;
		
		// vertex input: position, normal
		struct appdata {
		    float4 vertex : POSITION;
		    float4 texcoord : TEXCOORD0;
		};
		
		struct v2f {
		    float4 pos : POSITION;
		    float2 uv: TEXCOORD0;
		};
		
		v2f vert (appdata v) {
		    v2f o;
		   
			float angle= _Time * 50;
			
			v.vertex.y =  v.texcoord.x * sin(v.vertex.x + angle);
			v.vertex.y += sin(v.vertex.z / 2 + angle);
			v.vertex.y *= v.vertex.x * 0.1f;
		    
		    o.pos = mul( glstate.matrix.mvp, v.vertex );
		    o.uv = v.texcoord;
			return o;
		}
		
		float4 frag (v2f i) : COLOR
		{
			half4 color = tex2D(_MainTex, i.uv);
			return color;
		}

		ENDCG
		

		//SetTexture [_MainTex] {combine texture}
    }
}
Fallback "VertexLit"
}

thx

Hello cboe,

it is quite nice. As improvement I would make 1 edge of the flag fixed as in reality.

Was any progress made on this? I would be a useful shader if it was pinned at the side the flag was attached to the pole.

EDIT: ok, this shader doesn’t work or do anything. I know it was written a long time ago, but has anyone got any ideas as to whats wrong with it in Unity 2.6.1 ?

Cheers :slight_smile:

Hello Seon,

This sort of shader is used in often in vertex shader 101 tutorials. You can probably find numerous example shaders, maybe even pinned to one side as you want, searching about with google.

In fact I think the first time I saw one was on NeHe’s famous OpenGL tutorial site. I remember it giving good insight in to how it works.

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=11

There’s nothing wrong with it…works fine as-is.

–Eric

Hmm, i have it applied to a mesh and its not doing anything :frowning:

I must be missing something very obvious!

I have a flag mesh, i have created a material for it called flag, have selected the FlagWave shader for it, and have added a texture to the texture slot.

I see NO movement and I see no flag, other than when I select the object, i see the wireframe of the mesh.

Does your mesh have a reasonable number of vertices so the effect has something to work with? And you pressed Play? Also, one end of the flag can be pinned if you create the mesh the right way, such as using this.

–Eric

yes, i think its enough. here is an example image.

and here is a screenie of my editor panel

Ok, I got it working just using that pane creation script, but the same settings on my flag mesh don’t do anything… oh well!

Thanks for your help Eric!

The mesh is oriented wrong…the shader is animating the vertex.y coordinates. You can rotate the mesh vertical, but it has to be created as a horizontal plane.

–Eric

Yeah, I finally worked that out myself. Figures! My Trig is shite! So didnt really glance in that area of the shader to see it was trying to displace the wrong axis.

So, now that I have established that my trig is shite… I want to get the flag displacing on the z axis too (and maybe even the x) to give it 3 axis movement.

Anyone wanna give the math a try? my attempts so far are moving the z correctly, but squishing the flag on the z too…

v.vertex.z =  v.texcoord.x * cos(v.vertex.x + angle); // this is where I am going wrong I think....
v.vertex.z += cos(v.vertex.x / 2 + angle); 
v.vertex.z *= v.vertex.x * 0.1f; // ok, this is scaling movement down closer to U = 0

Suggestions?

Can you just clarify exactly what you are doing here? Are you aiming to get a single ripple (from the cosine shape) that runs from the top of the flag to the bottom?

Well yes, though wether its Cos or Sin, I have no idea!

I was to extend the maths in the original shader to add an extra ripple from V0 - V1 that is also stronger at U1 and muted at U0.

I have found some different math code (online) that ripples really well and has adjustments for ripples on 3 axis, but again it produces the same results on all axis other than y.

	  float sinOff=v.vertex.x+v.vertex.y+v.vertex.z;
	  float t=-_Time*50;
	  float sin1=sin(t*1.45+sinOff);
	  float sin2=sin(t*3.12+sinOff);
	  float sin3=sin(t*2.2+sinOff);
	  float fx=v.texcoord.x;
	  float fy=v.texcoord.x*v.texcoord.y;

	  //v.vertex.x=sin1*fx*0.5;
	  v.vertex.y=sin2*fx*0.5-fy*0.9;
	  v.vertex.z=-sin3*fx*0.5;

Produces this result:-

Now commenting out this line puts it back to single y axis ripple that works fine.

//v.vertex.z=-sin3*fx*0.5;

Produces this result:-

My parents used to tell me in school that I needed to pay attention in Maths classes and I used to argue, what’s the point, like I am ever going to use this stuff in the real world! Sheesh… life is full of regrets hey !

You shouldn’t set vertex.y at any point - this is what is squashing the flag. If you want a two-dimensional ripple, add the two sin values together and assign them to vertex.z:-

 v.vertex.z = sin3*fx*0.5 + sin2*fx*0.5;

…or something along those lines.

Hey Andeee, it’s Y I need in this case because of how the mesh is created (as a flat X*Z plane).

Ok, I have it working now, I was replacing X Z values rather that adding to them. That didn’t work, this does!

Quicktime movie of flag blowing - sector3.com.au

Here is a new shader that animates flag on all axis, and works a treat!

// Original shader by cboe - Mar, 23, 2009
// Enhanced to 3 axis movement by Seon - Jan, 21, 2010
//
// Requirements: assumes you are using a subdivided plane created with X (width) * Z (height) where Y is flat.
// Requirements: assumes UV as: left X (U0) is attatched to pole, and Top Z (V1) is at top of pole.  
//
// Enjoy!

Shader "Selfmade/FlagWave" 
{ 

Properties 
{ 
    _Color ("Main Color", Color) = (1,1,1,1) 
    _MainTex ("Texture", 2D) = "white" { } 
} 

SubShader 
{ 
    Pass 
    { 
       CULL Off 
        
      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 
      #include "UnityCG.cginc" 
      #include "AutoLight.cginc" 
       
      float4 _Color; 
      sampler2D _MainTex; 

      // vertex input: position, normal 
      struct appdata { 
          float4 vertex : POSITION; 
          float4 texcoord : TEXCOORD0; 
      }; 
       
      struct v2f { 
          float4 pos : POSITION; 
          float2 uv: TEXCOORD0; 
      }; 
       
      v2f vert (appdata v) { 
          v2f o; 

		  float sinOff=v.vertex.x+v.vertex.y+v.vertex.z;
		  float t=-_Time*50;
		  float fx=v.texcoord.x;
		  float fy=v.texcoord.x*v.texcoord.y;

		  v.vertex.x+=sin(t*1.45+sinOff)*fx*0.5;
		  v.vertex.y=sin(t*3.12+sinOff)*fx*0.5-fy*0.9;
		  v.vertex.z-=sin(t*2.2+sinOff)*fx*0.2;
	
          o.pos = mul( glstate.matrix.mvp, v.vertex ); 
          o.uv = v.texcoord; 

         return o; 
      } 
       
      float4 frag (v2f i) : COLOR 
      { 
         half4 color = tex2D(_MainTex, i.uv); 
         return color; 
      }

      ENDCG 

      SetTexture [_MainTex] {combine texture} 
    } 
} 
	Fallback "VertexLit" 
}

I’ve used this shader in my Virtual Egyptian Temple (http://www.medievalist.net/unityworlds/egyptiantemple.htm). I’ve been searching for a way to make the flags wave for ages, so I was very glad to find this shader here. Ideally, I’d like to have each of the four flags be a little out-of-synch with the others. If anyone can advise me how I might do that, I’d appreciate it (I am new to Unity). Thanks again.

I made the small addition of a WaveSpeed variable, so you can make different materials which have slightly different speeds:

// Original shader by cboe - Mar, 23, 2009 
// Enhanced to 3 axis movement by Seon - Jan, 21, 2010
// Added _WaveSpeed - Jan, 26, 2010 
// 
// Requirements: assumes you are using a subdivided plane created with X (width) * Z (height) where Y is flat. 
// Requirements: assumes UV as: left X (U0) is attatched to pole, and Top Z (V1) is at top of pole.  
// 
// Enjoy! 

Shader "Selfmade/FlagWave" 
{ 

Properties 
{ 
    _Color ("Main Color", Color) = (1,1,1,1) 
    _MainTex ("Texture", 2D) = "white" { }
    _WaveSpeed ("Wave Speed", Range(0.0, 150.0)) = 50.0 
} 

SubShader 
{ 
    Pass 
    { 
       CULL Off 
        
      CGPROGRAM 
      #pragma vertex vert 
      #pragma fragment frag 
      #include "UnityCG.cginc" 
      #include "AutoLight.cginc" 
        
      float4 _Color; 
      sampler2D _MainTex;
      float _WaveSpeed;

      // vertex input: position, normal 
      struct appdata { 
          float4 vertex : POSITION; 
          float4 texcoord : TEXCOORD0; 
      }; 
        
      struct v2f { 
          float4 pos : POSITION; 
          float2 uv: TEXCOORD0; 
      }; 
        
      v2f vert (appdata v) { 
          v2f o; 

        float sinOff=v.vertex.x+v.vertex.y+v.vertex.z; 
        float t=-_Time*_WaveSpeed; 
        float fx=v.texcoord.x; 
        float fy=v.texcoord.x*v.texcoord.y; 

        v.vertex.x+=sin(t*1.45+sinOff)*fx*0.5; 
        v.vertex.y=sin(t*3.12+sinOff)*fx*0.5-fy*0.9; 
        v.vertex.z-=sin(t*2.2+sinOff)*fx*0.2; 
    
          o.pos = mul( glstate.matrix.mvp, v.vertex ); 
          o.uv = v.texcoord; 

         return o; 
      } 
        
      float4 frag (v2f i) : COLOR 
      { 
         half4 color = tex2D(_MainTex, i.uv); 
         return color; 
      } 

      ENDCG 

      SetTexture [_MainTex] {combine texture} 
    } 
} 
   Fallback "VertexLit" 
}

–Eric

Thanks for that update Eric. It’s just what I was hoping for. Unfortunately, it is not working perfectly for me. Here’s what happens:

  • I change the material of one of the flags and change the speed of its waving. That works. I end up with one of my four flags waving at a different rate from the others, both in the editor and in the web player.
  • I change the material on another flag and change the speed of its waving. That works when I play the scene in the editor. I see two of the flags waving at different rates from each other and from the original setting (so, three different rates of flag waving). However, I only see this when playing the scene in the editor. If I build the scene to view it in the web player, the last flag I set does not wave independently. Its rate is identical to the rate of the first flag I changed. In other words, there are only two rates of flag waving (the original rate, and the first one I changed). When I return from the web player to the editor, I find that the level I set for the last flag has changed to be equal to the setting for the first flag I changed. Hope that makes sense.
    Perhaps I’m doing something wrong, or maybe there’s a bug somewhere.

The wave speed is part of the material, so you need a different material for each flag that should have a different speed. If you change the speed in one material, it changes for every object using that material.

–Eric

My previous message must not have been clear. I HAVE assigned three different materials, and set three different wave speeds. What I’m saying is that the third wave speed, though it starts out different, re-sets to match the speed I assigned to one of the other materials. I end up with two of my materials having exactly the same wave speed, though I had originally set them at different speeds. This happens after I build the web-player version. Do you not get this odd result? I’ve tried it over and over again and the result is always the same for me.