Untitled

mail@pastecode.io avatar
unknown
csharp
2 years ago
11 kB
8
Indexable
Never
Shader "/Grass"
{
    Properties
    {
		[Header(Shading)]
        _TopColor("Top Color", Color) = (1,1,1,1)
		_BottomColor("Bottom Color", Color) = (1,1,1,1)
		_DepositColor("Deposit Color", Color) = (1,1,1,1)
		_DepositTex("Deposit Texture", 2D) = "defaulttexture" {}
		_GrassMask("Grass Mask Texture", 2D) = "defaulttexture" {}
		_GrassBladeTex("Grass Blade Texture", 2D) = "defaulttexture" {}
		_CutOff("Cut off", float) = 0.1
		_ColorVariationRandom("Color Variation Random", Range(0,128)) = 5
		_TranslucentGain("Translucent Gain", Range(0,1)) = 0.5
		_BendRotationRandom("Bend Rotation Random", Range(0, 1)) = 0.2
		_BladeWidth("Blade Width", Float) = 0.05
		_BladeWidthRandom("Blade Width Random", Float) = 0.02
		_BladeHeight("Blade Height", Float) = 0.5
		_BladeHeightRandom("Blade Height Random", Float) = 0.3
		_TessellationUniform("Tessellation Uniform", Range(1, 64)) = 1
		_WindDistortionMap("Wind Distortion Map", 2D) = "white" {}
		_RotationSpeed ("Rotation Speed", Float) = 2.0
		_WindFrequency("Wind Frequency", Vector) = (0.05, 0.05, 0, 0)
		_WindStrength("Wind Strength", Float) = 1
		_BladeForward("Blade Forward Amount", Float) = 0.38
		_BladeCurve("Blade Curvature Amount", Range(1, 4)) = 2
		_maxDist("Max Distance", Float) = 100
		_UseTextureColors("Use Texture Colors", Range(0, 1)) = 0
		[Header(Bending)]
		_YOffset("Y offset", float) = 0.0// y offset, below this is no animation
        _MaxWidth("Max Displacement Width", Range(0, 2)) = 0.1 // width of the line around the dissolve
		_Radius("Radius", Range(0,5)) = 1 // width of the line around the dissolve 
		_CutRadius("Cut Radius", Range(0,5)) = 1 // width of the line around the dissolve (for cutting)
		_Positions("Positions", Vector) = (0,0,0,0) 
		_PositionArray("PositionArray", Float) = 0
		_CutPositions("Cut Positions", Vector) = (0,0,0,0) 
		_CutPositionArray("Cut PositionArray", Float) = 0
    }

	CGINCLUDE
	#include "UnityCG.cginc"
	#include "Autolight.cginc"
	#include "./CustomTessellation.cginc"

	#define BLADE_SEGMENTS 2

	float _BendRotationRandom;
	float _BladeHeight;
	float _BladeHeightRandom;	
	float _BladeWidth;
	float _BladeWidthRandom;
	float _BladeForward;
	float _BladeCurve;

	uniform float3 _Positions[100];
	uniform float _PositionArray;

	uniform float3 _CutPositions[100];
	uniform float _CutPositionArray;

	sampler2D _WindDistortionMap;
	float4 _WindDistortionMap_ST;
	float2 _WindFrequency;
	float _WindStrength;

	float _RotationSpeed;

	float _UseTextureColors;

	//limits
	float _SlopeLimit;
	float _BeachLimit;
	float _HeightLimit;
	float _maxDist;

	sampler2D _DepositTex;
	//sampler2D _GrassMask;
	float4 _GrassMask_ST;
	float4 _DepositTex_ST;
	sampler2D _GrassBladeTex;
	uniform float _CutOff;

	//bending
	float _Radius;
	float _MaxWidth;
	float _YOffset;

	//cutting
	float _CutRadius;

	struct geometryOutput
	{
		float4 pos : SV_POSITION;
		float2 uv : TEXCOORD0;
		float3 normal : NORMAL;
		float deposit : DEPOSIT;
		unityShadowCoord4 _ShadowCoord : TEXCOORD1;
	};

	geometryOutput VertexOutput(float3 pos, float2 uv, float3 normal, float deposit)
	{
		geometryOutput o;
		o.pos = UnityObjectToClipPos(pos);
		o.uv = uv;
		o._ShadowCoord = ComputeScreenPos(o.pos);
		o.normal = UnityObjectToWorldNormal(normal);
		o.deposit = deposit;
		#if UNITY_PASS_SHADOWCASTER
			// Applying the bias prevents artifacts from appearing on the surface. i.e. self-shadowing
			o.pos = UnityApplyLinearShadowBias(o.pos);
		#endif
		return o;
	}

	

	// Simple noise function, sourced from http://answers.unity.com/answers/624136/view.html
	// Extended discussion on this function can be found at the following link:
	// https://forum.unity.com/threads/am-i-over-complicating-this-random-function.454887/#post-2949326
	// Returns a number in the 0...1 range.
	float rand(float3 co)
	{
		return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 53.539))) * 43758.5453);
	}

	// Construct a rotation matrix that rotates around the provided axis, sourced from:
	// https://gist.github.com/keijiro/ee439d5e7388f3aafc5296005c8c3f33
	float3x3 AngleAxis3x3(float angle, float3 axis)
	{
		float c, s;
		sincos(angle, s, c);

		float t = 1 - c;
		float x = axis.x;
		float y = axis.y;
		float z = axis.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
			);
	}

	geometryOutput GenerateGrassVertex(float3 vertexPosition, float width, float height, float forward, float2 uv, float3x3 transformMatrix, float depositSample)
	{
		float3 tangentPoint = float3(width, forward, height);
		float3 tangentNormal = normalize(float3(0, -1, forward));
		float3 localNormal = mul(transformMatrix, tangentNormal);
		float3 localPosition = vertexPosition + mul(transformMatrix, tangentPoint);

		return VertexOutput(localPosition, uv, localNormal, depositSample);
	}

	[maxvertexcount(BLADE_SEGMENTS * 2 + 1)]
	void geo(triangle vertexOutput IN[3], inout TriangleStream<geometryOutput> triStream)
	{
		float3 pos = IN[0].vertex;
		float3 wpos = mul(unity_ObjectToWorld, pos).xyz;// world position
		float _size = 1000;
		//float3 worldPos = mul(unity_ObjectToWorld, IN[0].vertex.xyz);
		float3 worldNormal = mul( unity_ObjectToWorld, float4( IN[0].normal, 0.0 ) ).xyz;
		float slope =  worldNormal.y;
		float dist = distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld, IN[0].vertex).xyz);

		float grassMask = tex2Dlod(_GrassMask, float4(pos.xz / _GrassMask_ST.xy+_GrassMask_ST.zw,0,0));

		int shouldCreateGrass = sign(slope-0.9) + sign(180-dist) + sign(1 - grassMask);

		if(shouldCreateGrass==3){
			float3 vNormal = IN[0].normal;
			float4 vTangent = IN[0].tangent;
			float3 vBinormal = cross(vNormal, vTangent) * vTangent.w;

			float3x3 tangentToLocal = float3x3(
			vTangent.x, vBinormal.x, vNormal.x,
			vTangent.y, vBinormal.y, vNormal.y,
			vTangent.z, vBinormal.z, vNormal.z
			);

			float3x3 facingRotationMatrix = AngleAxis3x3(rand(pos) * UNITY_TWO_PI, float3(0, 0, 1));
			float3x3 bendRotationMatrix = AngleAxis3x3(rand(pos.zzx) * _BendRotationRandom * UNITY_PI * 0.5, float3(-1, 0, 0));
		
			float depositSample = tex2Dlod(_DepositTex, float4(pos.xz / _DepositTex_ST.xy+_DepositTex_ST.zw,0,0));

			float height = (rand(pos.zyx) * 2 - 1) * _BladeHeightRandom - (depositSample*3) + _BladeHeight;
			height = height > 0 ? height : 0.2f; // hack to keep the height from going negative

			float width = (rand(pos.xzy) * 2 - 1) * _BladeWidthRandom + _BladeWidth;
			float forward = rand(pos.yyz) * _BladeForward;

			//bend grass radially away from xyz coords
			float windStrength = _WindStrength;

			for  (int x = 0; x < _PositionArray; x++){
				float3 dis =  distance(_Positions[x], wpos); // distance for radius
				float3 radius = 1 - saturate(dis /_Radius); // in world radius based on objects interaction radius
				float3 sphereDisp = wpos - _Positions[x]; // position comparison
				sphereDisp *= radius; // position multiplied by radius for falloff
				float2 bendArea = abs(clamp(sphereDisp.xz * step(_YOffset, pos.y), -_MaxWidth,_MaxWidth));

				pos.xz += bendArea*2;// vertex movement based on falloff
				height -= bendArea*5;
				forward += bendArea*10;
			}
			
			float2 uv = (pos.xz * (_WindDistortionMap_ST.xy) + _WindDistortionMap_ST.zw + _WindFrequency * _Time.y);
			float2 windSample = (tex2Dlod(_WindDistortionMap, float4(uv, 0, 0)).xy * 2 - 1) * windStrength;

			float3 wind = normalize(float3(windSample.x, windSample.y, 0));

			float3x3 windRotation = AngleAxis3x3(UNITY_PI * windSample, wind);

			float3x3 transformationMatrix = mul(mul(mul(tangentToLocal, windRotation), facingRotationMatrix), bendRotationMatrix);
			float3x3 transformationMatrixFacing = mul(tangentToLocal, facingRotationMatrix);

			
			
			//pos = 1;

			for (int i = 0; i < BLADE_SEGMENTS; i++)
			{
				float t = i / (float)BLADE_SEGMENTS;
				float segmentHeight = height * t;
				float segmentWidth = i == 0 ? width/4 : width * (1 - t); //slimmer bottom segments

				float segmentForward = pow(t, _BladeCurve) * forward;

				float3x3 transformMatrix = i == 0 ? transformationMatrixFacing : transformationMatrix;

				triStream.Append(GenerateGrassVertex(pos, segmentWidth, segmentHeight, segmentForward, float2(0, t), transformMatrix, depositSample));
				triStream.Append(GenerateGrassVertex(pos, -segmentWidth, segmentHeight, segmentForward, float2(1, t), transformMatrix, depositSample));
				
			}

			//for cutting
			bool inArea = false;
			for  (int j = 0; j < _CutPositionArray; j++){
				float3 dis =  distance(_CutPositions[j], wpos); // distance for radius
				float3 radius = 1 - saturate(dis /_CutRadius); // in world radius based on objects interaction radius
				float3 sphereDisp = wpos - _CutPositions[j]; // position comparison
				sphereDisp *= radius; // position multiplied by radius for falloff

				float2 area = abs(clamp(sphereDisp.xz * step(_YOffset, pos.y), -_MaxWidth,_MaxWidth));

				
				height -= area*10;
				if(height > 0)
				{
					//height = 0;
					inArea = true;
				}
			}
			if(inArea)
			{
				triStream.Append(GenerateGrassVertex(pos, 0, height, forward, float2(0.5, 1), transformationMatrix, depositSample));
			}
			triStream.Append(GenerateGrassVertex(pos, 0, height, forward, float2(0.5, 1), transformationMatrix, depositSample));
		}
	}
	ENDCG

    SubShader
    {
		Cull Off

        Pass
        {
			Tags
			{
				"RenderType" = "Opaque"
				"LightMode" = "ForwardBase"
				"DisableBatching" = "True"//possibly needed for bending?
			}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
			#pragma geometry geo
			#pragma hull hull
			#pragma domain domain
			#pragma target 4.6
			#pragma multi_compile_fwdbase
            
			#include "Lighting.cginc"

			float4 _TopColor;
			float4 _BottomColor;
			float4 _DepositColor;
			float4 _ColorVariationRandom;
			float _TranslucentGain;

			float4 frag (geometryOutput i, fixed facing : VFACE) : SV_Target
            {	
				
				float3 normal = facing > 0 ? i.normal : -i.normal;
				float shadow = SHADOW_ATTENUATION(i);
				float NdotL = saturate(saturate(dot(normal, _WorldSpaceLightPos0)) + _TranslucentGain) * shadow;
				
				float3 ambient = ShadeSH9(float4(normal, 1));
				float4 lightIntensity = NdotL * _LightColor0 + float4(ambient, 1);
				
				float4 tex = tex2Dlod (_GrassBladeTex, float4(i.uv.xy,0,0));
				float deposit = i.deposit;

				float4 col = lerp(_BottomColor + (deposit * _DepositColor), (_TopColor  + (deposit * _DepositColor)) * lightIntensity, i.uv.y) * tex.r * 2;
				if(tex.a < _CutOff) discard;
				return _UseTextureColors ? tex : col;
            }
            ENDCG
        }

		Pass
		{
			Tags
			{
				"LightMode" = "ShadowCaster"
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma geometry geo
			#pragma fragment frag
			#pragma hull hull
			#pragma domain domain
			#pragma target 4.6
			#pragma multi_compile_shadowcaster

			float4 frag(geometryOutput i) : SV_Target
			{
				SHADOW_CASTER_FRAGMENT(i);
			}

			ENDCG
		}
    }
}