using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class ProceduralGrass : MonoBehaviour
{
#region Terrain Data
[Range(0, 1000)]
public int terrainSize = 250; //地形大小
[Range(0, 100f)]
public float terrainHeight = 10f; //地形高度
public Material terrainMat; //地形材质

private float xOffset;
private float zOffset;

[Range(1f, 100f)]
public float scaleFatter = 10f;          //地形缩放
[Range(1f, 100f)]
public float offsetFatter = 10f;          //地形偏移

List<Vector3> vertexs = new List<Vector3>();          //顶点列表,存储网格顶点信息
List<int> triangles = new List<int>();          //三角形面列表,存储网格三角形信息
float[,] perlinNoise;          //存储每个顶点的高度值

Vector3[] terrainNormals;          //存储地形的顶点法线的一维数组
Vector3[,] terrainNormals2D;          //存储地形的顶点法线的二维数组
#endregion 
//___________________________________________________________________________
#region Grass Data
[Range(0, 100)]
public int grassRowCount = 50;          //草根集,定义草的广度
[Range(1, 1000)]
public int grassCountPerPatch = 100;          //定义每一堆 草根集 的草密度
public Material grassMat;           //草的材质
public Mesh grassMesh;          //草的网格
List<Vector3> grassVerts = new List<Vector3>();          //存储草的顶点

Vector3[] grassNormals;          //存储草的顶点法线
List<Vector3> grassNormalList = new List<Vector3>();          //存储草的顶点法线列表
#endregion

void Start()
{
    xOffset = transform.position.x;
    zOffset = transform.position.z;
    terrainNormals = new Vector3[terrainSize * terrainSize];//顶点法线数组容量250*250
    terrainNormals2D = new Vector3[terrainSize, terrainSize];//2D顶点法线数组容量250*250
    perlinNoise = new float[terrainSize, terrainSize];//顶点高度数组容量250*250
    GenerateTerrain();//生成地形

    GenerateGrassArea(grassRowCount, grassCountPerPatch);//生成草地(广度,密度)

    
}

void CreateVertsAndTris()
{
    //遍历每一个顶点,并用列表 vertexs 和 triangles 存储
    for (int i = 0; i < terrainSize; i++)
    {
        for (int j = 0; j < terrainSize; j++)
        {
            float noiseHeight = GeneratePerlinNoise(i, j);//顶点随机高度
            perlinNoise[i, j] = noiseHeight;//该坐标下的顶点高度存入数组

            vertexs.Add(new Vector3(i, noiseHeight * terrainHeight, j));//顶点坐标(x,y,z)

            //不算上坐标轴的顶点
            if (i == 0 || j == 0)
                continue;

            //每三个顶点作为一个索引建立三角形
            triangles.Add(terrainSize * i + j);
            triangles.Add(terrainSize * i + j - 1);
            triangles.Add(terrainSize * (i - 1) + j - 1);
            triangles.Add(terrainSize * (i - 1) + j - 1);
            triangles.Add(terrainSize * (i - 1) + j);
            triangles.Add(terrainSize * i + j);
        }
    }

    //清空grassVerts的数据    
    grassVerts.Clear();
}

//生成地形高度的随机 Perlin 值
float GeneratePerlinNoise(int i, int j)
{
    float xCoord = (float)(i + xOffset) / terrainSize * scaleFatter + offsetFatter;
    float zCoord = (float)(j + zOffset) / terrainSize * scaleFatter + offsetFatter;

    return Mathf.PerlinNoise(xCoord, zCoord);
}

//生成地形网格数据
void GenerateTerrain()
{
    CreateVertsAndTris();

    //计算UV(二维向量-顶点坐标作为法线方向)
    Vector2[] uvs = new Vector2[vertexs.Count];
    for (int i = 0; i < vertexs.Count; i++)
    {
        uvs[i] = new Vector2(vertexs[i].x, vertexs[i].z);
    }

    //添加一个 MyTerrain 的物体,并添加 MeshFilter / MeshRenderer 两个组件
    //MeshFilter 存储物体的网格信息
    //MeshRenderer 负责接收这些信息并把这些信息渲染出来
    GameObject Myterrain = new GameObject("Terrain0");
    Myterrain.transform.position = this.gameObject.transform.position;
    Myterrain.AddComponent<MeshFilter>();
    MeshRenderer renderer = Myterrain.AddComponent<MeshRenderer>();
    //开启地面的阴影投射和接受
    renderer.receiveShadows = true;
    renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
    //添加Mesh Collider
    MeshCollider collider = Myterrain.AddComponent<MeshCollider>();

    //添加材质
    renderer.sharedMaterial = terrainMat;

    //创建一个 Mesh 网格
    Mesh groundMesh = new Mesh//网格构造函数
    {
        //输入网格顶点数据
        vertices = vertexs.ToArray(),
        //输入网格三角面数据
        triangles = triangles.ToArray(),
        uv = uvs
    };

    //为了得到正确的光照需要重新计算得到正确的法线信息
    groundMesh.RecalculateNormals();
    terrainNormals = groundMesh.normals;

    //将存储地形法线数组从一维数组转为二维,便于索引
    for (int i = 0; i < terrainSize; i++)
    {
        for (int j = 0; j < terrainSize; j++)
        {
            terrainNormals2D[i, j] = terrainNormals[i * terrainSize + j];
        }
    }
    //网格赋值到渲染器/碰撞体
    Myterrain.GetComponent<MeshFilter>().mesh = groundMesh;
    collider.sharedMesh = groundMesh;
}

void GenerateGrassArea(int rowCount, int perPatchSize)
{
    //最大顶点数为 65000
    List<int> indices = new List<int>();
    for (int i = 0; i < 65000; i++)
    {
        indices.Add(i);
    }

    //初始位置
    Vector3 currentPos = transform.position;
    //草根集 每一次循环偏移的距离
    Vector3 patchSize = new Vector3(terrainSize / rowCount, 0, terrainSize / rowCount);

    //每一堆 草根集 进行循环
    for (int i = 0; i < rowCount; i++)
    {
        for (int j = 0; j < rowCount; j++)
        {
            GenerateGrass(currentPos, patchSize, perPatchSize);
            currentPos.x += patchSize.x;
        }
        currentPos.x = transform.position.x;
        currentPos.z += patchSize.z;
    }

    //生成 GrassLayerGruop 来成为父级管理物理
    GameObject grassLayerGroup1 = new GameObject("GrassLayerGroup1");
    //生成 GrassLayer 物体来存储草数据
    GameObject grassLayer;
    MeshFilter grassMeshFilter;
    //Mesh grassMesh;
    MeshRenderer grassMeshRenderer;
    int a = 0;

    //当 grassVerts.Count 的数量即草的全部顶点数超过 65000 个时
    //创立多个网格处理
    while (grassVerts.Count > 65000)
    {
        Debug.Log("More65000");
        grassMesh = new Mesh();
        grassMesh.vertices = grassVerts.GetRange(0, 65000).ToArray();
        //存储每个草顶点的法线(当顶点超过 65000个)
        grassNormals = new Vector3[65000];
        grassNormalList.GetRange(0, 65000);
        for (int i = 0; i < 65000; i++)
        {
            grassNormals[i] = grassNormalList[i];
        }

        //设置子网格的索引缓冲区,相关官方文档:https://docs.unity3d.com/ScriptReference/Mesh.SetIndices.html
        //每一个创建的网格的顶点数目不会超过 65000 个
        grassMesh.SetIndices(indices.ToArray(), MeshTopology.Points, 0);

        //创建一个新的 GameObject 来承载这些点
        grassLayer = new GameObject("GrassLayer " + a++);
        grassLayer.transform.SetParent(grassLayerGroup1.transform);
        grassMeshFilter = grassLayer.AddComponent<MeshFilter>();
        grassMeshRenderer = grassLayer.AddComponent<MeshRenderer>();
        //关闭草地的阴影投射和接受
        grassMeshRenderer.receiveShadows = false;
        grassMeshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        grassMeshRenderer.sharedMaterial = grassMat;
        grassMesh.normals = grassNormals;
        grassMeshFilter.mesh = grassMesh;
        //移除前 65000 个顶点
        grassVerts.RemoveRange(0, 65000);
        grassNormalList.RemoveRange(0, 65000);
    }
    #region 草的数量少于6500时
    //当 grassVerts.Count 的数量即草的全部顶点数没有超过 65000 个时
    grassLayer = new GameObject("GrassLayer" + a);
    grassLayer.transform.SetParent(grassLayerGroup1.transform);
    grassMeshFilter = grassLayer.AddComponent<MeshFilter>();
    grassMeshRenderer = grassLayer.AddComponent<MeshRenderer>();
    
    //关闭草地的阴影投射和接受
    grassMeshRenderer.receiveShadows = false;
    grassMeshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
    grassMesh = new Mesh
    {
        vertices = grassVerts.ToArray()
    };

    //存储每个草顶点的法线(当顶点没有超过 65000个)
    grassNormals = new Vector3[grassMesh.vertexCount];
    grassNormalList.GetRange(0, grassMesh.vertexCount);
    for (int i = 0; i < grassMesh.vertexCount; i++)
    {
        grassNormals[i] = grassNormalList[i];
    }
    grassMesh.normals = grassNormals;
    //设立子网格数据
    grassMesh.SetIndices(indices.GetRange(0, grassVerts.Count).ToArray(), MeshTopology.Points, 0);

    grassMeshFilter.mesh = grassMesh;
    grassMeshRenderer.sharedMaterial = grassMat;
    #endregion
}

//生成草
void GenerateGrass(Vector3 vertPos, Vector3 patchSize, int grassCountPerPatch)
{
    //每一堆 草根集 里的草进行循环
    for (int i = 0; i < grassCountPerPatch; i++)
    {
        //Random.value 返回 0~1 之间的随机值
        //得到在两个 草根集 之间的草的随机位置并用索引值
        float randomX = Random.value * patchSize.x;
        float randomZ = Random.value * patchSize.z;

        int indexX = (int)((vertPos.x - transform.position.x) + randomX);
        int indexZ = (int)((vertPos.z - transform.position.z) + randomZ);

        //防止草种出地形
        if (indexX >= terrainSize)
        {
            Debug.Log("Full");
            indexX = (int)terrainSize - 1;
        }

        if (indexZ >= terrainSize)
        {
            Debug.Log("Full");
            indexZ = (int)terrainSize - 1;
        }

        //添加每一个草的顶点位置到 grassVert 列表里
        grassVerts.Add(new Vector3(vertPos.x + randomX, perlinNoise[indexX, indexZ] * terrainHeight, vertPos.z + randomZ));//包括草地Mesh网格顶点高度值

        //添加每一个草的顶点法线到 grassNormalList 列表里
        grassNormalList.Add(terrainNormals2D[indexX, indexZ]);//草地Mesh网格顶点法线,与同坐标的地面网格法线相同
    }
}

}
———————————草地Shader——————————————
Shader "Unlit/Grass+Wind"
{
Properties
{
[HDR]_GrassColor("GrassColor", Color) = (1,1,1,1) //控制草的颜色
_SpecualarColor("SpecularColor", Color) = (1,1,1,1) //控制草的高光颜色
_Specular("_Specular", Range(0, 1)) = 1 //控制草的高光程度
_Gloss("Gloss", Range(0,20)) = 1 //控制草的高光
[HDR]_FresnelColor("FresnelColor", Color) = (1,1,1,1) //控制草的边缘高光颜色
_FresnelPower("FresnelPower", Range(0, 5)) = 1 //控制草的边缘高光程度
_MainTex ("Texture", 2D) = "white" {} //草的颜色贴图
_AlphaTex("AlphaTexture", 2D) = "white" {} //草的透明贴图
_GrassHeight("GrassHeight", Range(0.5, 5)) = 2.5 //控制草的高度
_GrassWidth("GrassWidth", Range(0.001, 0.5)) = 0.05 //控制草的宽度
_BladeForward("BladeForward", Range(0, 2)) = 1 //控制草的弯曲程度

	_WindTex("WindTex", 2D) = "white" {}          //风的采样贴图
    _WindVector("WindVector", Vector) = (1,1,1,0)          //控制风的方向
    _WindTimeScale("WindTimeScale", float) = 1          //控制风的速度
    _WindTexMapSize("WindTexMapSize", float) = 80          //控制风的采样贴图大小
    _WindXZStrength("WindXZStrength", float) = 10          //控制风在草的XZ轴上的偏移
    _WindYStrength("WindYStrength", float) = 10          //控制风在草的Y轴上的偏移          */
}

SubShader
{
    //存在顶点动画,所以要关闭批处理,DisableBatching 设置为 True
    Tags {
        "RenderType" = "TransparentCutout"
        "IgnoreProjector" = "True"
        "Queue" = "AlphaTest"
        "DisableBatching" = "True"
    }

    //设置为双面渲染,关闭背面剔除
    Cull Off
    LOD 100

    Pass
    {
        //设置为前向渲染模式
        Tags { "LightMode" = "ForwardBase" }
        Cull Off
        AlphaToMask On

        CGPROGRAM
        //引入头文件
        #include "UnityCG.cginc"
        #include "Lighting.cginc"
        #include "AutoLight.cginc"

        //要应用几何着色器必须要将编译目标设置为 4.0 
        #pragma target 4.0
        #pragma multi_compile_fwdbase
        #pragma vertex vert
        #pragma fragment frag
        //定义几何着色器
        #pragma geometry geom

        fixed4 _GrassColor;
        fixed4 _SpecualarColor;
        fixed _Specular;
        float _Gloss;
        fixed4 _FresnelColor;
        half _FresnelPower;
        sampler2D _MainTex;
        float4 _MainTex_ST;
        sampler2D _AlphaTex;
        fixed _GrassHeight;
        fixed _GrassWidth;
		fixed _BladeForward;

		sampler2D _WindTex;
        float4 _WindTex_ST;
        half4 _WindVector;
        half _WindTimeScale;
        float _WindTexMapSize;
        half _WindXZStrength;
        half _WindYStrength;

        struct a2v {
            float4 pos : POSITION;
            float3 normal : NORMAL;
            float2 uv : TEXCOORD0;
        };

        //顶点着色器传给几何着色器的数据结构
        struct v2g {
            float4 pos : POSITION;
            float3 normal : NORMAL;
            float2 uv : TEXCOORD0;
        };

        //几何着色器传给片元着色器的数据结构
        struct g2f {
            float4 pos : SV_POSITION;
            float3 normal : NORMAL;
            float2 uv : TEXCOORD0;
            float3 worldPos : TEXCOORD1;
        };

		static const float oscillateDelta = 0.05;

        //顶点着色器
        //直接将从网格得到的数据传给传入几何着色器的结构体 v2g
        v2g vert(a2v v) {
            v2g o;
            o.pos = v.pos;
            o.normal = v.normal;
            o.uv = v.uv;
            return o;
        }

        //创建 CreatG2fOut() 函数
        //初始化从几何着色器传入片元着色器的结构体 g2f
        g2f CreatG2fOut() {
            g2f output;
            output.pos = float4(0, 0, 0, 0);
            output.normal = float3(0, 0, 0);
            output.uv = float2(0, 0);
            output.worldPos = float3(0, 0, 0);
            return output;
        }

        g2f GetVertex(float4 pos, float3 normal, float2 uv) {
            g2f output;

            output.pos = UnityObjectToClipPos(pos);    
            output.normal = UnityObjectToWorldNormal(normal);
            output.uv = uv;
            output.worldPos = UnityObjectToWorldDir(pos);

            return output;
        }

        //几何着色器
        [maxvertexcount(30)]//限制几何着色器输出的最大顶点数目。每当输入一个图元,几何着色器可以输出 0~N 个图元。不论是什么结构的图元都是由顶点构成的,而这个语句就是用来限制输出最大的顶点数量(只要小于等于这个数量就可以,多余的顶点会被剔除)
        void geom(point v2g points[1], inout TriangleStream<g2f> triStream) {

            //顶点着色器输入的顶点位置
            float4 root = points[0].pos;

            //生成一个伪随机数
            float random = sin(UNITY_HALF_PI * frac(root.x) + UNITY_HALF_PI * frac(root.z));
            //给每根草的长宽加上这个随机值,我们希望草的宽度不要太宽或者太窄
            _GrassWidth = _GrassWidth + (random / 50);
            _GrassHeight = _GrassHeight + (random / 5);

            //设置草的网格顶点一共有12个
            const int vertexCount = 12;

            //创建12个 g2f 输出数组
            g2f v[vertexCount] = {
                CreatG2fOut(), CreatG2fOut(), CreatG2fOut(), CreatG2fOut(),
                CreatG2fOut(), CreatG2fOut(), CreatG2fOut(), CreatG2fOut(),
                CreatG2fOut(), CreatG2fOut(), CreatG2fOut(), CreatG2fOut()
            };

            //初始化每个顶点的位置 pos 和 uv
            float4 pos = float4(0, 0, 0, 0);
            float2 uv = float2(0, 0);

            //顶点的 UV 在竖直方向上的当前值和偏移值
            float currentV = 0;
            float offsetV = 1.0 / (vertexCount / 2 - 1);

            //顶点的 y 坐标在竖直方向上的当前值的偏移值
            float currentVertexHeight = 0;
            float currentHeightOffset = 0;
            float verticalEff = 0;
			
			//BlendCood
			//让草绕着自身的 y 轴进行旋转
            //生成一个随机角度
            fixed randomAngle = frac(sin(root.x)*10000.0) * UNITY_HALF_PI;

            //根据矩阵旋转的定理,分别创建旋转矩阵
            //平移矩阵,先将所有点平移到原点
            float4x4 firstTransformMatrix = float4x4(
                1.0, 0.0, 0.0, -root.x,
                0.0, 1.0, 0.0, -root.y,
                0.0, 0.0, 1.0, -root.z,
                0.0, 0.0, 0.0, 1.0
                );

            //旋转矩阵
            float4x4 rotateMatrix = float4x4(
                cos(randomAngle), 0, sin(randomAngle), 0,
                0, 1, 0, 0,
                -sin(randomAngle), 0, cos(randomAngle), 0,
                0, 0, 0, 1
                );

            //再平移回去
            float4x4 lastTransformMatrix = float4x4(
                1.0, 0.0, 0.0, root.x,
                0.0, 1.0, 0.0, root.y,
                0.0, 0.0, 1.0, root.z,
                0.0, 0.0, 0.0, 1.0
                );
				//BlendCood

            //进行生成全部草顶点的循环
            for (int i = 0; i < vertexCount; i++)
            {
                //fmod(a,b) 返回 a 除 b 的余数
                //如果返回值为偶数,顶点 UV 坐标均为(0,V)
                if (fmod(i, 2) == 0) {
                    pos = float4(root.x - _GrassWidth, root.y + currentVertexHeight, root.z, 1);
                    uv = fixed2(0, currentV) * _MainTex_ST.xy + _MainTex_ST.zw;
                }
                else {
                    pos = float4(root.x + _GrassWidth, root.y + currentVertexHeight, root.z, 1);
                    uv = fixed2(1, currentV) * _MainTex_ST.xy + _MainTex_ST.zw;

                    currentV += offsetV;
                    currentVertexHeight += currentV * _GrassHeight;
                }
				 //对顶点 XZ 轴进行偏移
                float2 randomDir = float2(sin((random * 15)), sin((random * 10)));
                float2 forward = (sin((root.x * 10 + root.z / 5) * random)* verticalEff + randomDir * sin((random * 15)))* verticalEff;
                pos.xz += forward * _BladeForward;
                if (fmod(i, 2) == 1) {
                    verticalEff += offsetV;
                }

                //对顶点 Y 轴进行旋转
                //pos = mul(lastTransformMatrix, mul(rotateMatrix, mul(firstTransformMatrix, pos)));

                 //对顶点 Y 轴进行旋转
                pos = mul(lastTransformMatrix, mul(rotateMatrix, mul(firstTransformMatrix, pos)));
				
				/*/风随机偏移
				float2 wind = float2(sin(_Time.x * UNITY_PI * 5), sin(_Time.x * UNITY_PI * 5));
				wind.x += (sin(_Time.x + root.x / 25) + sin((_Time.x + root.x / 15) + 50)) * 0.5;
				wind.y += cos(_Time.x + root.z / 80);
				wind *= lerp(0.7, 1.0, 1.0 - random);

				float oscillationStrength = 2.5f;
				float sinSkewCoeff = random;
				float lerpCoeff = (sin(oscillationStrength * _Time.x + sinSkewCoeff) + 1.0) / 2;
				float2 leftWindBound = wind * (1.0 - oscillateDelta);
				float2 rightWindBound = wind * (1.0 + oscillateDelta);

				wind = lerp(leftWindBound, rightWindBound, lerpCoeff);

				float randomAngle = lerp(-UNITY_PI, UNITY_PI, random);
				float randomMagnitude = lerp(0, 1., random);
				float2 randomWindDir = float2(sin(randomAngle), cos(randomAngle));
				wind += randomWindDir * randomMagnitude;

				float windForce = length(wind);

				pos.xz += wind.xy * verticalEff;
				pos.y -= windForce * verticalEff * 0.8;

				pos = UnityObjectToClipPos(pos);

				if (fmod(i, 2) == 1) {

					verticalEff += offsetV;
				}*/
                //--风
                //将世界坐标下的风的方向转化为局部坐标
                float4 localWindDir = normalize(mul(unity_WorldToObject, _WindVector));
                //控制风速(实际上为采样 uv 的移动速度)
                float time = (_Time.y)*(_WindTimeScale);
                //对风贴图进行采样
                half4 rootWorldPos = mul(unity_ObjectToWorld, root);
                //windmutation 一直在 0~1 之间变化 
                float windmutation = 1 - tex2Dlod(_WindTex, float4(rootWorldPos.x / _WindTexMapSize + time, rootWorldPos.z / _WindTexMapSize, 0, 0)).g;
                //sin(time + windmutation * 10) * cos(time * 2 / 3 + 1 + windmutation * 10) -1~1
                //localWindDir.xz 控制风的方向
                //clamp(uv.y - 0.1, 0, 1) UV.y 范围在 0.1 以下的顶点不发生移动 
                //xz 轴上的偏移
                half2 xzOffset = sin(time + windmutation * 10) * cos(time * 2 / 3 + 1 + windmutation * 10) * localWindDir.xz * clamp(uv.y - 0.1, 0, 1);
                pos.xz += xzOffset * _WindXZStrength;
                //根据 XZ 轴上的偏移算出在 Y 轴上
                //直角三角形定理
                //Y轴的偏移
                half yOffset = pos.y - sqrt(pos.y * pos.y - (xzOffset.x * xzOffset.x + xzOffset.y * xzOffset.y));
                pos.y -= yOffset * _WindYStrength * clamp(uv.y - 0.35, 0, 1);
				
                //pos.xz += sin(_Time.y * _WindTimeScale) * uv.y;

                v[i] = GetVertex(pos, points[0].normal, uv);


            }

            //inout TriangleStream<g2f> triStream 输出三角形,即三个顶点数据
            //将每三个顶点转化为三角形输出到片元着色器
            for (int p = 0; p < (vertexCount - 2); p++)
            {
                //triStream.Append(vertex); 该方法将输入的三个顶点自动构建成三角形
                triStream.Append(v[p]);
                triStream.Append(v[p + 2]);
                triStream.Append(v[p + 1]);
            }
        }

        //片元着色器
        //简单的 Blin-Phong 光照模型
        float4 frag(g2f i) : SV_Target{

            //对_MainTex纹理和_AlphaTex纹理进行采样
            fixed4 texColor = tex2D(_MainTex, i.uv);
            fixed alpha = tex2D(_AlphaTex, i.uv).a;

            //将法线归一化
            float3 worldNormal = normalize(i.normal);
            float3 worldSpecNormal = worldNormal;
            worldNormal = worldNormal * 0.5 + 0.5;

            //得到环境光
            fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
            //得到世界空间下光照方向
            fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

            //Diffuse 漫反射颜色
            fixed NdotL = saturate(dot(worldNormal, worldLightDir));
            fixed3 diffuse = _LightColor0.rgb * NdotL;

            //Specular 高光颜色
            //得到世界空间下的视线方向
            fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
            //得到半角向量
            fixed3 halfDir = normalize(worldLightDir + worldViewDir);
            fixed3 NdotH = saturate(dot(worldSpecNormal, halfDir));
            float spec = pow(NdotH, _Specular * 128.0) * _Gloss;
            fixed3 specular = _SpecualarColor * _LightColor0.rgb * spec;

            //Fresnel
            fixed fresnel = saturate(1 - dot(worldSpecNormal, worldViewDir));
            //fresnel = clamp(fresnel - 0.2, 0, 1);
            fresnel = pow(fresnel, _FresnelPower) * clamp(i.uv.y - 0.5, 0, i.uv.y);
            fixed3 fresnelColor = fresnel * _FresnelColor;

            //得到并输出最终颜色
            fixed3 finalColor = ambient + diffuse + specular;
            return fixed4(texColor * _GrassColor.rgb * finalColor, alpha);
            //return fixed4(worldNormal, alpha);
        }
        ENDCG
    }
}
FallBack "Diffuse"

}