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 Code (csharp): 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
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
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
Hmm, i have it applied to a mesh and its not doing anything 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
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 S***e! 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 S***e... 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... Code (csharp): 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. Code (csharp): 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. Code (csharp): //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:- Code (csharp): 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 - http://games.sector3.com.au/examples/flag_blowing.mov.zip Here is a new shader that animates flag on all axis, and works a treat! Code (csharp): // 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: Code (csharp): // 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.
I'll try some different things at my end, and test it on a different machine. In any case, I'm pretty satisfied with having the flags wave at two different speeds. That's an improvement over having them all in synch. So thanks again for the update.
This shader seems to work great, but it doesn't recalculate the normals. I've tried to do a few things, but I don't know enough about Unity's shader system to write anything. I spent quite a bit of time getting it to work but couldn't. Any chance anyone would want to help me with that?
Following Eric5h5 implementation I did a little ajustment in time value function because flag animation looks bouncy. I changed the slider WaveLength value to a float WaveLength number value. Enjoy! Code (csharp): // Original shader by cboe - Mar, 23, 2009 // Enhanced to 3 axis movement by Seon - Jan, 21, 2010 // Added _WaveSpeed - Jan, 26, 2010 Eric5h5 // Ajustement time function - April, 19, 2010 Fontmaster // // 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 "FX/FlagWave" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" { } _WaveSpeed ("Wave Speed", float) = 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; if(t < 0.0) t *= -1.0; 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" }
Is it possible for this shader to accept lighting info? Or at least be able to adjust the brightness with the color option?
Using the latest shader posted above, on one side of the flag mesh I see the flat plane that the flag is based on. The other side looks like a normal waving flag, however.
Bump, in reference to my previous post, does anyone know how to fix this? Currently on the latest widely available Unity 3 build.
Great Work! I have only a question... How can I modify this shader to render the flag movement on a transparent Texture?
I have the same question as Michele. The programmer on my team made the following adjustment: Code (csharp): // Upgrade NOTE: replaced 'glstate.matrix.mvp' with 'UNITY_MATRIX_MVP' // Original shader by cboe - Mar, 23, 2009 // Enhanced to 3 axis movement by Seon - Jan, 21, 2010 // Added _WaveSpeed - Jan, 26, 2010 Eric5h5 // Ajustement time function - April, 19, 2010 Fontmaster // // 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 "FX/FlagWave" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" { } _WaveSpeed ("Wave Speed", float) = 50.0 } SubShader { Pass { [B]Blend SrcAlpha OneMinusSrcAlpha[/B] //<---- New Line of Code CULL Off Program "vp" { // Vertex combos: 1 // opengl - ALU: 71 to 71 // d3d9 - ALU: 66 to 66 SubProgram "opengl " { Keywords { } Bind "vertex" Vertex Bind "texcoord" TexCoord0 Vector 5 [_Time] Float 6 [_WaveSpeed] "!!ARBvp1.0 # 71 ALU PARAM c[13] = { { 24.980801, -24.980801, 0.15915491, 0 }, state.matrix.mvp, program.local[5..6], { 0, 0.5, 1, 3.1199999 }, { 0.25, -60.145809, 60.145809, 0.89999998 }, { 85.453789, -85.453789, -64.939346, 64.939346 }, { 19.73921, -19.73921, -1, 1 }, { -9, 0.75, 1.45, 2.2 }, { 0.2 } }; TEMP R0; TEMP R1; TEMP R2; TEMP R3; TEMP R4; ADD R0.y, vertex.position.x, vertex.position; MOV R0.x, c[6]; MUL R0.x, R0, c[5]; ADD R2.w, R0.y, vertex.position.z; SLT R0.z, R0.x, c[0].w; ADD R0.y, -R0.x, -R0.x; MAD R1.w, R0.y, R0.z, R0.x; MAD R0.x, R1.w, c[11].w, R2.w; MUL R0.x, R0, c[0].z; ADD R0.x, R0, -c[8]; FRC R0.w, R0.x; ADD R0.xyz, -R0.w, c[7]; MUL R0.xyz, R0, R0; MUL R1.xyz, R0, c[0].xyxw; ADD R1.xyz, R1, c[8].yzyw; MAD R1.xyz, R1, R0, c[9].xyxw; MAD R1.xyz, R1, R0, c[9].zwzw; MAD R1.xyz, R1, R0, c[10].xyxw; MAD R0.xyz, R1, R0, c[10].zwzw; SLT R2.x, R0.w, c[8]; SGE R2.yz, R0.w, c[11].xxyw; MOV R1.xz, R2; DP3 R1.y, R2, c[10].zwzw; DP3 R0.x, R0, -R1; MAD R0.y, R1.w, c[11].z, R2.w; MUL R0.x, R0, vertex.texcoord[0]; MAD R0.w, -R0.x, c[12].x, vertex.position.z; MAD R0.x, R1.w, c[7].w, R2.w; MUL R0.y, R0, c[0].z; ADD R0.y, R0, -c[8].x; FRC R2.w, R0.y; MUL R0.x, R0, c[0].z; ADD R0.x, R0, -c[8]; FRC R1.w, R0.x; ADD R0.xyz, -R2.w, c[7]; MUL R0.xyz, R0, R0; MUL R3.xyz, R0, c[0].xyxw; ADD R1.xyz, -R1.w, c[7]; MUL R1.xyz, R1, R1; MUL R2.xyz, R1, c[0].xyxw; ADD R3.xyz, R3, c[8].yzyw; MAD R3.xyz, R3, R0, c[9].xyxw; MAD R3.xyz, R3, R0, c[9].zwzw; MAD R3.xyz, R3, R0, c[10].xyxw; ADD R2.xyz, R2, c[8].yzyw; MAD R2.xyz, R2, R1, c[9].xyxw; MAD R2.xyz, R2, R1, c[9].zwzw; MAD R2.xyz, R2, R1, c[10].xyxw; MAD R3.xyz, R3, R0, c[10].zwzw; SLT R4.x, R2.w, c[8]; SGE R4.yz, R2.w, c[11].xxyw; MOV R0.xz, R4; DP3 R0.y, R4, c[10].zwzw; DP3 R2.w, R3, -R0; SGE R0.yz, R1.w, c[11].xxyw; SLT R0.x, R1.w, c[8]; DP3 R0.y, R0, c[10].zwzw; MAD R1.xyz, R2, R1, c[10].zwzw; DP3 R0.x, R1, -R0; MUL R1.w, vertex.texcoord[0].x, vertex.texcoord[0].y; MOV R0.z, vertex.position.w; MUL R0.x, vertex.texcoord[0], R0; MUL R0.y, -R1.w, c[8].w; MAD R0.y, R0.x, c[7], R0; MUL R0.x, vertex.texcoord[0], R2.w; MAD R0.x, R0, c[7].y, vertex.position; DP4 result.position.w, R0.xywz, c[4]; DP4 result.position.z, R0.xywz, c[3]; DP4 result.position.y, R0.xywz, c[2]; DP4 result.position.x, R0.xywz, c[1]; MOV result.texcoord[0].xy, vertex.texcoord[0]; END # 71 instructions, 5 R-regs " } SubProgram "d3d9 " { Keywords { } Bind "vertex" Vertex Bind "texcoord" TexCoord0 Matrix 0 [glstate_matrix_mvp] Vector 4 [_Time] Float 5 [_WaveSpeed] "vs_2_0 ; 66 ALU dcl_position0 v0 dcl_texcoord0 v1 def c6, -0.02083333, -0.12500000, 1.00000000, 0.50000000 def c7, -0.00000155, -0.00002170, 0.00260417, 0.00026042 def c8, 0.00000000, 3.11999989, 0.15915491, 0.50000000 def c9, 6.28318501, -3.14159298, 0.89999998, 1.45000005 def c10, 2.20000005, 0.20000000, 0, 0 add r0.w, v0.x, v0.y mov r0.x, c4 mul r0.x, c5, r0 slt r0.y, r0.x, c8.x max r0.y, -r0, r0 slt r0.y, c8.x, r0 add r0.z, -r0.y, c6 mul r0.z, r0.x, r0 mad r1.y, r0, -r0.x, r0.z add r1.x, r0.w, v0.z mad r0.x, r1.y, c10, r1 mad r0.x, r0, c8.z, c8.w frc r0.x, r0 mad r1.z, r0.x, c9.x, c9.y sincos r0.xy, r1.z, c7.xyzw, c6.xyzw mul r0.x, r0.y, v1 mad r2.z, -r0.x, c10.y, v0 mad r0.y, r1, c9.w, r1.x mad r0.x, r1.y, c8.y, r1 mad r0.x, r0, c8.z, c8.w mad r0.y, r0, c8.z, c8.w frc r0.y, r0 mov r2.w, v0 mad r1.y, r0, c9.x, c9 frc r1.x, r0 sincos r0.xy, r1.y, c7.xyzw, c6.xyzw mad r0.x, r1, c9, c9.y sincos r1.xy, r0.x, c7.xyzw, c6.xyzw mul r0.x, v1, v1.y mul r0.z, -r0.x, c9 mul r0.x, v1, r1.y mad r2.y, r0.x, c6.w, r0.z mul r0.x, v1, r0.y mad r2.x, r0, c6.w, v0 dp4 oPos.w, r2, c3 dp4 oPos.z, r2, c2 dp4 oPos.y, r2, c1 dp4 oPos.x, r2, c0 mov oT0.xy, v1 " } SubProgram "gles " { Keywords { } "!!GLES #define SHADER_API_GLES 1 #define tex2D texture2D #ifdef VERTEX #define gl_ModelViewProjectionMatrix glstate_matrix_mvp uniform mat4 glstate_matrix_mvp; varying highp vec2 xlv_TEXCOORD0; uniform highp float _WaveSpeed; uniform highp vec4 _Time; attribute vec4 _glesMultiTexCoord0; attribute vec4 _glesVertex; void main () { highp vec4 tmpvar_1; tmpvar_1 = _glesVertex; highp float t; highp float tmpvar_2; tmpvar_2 = ((_glesVertex.x + _glesVertex.y) + _glesVertex.z); highp float tmpvar_3; tmpvar_3 = (_Time * _WaveSpeed).x; t = tmpvar_3; if ((tmpvar_3 < 0.0)) { t = (tmpvar_3 * -1.0); }; highp float tmpvar_4; tmpvar_4 = _glesMultiTexCoord0.x; tmpvar_1.x = (_glesVertex.x + ((sin (((t * 1.45) + tmpvar_2)) * tmpvar_4) * 0.5)); tmpvar_1.y = (((sin (((t * 3.12) + tmpvar_2)) * tmpvar_4) * 0.5) - ((_glesMultiTexCoord0.x * _glesMultiTexCoord0.y) * 0.9)); tmpvar_1.z = (tmpvar_1.z - ((sin (((t * 2.2) + tmpvar_2)) * tmpvar_4) * 0.2)); gl_Position = (gl_ModelViewProjectionMatrix * tmpvar_1); xlv_TEXCOORD0 = _glesMultiTexCoord0.xy; } #endif #ifdef FRAGMENT varying highp vec2 xlv_TEXCOORD0; uniform sampler2D _MainTex; void main () { highp vec4 tmpvar_1; mediump vec4 color; lowp vec4 tmpvar_2; tmpvar_2 = texture2D (_MainTex, xlv_TEXCOORD0); color = tmpvar_2; tmpvar_1 = color; gl_FragData[0] = tmpvar_1; } #endif" } } Program "fp" { // Fragment combos: 1 // opengl - ALU: 1 to 1, TEX: 1 to 1 // d3d9 - ALU: 1 to 1, TEX: 1 to 1 SubProgram "opengl " { Keywords { } SetTexture 0 [_MainTex] 2D "!!ARBfp1.0 # 1 ALU, 1 TEX TEX result.color, fragment.texcoord[0], texture[0], 2D; END # 1 instructions, 0 R-regs " } SubProgram "d3d9 " { Keywords { } SetTexture 0 [_MainTex] 2D "ps_2_0 ; 1 ALU, 1 TEX dcl_2d s0 dcl t0.xy texld r0, t0, s0 mov oC0, r0 " } SubProgram "gles " { Keywords { } "!!GLES" } } #LINE 76 SetTexture [_MainTex] {combine texture} } } Fallback "VertexLit" } Which results in a flag that uses alpha values, but when the flag waves it leaves rendering artifacts at the end of the flag (it looks like a copy of the end of the flag is left hanging in space as the flag moves on). Does anyone have any ideas how to fix this?
Ok guys, Thanks a lot for this very usefull Thread. Starting from this, I went a little bit further in the study. Here is my version of the shader : The "FlagWaveCG.cginc" file : Code (csharp): // Upgrade NOTE: replaced 'glstate.matrix.mvp' with 'UNITY_MATRIX_MVP' // Original shader by cboe - Mar, 23, 2009 // Enhanced to 3 axis movement by Seon - Jan, 21, 2010 // Added _WaveSpeed by Eric5h5 - Jan, 26, 2010 // CHANGE LOG - Gauthier BOAGLIO (golgauth) / Klakos - May, 07, 2011 : // - Added Transparency support // - Added Spec and Normal mapping support // - Added Shadow casting support (+ Shadow Alpha and Shadow Alpha cutoff support) // [Done in the "ShadowCaster" additional Pass] // - Added advanced double-sided rendering support // - Added _WaveStrength param // // 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. // // [url]http://klakos.com/en/advanced-waving-flag-shader-for-unity-double-sided-alpha-shadow-support-3/[/url] ] for // visuals and more informations #include "UnityCG.cginc" float4 _Color; sampler2D _MainTex; fixed _Cutoff; float _WaveSpeed; float _WaveStrength; struct v2f { V2F_SHADOW_CASTER; float2 uv : TEXCOORD1; }; void computeWave (inout appdata_full v, inout v2f o) { float sinOff=(v.vertex.x+v.vertex.y+v.vertex.z) * _WaveStrength; 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( UNITY_MATRIX_MVP, v.vertex ); o.uv = v.texcoord; } The "FlagWave-Advanced.shader" file : Code (csharp): // Upgrade NOTE: replaced 'glstate.matrix.mvp' with 'UNITY_MATRIX_MVP' // Original shader by cboe - Mar, 23, 2009 // Enhanced to 3 axis movement by Seon - Jan, 21, 2010 // Added _WaveSpeed by Eric5h5 - Jan, 26, 2010 // CHANGE LOG - Gauthier BOAGLIO (golgauth) / Klakos - May, 07, 2011 : // - Added Transparency support // - Added Spec and Normal mapping support // - Added Shadow casting support (+ Shadow Alpha and Shadow Alpha cutoff support) // [Done in the "ShadowCaster" additional Pass] // - Added advanced double-sided rendering support // - Added _WaveStrength param // // 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. // // See [ http://klakos.com/en/advanced-waving-flag-shader-for-unity-double-sided-alpha-shadow-support-3/ ] for // visuals and more informations Shader "Selfmade/for-2sided/FlagWave Advanced Regular" { Properties { // Ususal stuffs _Color ("Main Color", Color) = (1,1,1,1) _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 0) _Shininess ("Shininess", Range (0.01, 1)) = 0.078125 _MainTex ("Base (RGB) TransGloss (A)", 2D) = "white" {} // Bump stuffs //_Parallax ("Height", Range (0.005, 0.08)) = 0.02 _BumpMap ("Normalmap", 2D) = "bump" {} //_ParallaxMap ("Heightmap (A)", 2D) = "black" {} // Shadow Stuff _Cutoff ("Shadow Alpha cutoff", Range(0.25,0.9)) = 1.0 // Flag Stuffs _WaveSpeed ("Wave Speed", Range(0.0, 300.0)) = 50.0 _WaveStrength ("Wave Strength", Range(0.0, 5.0)) = 1.0 } SubShader { Tags { "Queue"="Geometry" "IgnoreProjector"="True" "RenderType"="Transparent"} LOD 300 Pass { Name "ShadowCaster" Tags { "LightMode" = "ShadowCaster" } Fog {Mode Off} ZWrite On ZTest Less Cull Off Offset 1, 1 CGPROGRAM // Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it does not contain a surface program or both vertex and fragment programs. #pragma exclude_renderers gles #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #pragma multi_compile_shadowcaster #include "FlagWaveCG.cginc" v2f vert( appdata_full v ) { v2f o; computeWave(v, o); TRANSFER_SHADOW_CASTER(o) return o; } //sampler2D _MainTex; float4 frag( v2f i ) : COLOR { fixed4 texcol = tex2D( _MainTex, i.uv ); clip( texcol.a - _Cutoff ); SHADOW_CASTER_FRAGMENT(i) } ENDCG //SetTexture [_MainTex] {combine texture} } //CULL Front CGPROGRAM #pragma surface surf BlinnPhong alpha vertex:vert fullforwardshadows approxview #include "FlagWaveCG.cginc" half _Shininess; sampler2D _BumpMap; //sampler2D _ParallaxMap; float _Parallax; struct Input { float2 uv_MainTex; float2 uv_BumpMap; //float3 viewDir; }; v2f vert (inout appdata_full v) { v2f o; computeWave(v, o); return o; } void surf (Input IN, inout SurfaceOutput o) { // Comment the next 4 following lines to get a standard bumped rendering // [Without Parallax usage, which can cause strange result on the back side of the plane] /*half h = tex2D (_ParallaxMap, IN.uv_BumpMap).w; float2 offset = ParallaxOffset (h, _Parallax, IN.viewDir); IN.uv_MainTex += offset; IN.uv_BumpMap += offset;*/ fixed4 tex = tex2D(_MainTex, IN.uv_MainTex); o.Albedo = tex.rgb * _Color.rgb; o.Gloss = tex.a; o.Alpha = tex.a * _Color.a; //clip(o.Alpha - _Cutoff); o.Specular = _Shininess; o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap)); } ENDCG } Fallback "Transparent/VertexLit" } I also made a full case study here : http://klakos.com/en/advanced-waving-flag-shader-for-unity-double-sided-alpha-shadow-support-3/ It covers the following points : * * Flag vertices animation via a shader (trigo. way) * * Advanced ShaderLab surface shading for transparency management * * Adding a shadow Pass (with alpha support) * * Double-sided surfaces methods (methods 1, 2 and 3) * * Provided Double-sided Materials Configuration Wizard (for 3rd method) >>> Downloads [from the address bellow] * - PDF version of the article : WavingFlag.pdf * - Configuration Wizard : BackwardMaterialBuilder.cs * - Unity 3.3 Package : WavingFlagDemo.unitypackage | WavingFlagDemo.rar Hope this will help...
Hello cboe~~~ it's very useful for me. But there are still some parts of this shader ,that i do not understand. Such as: TRANSFER_SHADOW_CASTER(o) SHADOW_CASTER_FRAGMENT(i) Are they the Built-in funtion of Unity? Where i can found the details about them?
Yes they are (from UnityCG.cginc). Have a look at the Vertexlit built-in shader : it includes passes for both shadow casting SHADOW_CASTER_FRAGMENT and shadow receiving SHADOW_COLLECTOR_FRAGMENT. The goal, here is to force both shadow casting and receiving even if the material is transparent (and should not be able to). http://unity3d.com/support/documentation/Components/SL-PassTags.html
I'm trying to use this (and even downloaded the unitypackage example scene) and in doing so ran across the following issue (attached) where a polyPlane from maya - exported without any edits - causes a weird issue. It's more pinched at one side, and isn't exactly animating or flowing correctly to the Sin. I assume this is a problem with what's documented in the shader: Although this seems fine to me, I'm honestly not understanding where the issue lays and where I should be fixing this in maya. I'm not quite sure if anything was done to the blender imported plane to make it work however. Much appreciated!
Yes it does. Unfortunately I don't know anything about Maya vertices and axises management. So, all I can say, is that under Blender, you have to enter the "Vertex Mode" (aka : Edit the Mesh). Then select all vertices and rotate of 90 degrees along the appropriate axis. Then apply (I think it is Ctrl+A+Enter), to reset the relative coordinates of the selected vertices. Then save and reimport in Unity : the flag should be in the same plane than the Unity plane now. If you can't do such an operation in Maya, all I can suggest is to use Blender... Sorry. If we have a Maya specialist around there, please help !
Hi Guys, I've been using this shader and want to have the flag some gravity applied to it. Like this I'm very new to CGProgramming. But I think I have to change the code in here to apply gravity to it. I'm not completely sure how to do this. Any help would be appreciated. thanks for your help in advance.