Digging myself deeper and deeper into the ShaderLab hole... I have a lot of objects with the same shader. The shader needs to know the position of another object. First attempt has an exposed Vector property for the shader. This works, but with many objects it gets inconvenient: Code (csharp): //shader Properties { _Obstacle ("Obstacle", Vector) = (0,0,0,0) } //Object that affects shader other.renderer.material.SetVector("_Obstacle", transform.position); Then I remembered global shader properties, but it seems SetGlobalVector is missing . I can use SetGlobalFloat for x,y,z, that should work fine, I'm just wondering if there's a 'proper' way of getting a position like this into the shader? /P
For now use SetGlobalColor, we'll add SetGlobalVector in the future release. SetGlobalColor will just work; as vectors and colors internally are the same thing (four floating point numbers); and Colors can have components outside of the usual 0..1 range.
SetGlobalColor works great. Managed to hack the Windy Grass shader to make the grass bend to avoid an obstacle. Still need to fix issues when the obstacle is inside the grass geometry as this will stretch the grass unnaturally. (Btw, I'm using geometry instead of billboards so I can have the camera close to the grass) /P
wow that's really cool - i'm wondering how is the performance using regular meshes instead of billboards?
Looks awesome metervara! Any chance you could share you code for that? Pretty please? I'd like to learn how to do this stuff in a shader instead of the mesh interface. ;-) -Jeremy
Here is the most basic version. It has some problems when the obstacle is inside the geometry. One fix is to move the grass slightly away from the obstacle as it gets close, but it looks weird if the ground is visible. Works when you only see the top of the grass though. It's a few additions to the standard Windy Grass shader from the Nature pack: Firts off there's a global shader color: _Obstacle. Use Shader.SetGlobalColor to get the obstacle position to the shader. Then the main block (/OBSTACLE AVOIDANCE CALC). The windy grass shader already calculates the world position for vertices so use that and compare with obstacle position to get bend direction vector. Also calculate distance falloff. Finally we add the bend offset exponentially - v.vertex.xz += ... We could also swap v.texcoord.y for let's say v.color.r and paint the 'bendyness' into the model using vertex colors to have some parts softer than others. Doesn't really make sense for a simple thing like a grass straw though, but could be cool for more complex models. Note: And all this is not really bending, but stretching or skewing so the geometry can look strange sometimes. Feel free to fix Code (csharp): Shader "Nature/Windy Grass" { Properties { _Color ("Main Color", Color) = (.5, .5, .5, 0) _Color2 ("Fade Color", Color) = (1, .9, .8, 0) _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {} _Cutoff ("Base Alpha cutoff", Range (0,1)) = .5 } SubShader { Tags { "Queue" = "Transparent" } BindChannels { Bind "Color", color Bind "Vertex", vertex Bind "TexCoord", texcoord } Pass { Lighting On CGPROGRAM // vertex Vertex #include "waves.cginc" // Get in the helper wave functions #include "UnityCG.cginc" // Get standard Unity constants struct Appdata { float4 vertex; float3 normal; float4 texcoord; float4 color; }; struct v2f { float4 pos : POSITION; float4 color : COLOR0; float4 uv : TEXCOORD0; float fog : FOGC; }; uniform float4 _Color, _Color2, _SkyLight; uniform float4 _Obstacle; // OBSTACLE AVOIDANCE v2f Vertex(Appdata v) { v2f o; const float4 _waveXSize = float4(0.012, 0.02, -0.06, 0.048) * 2; const float4 _waveZSize = float4 (0.006, .02, -0.02, 0.1) * 2; const float4 waveSpeed = float4 (0.3, .3, .08, .07) * 4; float4 _waveXmove = _waveXSize * waveSpeed * 25; float4 _waveZmove = _waveZSize * waveSpeed * 25; // We model the wind as basic waves... // Calculate the wind input to leaves from their vertex positions.... // for now, we transform them into world-space x/z positions... // Later on, we should actually be able to do the whole calc's in post-projective space float3 worldPos = mul ((float3x4)_Object2World, v.vertex); // OBSTACLE AVOIDANCE CALC float3 bendDir = normalize (float3(worldPos.x,0,worldPos.z) - float3(_Obstacle.x,0,_Obstacle.z));//direction of obstacle bend float distLimit = 3;// how far away does obstacle reach float distMulti = (distLimit-min(distLimit,distance(float3(worldPos.x,0,worldPos.z),float3(_Obstacle.x,0,_Obstacle.z))))/distLimit; //distance falloff //OBSTACLE AVOIDANCE END // This is the input to the sinusiodal warp float4 waves; waves = worldPos.x * _waveXSize; waves += worldPos.z * _waveZSize; // Add in time to model them over time waves += _Time.x * waveSpeed; float4 s, c; waves = frac (waves); FastSinCos (waves, s,c); float waveAmount = v.texcoord.y; s *= waveAmount; // Faste winds move the grass more than slow winds s *= normalize (waveSpeed); s = s * s; float fade = dot (s, 1.3); s = s * s; float3 waveMove = float3 (0,0,0); waveMove.x = dot (s, _waveXmove); waveMove.z = dot (s, _waveZmove); v.vertex.xz -= mul ((float3x3)_World2Object, waveMove).xz; v.vertex.xz += bendDir.xz*distMulti*v.texcoord.y*v.texcoord.y*1.5; //ADD OBSTACLE BENDING o.pos = mul(glstate.matrix.mvp, v.vertex); o.fog = o.pos.w; o.uv = v.texcoord; o.color = lerp (_Color, _Color2, fade.xxxx); // o.color *= _SkyLight; return o; } ENDCG AlphaTest Greater [_Cutoff] Cull Off SetTexture [_MainTex] { combine texture * primary double, texture} } } SubShader { Tags { "Queue" = "Transparent" } Pass { Blend SrcAlpha oneMinusSrcAlpha AlphaTest Greater [_Cutoff] Cull Off color [_Color] ZTest Less SetTexture [_MainTex] { combine texture * primary DOUBLE, texture} } } } /P
Here's a version that works in Unity 2.5. Please note, I customized it to my own situation, which means the texture has been removed. Code (csharp): Shader "Dynamic Grass" { Properties { _Color ("Main Color", Color) = (.055, .094, .082, 1) _Color2 ("Fade Color", Color) = (.09, .157, .137, 1) _WaveX ("Wave X", Vector) = (.07, .01, .01, 0.01) _WaveZ ("Wave Z", Vector) = (-.07, .01, .01, 0.01) _WaveSpeed ("Wave Speed", Vector) = (1, 1.5, 1.1, .9) } SubShader { Tags { "Queue" = "Transparent" } Pass { Lighting On CGPROGRAM #pragma vertex Vertex #include "waves.cginc" // Get in the helper wave functions #include "UnityCG.cginc" // Get standard Unity constants struct v2f { float4 pos : POSITION; float4 color : COLOR0; float4 uv : TEXCOORD0; float fog : FOGC; }; uniform float4 _Color, _Color2, _WaveX, _WaveZ, _WaveSpeed; uniform float3 _obstacle; uniform float _affectDist, _bendAmount; v2f Vertex(appdata_base v) { v2f o; const float4 _waveXSize = _WaveX * 2; const float4 _waveZSize = _WaveZ * 2; const float4 waveSpeed = _WaveSpeed * 4; float4 _waveXmove = _waveXSize * waveSpeed * 25; float4 _waveZmove = _waveZSize * waveSpeed * 25; // Calculate the wind input to leaves from their vertex positions.... float3 worldPos = mul ((float3x4)_Object2World, v.vertex); // OBSTACLE AVOIDANCE CALC float3 bendDir = normalize (float3(worldPos.x,0,worldPos.z) - float3(_obstacle.x,0,_obstacle.z));//direction of obstacle bend float distLimit = _affectDist;// how far away does obstacle reach float distMulti = (distLimit-min(distLimit,distance(float3(worldPos.x,0,worldPos.z),float3(_obstacle.x,0,_obstacle.z))))/distLimit; //distance falloff //OBSTACLE AVOIDANCE END // This is the input to the sinusiodal warp float4 waves; waves = worldPos.x * _waveXSize; waves += worldPos.z * _waveZSize; // Add in time to model them over time waves += _Time.x * waveSpeed; float4 s, c; waves = frac (waves); FastSinCos (waves, s,c); float waveAmount = v.texcoord.y; s *= waveAmount; // Faste winds move the grass more than slow winds s *= normalize (waveSpeed); s = s * s; float fade = dot (v.texcoord.y * v.texcoord.y, 2); s = s * s; float3 waveMove = float3 (0,0,0); waveMove.x = dot (s, _waveXmove); waveMove.z = dot (s, _waveZmove); v.vertex.xz -= mul ((float3x3)_World2Object, waveMove).xz; v.vertex.xz += bendDir.xz * distMulti * v.texcoord.y * v.texcoord.y * _bendAmount; //ADD OBSTACLE BENDING o.pos = mul(glstate.matrix.mvp, v.vertex); o.fog = o.pos.w; o.uv = v.texcoord; o.color = lerp (_Color, _Color2, fade.xxxx); return o; } ENDCG AlphaTest Greater [_Cutoff] Cull Off } } SubShader { Tags { "Queue" = "Transparent" } Pass { Blend SrcAlpha oneMinusSrcAlpha AlphaTest Greater [_Cutoff] Cull Off color [_Color] ZTest Less } } } This script is attached to a cube that acts as my obstacle. I've rigged it up so that it increases how far it affects the grass and how much the grass bends when you're pressing the Jump button. Code (csharp): #pragma strict @script ExecuteInEditMode var affectDist : float = 8; var bendAmount : float = 5; private var myTransform : Transform; function Awake() { SetBend(); myTransform = transform; } function Update() : void { Shader.SetGlobalVector("_obstacle", myTransform.position); if (Input.GetButton("Jump")) { if (affectDist < 22) { affectDist += 3; bendAmount += 0.3; SetBend(affectDist, bendAmount); } if (affectDist > 20) { affectDist = 20; bendAmount = 6.2; SetBend(affectDist, bendAmount); } } else { if (affectDist > 8) { affectDist -= 4; bendAmount -= 0.6; SetBend(affectDist, bendAmount); } else { SetBend(); } } } function SetBend(_affectDist : float, _bendAmount : float) : void { Shader.SetGlobalFloat("_affectDist", _affectDist); Shader.SetGlobalFloat("_bendAmount", _bendAmount); } function SetBend() : void { SetBend(8, 5); } IMPORTANT: The values here are set to blades of grass that are approximately 1 unit wide and 8 units tall or so. It's very important that the grass blade mesh has UV coordinates such that the grass blade looks "upright," which a planar projection along the Z would get you. A screenshot is attached. Note, that cube is a default cube created by Unity.
I am having trouble getting the shader to work. When I use the shader on my planes no color is added and they remain invisible. Would it be possible by any chance for you to upload the Unity project? many thanks, Lars
Im also having problems with the shader aswell. I cant seem to get either of the shaders working either.
I've attached the waves.cginc file, which I have in my Materials folder along with the shader. Dynamic Grass shader applied as a material to grass blade meshes with UV coordinates with optional bending on the y: Code (csharp): Shader "Dynamic Grass" { Properties { _Color ("Main Color", Color) = (.055, .094, .082, 1) _Color2 ("Fade Color", Color) = (.09, .157, .137, 1) _WaveX ("Wave X", Vector) = (.07, .01, .01, 0.01) _WaveZ ("Wave Z", Vector) = (-.07, .01, .01, 0.01) _WaveSpeed ("Wave Speed", Vector) = (1, 1.5, 1.1, .9) } SubShader { Tags { "Queue" = "Transparent" } Pass { Lighting On CGPROGRAM #pragma vertex Vertex #include "waves.cginc" // Get in the helper wave functions #include "UnityCG.cginc" // Get standard Unity constants struct v2f { float4 pos : POSITION; float4 color : COLOR0; float4 uv : TEXCOORD0; float fog : FOGC; }; uniform float4 _Color, _Color2, _WaveX, _WaveZ, _WaveSpeed; uniform float3 _obstacle; uniform float _affectDist, _bendAmount; v2f Vertex(appdata_base v) { v2f o; const float4 _waveXSize = _WaveX * 2; const float4 _waveZSize = _WaveZ * 2; const float4 waveSpeed = _WaveSpeed * 4; float4 _waveXmove = _waveXSize * waveSpeed * 25; float4 _waveZmove = _waveZSize * waveSpeed * 25; // Calculate the wind input to leaves from their vertex positions.... float3 worldPos = mul ((float3x4)_Object2World, v.vertex); // OBSTACLE AVOIDANCE CALC float3 bendDir = normalize (float3(worldPos.x,worldPos.y,worldPos.z) - float3(_obstacle.x,_obstacle.y,_obstacle.z));//direction of obstacle bend float distLimit = _affectDist;// how far away does obstacle reach float distMulti = (distLimit-min(distLimit,distance(float3(worldPos.x,worldPos.y,worldPos.z),float3(_obstacle.x,_obstacle.y,_obstacle.z))))/distLimit; //distance falloff //OBSTACLE AVOIDANCE END // This is the input to the sinusiodal warp float4 waves; waves = worldPos.x * _waveXSize; waves += worldPos.z * _waveZSize; // Add in time to model them over time waves += _Time.x * waveSpeed; float4 s, c; waves = frac (waves); FastSinCos (waves, s,c); float waveAmount = v.texcoord.y; s *= waveAmount; // Faste winds move the grass more than slow winds s *= normalize (waveSpeed); s = s * s; float fade = dot (v.texcoord.y * v.texcoord.y, 2); s = s * s; float3 waveMove = float3 (0,0,0); waveMove.x = dot (s, _waveXmove); waveMove.z = dot (s, _waveZmove); v.vertex.xz -= mul ((float3x3)_World2Object, waveMove).xz; v.vertex.xz += bendDir.xz * distMulti * v.texcoord.y * v.texcoord.y * _bendAmount; //ADD OBSTACLE BENDING //optional y bending //v.vertex.xyz += bendDir.xyz * distMulti * v.texcoord.y * v.texcoord.y * _bendAmount; //ADD OBSTACLE BENDING o.pos = mul(glstate.matrix.mvp, v.vertex); o.fog = o.pos.w; o.uv = v.texcoord; o.color = lerp (_Color, _Color2, fade.xxxx); return o; } ENDCG AlphaTest Greater [_Cutoff] Cull Off } } SubShader { Tags { "Queue" = "Transparent" } Pass { Blend SrcAlpha oneMinusSrcAlpha AlphaTest Greater [_Cutoff] Cull Off color [_Color] ZTest Less } } } Bend affect script attached to obstacle object: Code (csharp): #pragma strict @script ExecuteInEditMode var affectDist : float = 20; var bendAmount : float = 5; private var myTransform : Transform; function Awake() { myTransform = transform; } function Update() { Shader.SetGlobalVector("_obstacle", myTransform.position); Shader.SetGlobalFloat("_affectDist", _affectDist); Shader.SetGlobalFloat("_bendAmount", _bendAmount); }
Hello, sorry for digging into this old thread. But is there a way to add shadow receiving to this shader? I found this: http://wiki.unity3d.com/index.php?title=TransparentShadowReceiver but combining it with this shader results in shadow casting, no receiving and no deformation anymore. Thanks.
hi, sorry to necro this... i'm trying to get collision info in a shader and the examples i see always rely on old unity versions i'm on 5 and Wonder witch changes have been made in code to deal with collisions et setglobalvector i use this code with no success : collisionInfo.gameObject.GetComponent<Renderer>().material.SetVector("_CollisionPoint", contact.point); thanks
This seems to not be working at all on unity 5 Terrain, sad face :'( Probably something is done differently on the Grass Shader itself, when you do it line by line, you see that everything gets weird when you multiply wordPos * waveXsizes instead of vertex * waveXsizes.. Code (csharp): waves = worldPos.x * _waveXSize; waves += worldPos.z * _waveZSize; waves = vertex.x * _waveXSize; waves += vertex.z * _waveZSize;