Simple Interactive Grass

Submitted by rootmaster on Fri, 06/15/2018 - 22:35

 

Shader "Debug/debugVertexColor"
{
    Properties
    {
        _ColorMask ("ColorMask", Vector) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        cull off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            uniform half4 _ColorMask;

 

            struct appdata
            {
                float4 vertex : POSITION;
                fixed4 vertexColor : COLOR;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed4 vertexColor : COLOR;
            };
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.vertexColor = v.vertexColor;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = i.vertexColor*_ColorMask;
                return col;
            }
            ENDCG
        }
    }
}

 Check each leaf have different vertex color. Then they won't move in same phase.

VC grass

 

simple trigger script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SwayGrassMove : MonoBehaviour
{
    private float remainTime;

    public static float TimeDuration = 1.5f;
    public static float Strength = 1.5f;
    public static float BaseStrength = 0;
    public AnimationCurve Curve;
    public Material swayGrassMat;
    private MeshRenderer render;

    private Vector4 Dir;

    void Start()
    {
        render = GetComponent<MeshRenderer>();
    }


    public void StartMove()
    {
        remainTime = TimeDuration;
    }

    void OnTriggerEnter(Collider other)
    {
        Dir = other.gameObject.transform.right.normalized;
        StartMove();
    }

    // Update is called once per frame
    void Update()
    {
        remainTime = remainTime - Time.deltaTime;

        if (remainTime > 0)
        {
            float val = BaseStrength + Curve.Evaluate(remainTime / TimeDuration) * Strength;
            render.material.SetFloat("_str", val);
            render.material.SetVector("_waveDir", Dir);
        }
    }
}

 

use capsule to trigger the grass movement

Grass Setup

capsule

Rotate around a certain Aixs seems fine

Shader "Effect/SwayWaveGrass"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _speed("Wave Speed",float) = 1
        _str("Strength",float) = 1
        _waveDir("Wave Direction",Vector) = (0,0,0,0)        
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        cull off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            
            ///////////////////////////////////////////////////////////////////////
            //  RotationMatrix
            //
            //  Constructs an arbitrary axis rotation matrix

            float3x3 RotationMatrix(float3 vAxis, float fAngle)
            {
                // compute sin/cos of fAngle
                float2 vSinCos;
                #ifdef OPENGL
                    vSinCos.x = sin(fAngle);
                    vSinCos.y = cos(fAngle);
                #else
                    sincos(fAngle, vSinCos.x, vSinCos.y);
                #endif

                const float c = vSinCos.y;
                const float s = vSinCos.x;
                const float t = 1.0 - c;
                const float x = vAxis.x;
                const float y = vAxis.y;
                const float z = vAxis.z;

                return float3x3(t * x * x + c,      t * x * y - s * z,  t * x * z + s * y,
                                t * x * y + s * z,  t * y * y + c,      t * y * z - s * x,
                                t * x * z - s * y,  t * y * z + s * x,  t * z * z + c);
            }

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
                fixed4 vertexColor : COLOR;
            };

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            half _str;
            half _speed;
            half4 _waveDir;
            
            v2f vert (appdata v)
            {
                v2f o;
                //--per leaf moving---//
                half param = sin((_Time.z+v.vertexColor.r*2)*_speed)*v.vertexColor.g*_str;
                //float3 aix = cross(v.normal,float3(0,1,0));
                //v.vertex.xyz = mul(RotationMatrix(aix,param),v.vertex.xyz);
                //--whole grass moving--//
                float3 aix = cross(float3(_waveDir.x,0,_waveDir.z),float3(0,1,0));
                v.vertex.xyz = mul(RotationMatrix(aix,param),v.vertex.xyz);
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);;
                return col;
            }
            ENDCG
        }
    }
}

Just sin wave less calculation but tend to deform too much

Shader "Effect/WaveGrass"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _speed("Wave Speed",float) = 1
        _str("Strength",float) = 1
        _waveDir("Wave Direction",Vector) = (0,0,0,0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        cull off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            half _str;
            half _speed;
            half _duration;
            half4 _waveDir;
            
            v2f vert (appdata v)
            {
                v2f o;
                half param = (_Time.z+v.vertexColor.r*2)*_speed;
                half param2 = v.vertexColor.g*_str/10;
                _waveDir.x = _waveDir.x*sin(param)*param2;
                _waveDir.z = _waveDir.z*sin(param)*param2;
                v.vertex.x = v.vertex.x+_waveDir.x;
                v.vertex.z = v.vertex.z+_waveDir.z;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);;
                return col;
            }
            ENDCG
        }
    }
}

 

grass move

Just a test project. If unity internal collision is not sufficient, Replace it with your own.