public void Normal_Render(Vector3 vertexScale)
        {
            for (int z = 0; z < mNumPatchesPerSize; ++z)
            {
                for (int x = 0; x < mNumPatchesPerSize; ++x)
                {
                    CGeommPatch patch = GetPatch(x, z);
                    if (null == patch)
                    {
                        continue;
                    }

                    Profiler.BeginSample("NormalRender.Reset");
                    patch.Reset();
                    Profiler.EndSample();

                    Profiler.BeginSample("NormalRender.Render");
                    patch.Render(mHeightData, vertexScale);
                    Profiler.EndSample();

                    Profiler.BeginSample("NormalRender.Present");
                    patch.Present();
                    Profiler.EndSample();
                }
            }
        }
        private bool CanDrawMidVertex(int lod, CGeommPatch neighborPatch)
        {
            bool ret = false;

            if (null == neighborPatch || neighborPatch.mLOD <= lod || !neighborPatch.mbIsVisible)
            {
                ret = true;
            }
            return(ret);
        }
        public void DrawGizoms(Vector3 vertexScale, float gizmosScale, Color gizmosColor)
        {
            Gizmos.color = gizmosColor;

            for (int z = 0; z < mNumPatchesPerSize; ++z)
            {
                for (int x = 0; x < mNumPatchesPerSize; ++x)
                {
                    CGeommPatch patch = GetPatch(x, z);
                    if (null == patch)
                    {
                        continue;
                    }

                    patch.DrawGizoms(mHeightData, vertexScale, gizmosScale);
                }
            }
        }
        public void CLOD_Render(Vector3 vectorScale)
        {
            for (int z = 0; z < mNumPatchesPerSize; ++z)
            {
                for (int x = 0; x < mNumPatchesPerSize; ++x)
                {
                    CGeommPatch patch = GetPatch(x, z);
                    if (null == patch)
                    {
                        continue;
                    }

                    int         curPatchLOD         = patch.mLOD;
                    CGeommPatch leftNeighborPatch   = GetPatch(x - 1, z);
                    CGeommPatch topNeighborPatch    = GetPatch(x, z + 1);
                    CGeommPatch rightNeighborPatch  = GetPatch(x + 1, z);
                    CGeommPatch bottomNeighborPatch = GetPatch(x, z - 1);

                    //需要画左边中间的点
                    patch.mbDrawLeftBorderMid   = CanDrawMidVertex(curPatchLOD, leftNeighborPatch);
                    patch.mbDrawTopBorderMid    = CanDrawMidVertex(curPatchLOD, topNeighborPatch);
                    patch.mbDrawRightBorderMid  = CanDrawMidVertex(curPatchLOD, rightNeighborPatch);
                    patch.mbDrawBottomBorderMid = CanDrawMidVertex(curPatchLOD, bottomNeighborPatch);

                    Profiler.BeginSample("Geomipmapping.Reset");
                    patch.Reset();
                    Profiler.EndSample();

                    if (patch.mbIsVisible)
                    {
                        Profiler.BeginSample("Geomipmapping.RenderPatch");
                        RenderPatch(patch, vectorScale);
                        Profiler.EndSample();
                    }

                    Profiler.BeginSample("Geomipmapping.Present");
                    patch.Present();
                    Profiler.EndSample();
                }
            }
        }
        private void RenderFan(int inPatchX, int inPatchZ, int fanSize, bool drawLeft, bool drawTop, bool drawRight, bool drawBottom,
                               CGeommPatch patch, Vector3 vectorScale)
        {
            if (null == patch)
            {
                return;
            }

            float fHalfSize = fanSize / 2.0f;
            int   iHalfSize = (int)fHalfSize;

            //在Patch里面的顶点位置
            int xCenterInPatchVertexs = (int)inPatchX;
            int zCenterInPatchVertexs = (int)inPatchZ;
            int xLeftInPatchVertexs   = xCenterInPatchVertexs - iHalfSize;
            int zTopInPatchVertexs    = zCenterInPatchVertexs + iHalfSize;
            int xRightInPatchVertexs  = xCenterInPatchVertexs + iHalfSize;
            int zBottomInPatchVertexs = zCenterInPatchVertexs - iHalfSize;

            //相对于Patch中心点的偏移
            int xOffsetFromPatchCentexX = xCenterInPatchVertexs - patch.CenterXInPatch;
            int zOffsetFromPatchCentexZ = zCenterInPatchVertexs - patch.CenterZInPatch;


            //在高度图里面的位置
            float fanCenterRawXInHeight = patch.PatchCenterXInHeight + xOffsetFromPatchCentexX;
            float fanCenterRawZInHeight = patch.PatchCenterZInHeight + zOffsetFromPatchCentexZ;
            float fanLeftRawXInHeight   = fanCenterRawXInHeight - iHalfSize;
            float fanRightRawXInHeight  = fanCenterRawXInHeight + iHalfSize;
            float fanTopRawZInHeight    = fanCenterRawZInHeight + iHalfSize;
            float fanBottomRawZInHeight = fanCenterRawZInHeight - iHalfSize;

            float fTexLeft   = ((float)Mathf.Abs(fanCenterRawXInHeight - fHalfSize) / mHeightData.mSize);
            float fTexBottom = ((float)Mathf.Abs(fanCenterRawZInHeight - fHalfSize) / mHeightData.mSize);
            float fTexRight  = ((float)Mathf.Abs(fanCenterRawXInHeight + fHalfSize) / mHeightData.mSize);
            float fTexTop    = ((float)Mathf.Abs(fanCenterRawZInHeight + fHalfSize) / mHeightData.mSize);

            float fMidX = ((fTexLeft + fTexRight) / 2);
            float fMidZ = ((fTexBottom + fTexTop) / 2);


            stVertexAtrribute centerVertex      = GenerateVertex(GetPatchVertexIndex(xCenterInPatchVertexs, zCenterInPatchVertexs), fanCenterRawXInHeight, fanCenterRawZInHeight, fMidX, fMidZ, vectorScale);
            stVertexAtrribute bottomLeftVertex  = GenerateVertex(GetPatchVertexIndex(xLeftInPatchVertexs, zBottomInPatchVertexs), fanLeftRawXInHeight, fanBottomRawZInHeight, fTexLeft, fTexBottom, vectorScale);
            stVertexAtrribute leftMidVertex     = GenerateVertex(GetPatchVertexIndex(xLeftInPatchVertexs, zCenterInPatchVertexs), fanLeftRawXInHeight, fanCenterRawZInHeight, fTexLeft, fMidZ, vectorScale);
            stVertexAtrribute topLeftVertex     = GenerateVertex(GetPatchVertexIndex(xLeftInPatchVertexs, zTopInPatchVertexs), fanLeftRawXInHeight, fanTopRawZInHeight, fTexLeft, fTexTop, vectorScale);
            stVertexAtrribute topMidVertex      = GenerateVertex(GetPatchVertexIndex(xCenterInPatchVertexs, zTopInPatchVertexs), fanCenterRawXInHeight, fanTopRawZInHeight, fMidX, fTexTop, vectorScale);
            stVertexAtrribute topRightVertex    = GenerateVertex(GetPatchVertexIndex(xRightInPatchVertexs, zTopInPatchVertexs), fanRightRawXInHeight, fanTopRawZInHeight, fTexRight, fTexTop, vectorScale);
            stVertexAtrribute rightMidVertex    = GenerateVertex(GetPatchVertexIndex(xRightInPatchVertexs, zCenterInPatchVertexs), fanRightRawXInHeight, fanCenterRawZInHeight, fTexRight, fMidZ, vectorScale);
            stVertexAtrribute bottomRightVertex = GenerateVertex(GetPatchVertexIndex(xRightInPatchVertexs, zBottomInPatchVertexs), fanRightRawXInHeight, fanBottomRawZInHeight, fTexRight, fTexBottom, vectorScale);
            stVertexAtrribute bottomMidVertex   = GenerateVertex(GetPatchVertexIndex(xCenterInPatchVertexs, zBottomInPatchVertexs), fanCenterRawXInHeight, fanBottomRawZInHeight, fMidX, fTexBottom, vectorScale);


            patch.RenderFan(
                centerVertex,
                bottomLeftVertex,
                leftMidVertex,
                topLeftVertex,
                topMidVertex,
                topRightVertex,
                rightMidVertex,
                bottomRightVertex,
                bottomMidVertex,
                drawLeft,
                drawTop,
                drawRight,
                drawBottom
                );
        }
        public void RenderPatch(CGeommPatch patch, Vector3 vectorScale)
        {
            if (null == patch)
            {
                return;
            }

            int iSize = mPatchSize;

            int iDivisor = mPatchSize - 1;
            int tLOD     = patch.mLOD;

            while (tLOD >= 0)
            {
                iDivisor = iDivisor >> 1;
                tLOD--;
            }

            iSize /= iDivisor;
            int iHalfSize = iSize / 2;

            //Patch是从左往右,从下到上,而不是先中心点开始绘制的
            for (int inPatchZ = iHalfSize; (inPatchZ + iHalfSize) < mPatchSize + 1; inPatchZ += iSize)
            {
                for (int inPatchX = iHalfSize; (inPatchX + iHalfSize) < mPatchSize + 1; inPatchX += iSize)
                {
                    bool bDrawLeft   = false;
                    bool bDrawTop    = false;
                    bool bDrawRight  = false;
                    bool bDrawBottom = false;

                    //最左边的Fan
                    if (inPatchX == iHalfSize)
                    {
                        bDrawLeft = patch.mbDrawLeftBorderMid;
                    }
                    else
                    {
                        bDrawLeft = true;   //如果是内部的Fan,即中点必须画
                    }

                    if (inPatchZ == iHalfSize)
                    {
                        bDrawBottom = patch.mbDrawBottomBorderMid;
                    }
                    else
                    {
                        bDrawBottom = true;   //如果是内部的Fan,即中点必须画
                    }


                    if (inPatchX >= (mPatchSize - 1 - iHalfSize))  //左边括号的那坨东西是代表最后一个顶点
                    {
                        bDrawRight = patch.mbDrawRightBorderMid;
                    }
                    else
                    {
                        bDrawRight = true;   //如果是内部的Fan,即中点必须画
                    }


                    if (inPatchZ >= (mPatchSize - 1 - iHalfSize))
                    {
                        bDrawTop = patch.mbDrawTopBorderMid;
                    }
                    else
                    {
                        bDrawTop = true;   //如果是内部的Fan,即中点必须画
                    }

                    Profiler.BeginSample("Geomipmapping.RenderFan");
                    RenderFan(inPatchX, inPatchZ, iSize, bDrawLeft, bDrawTop, bDrawRight, bDrawBottom, patch, vectorScale);
                    Profiler.EndSample();
                }
            }
        }
        /// <summary>
        /// 每条边有多少个顶点
        /// </summary>
        /// <param name="oneSideVertexPerPatch"></param>
        public void ConfigGeommaping(
            int vertexPerPatch,
            GameObject patchPrefab,
            GameObject patchParent,
            Texture2D colorTexture,
            Texture2D detailTexture)
        {
            if (vertexPerPatch > 0 &&
                mHeightData.IsValid())
            {
                mPatchSize = vertexPerPatch;

                int tDivisor = vertexPerPatch - 1;
                int tLOD     = 0;
                while (tDivisor > 2)
                {
                    tDivisor = tDivisor >> 1;
                    tLOD++;
                }

                mMaxLOD = tLOD;


                //构造材质
                Shader terrainShader = Shader.Find("Terrain/Geomipmapping/TerrainRender");
                if (terrainShader != null)
                {
                    mTerrainMaterial = new Material(terrainShader);
                    if (mTerrainMaterial != null)
                    {
                        mTerrainMaterial.SetTexture("_MainTex", colorTexture);
                        if (detailTexture != null)
                        {
                            mTerrainMaterial.SetTexture("_DetailTex", detailTexture);
                        }
                    }
                }


                for (int z = 0; z < mNumPatchesPerSize; z++)
                {
                    for (int x = 0; x < mNumPatchesPerSize; x++)
                    {
                        GameObject patchGo = GameObject.Instantiate(patchPrefab, Vector3.zero, Quaternion.identity) as GameObject;
                        if (patchGo != null)
                        {
                            patchGo.name = string.Format("{0}_{1:D2}{2:D2}", patchGo.name, x, z);
                            patchGo.transform.SetParent(patchParent.transform);
                        }

                        CGeommPatch patch = new CGeommPatch(
                            x,
                            z,
                            mPatchSize,
                            mMaxLOD,
                            patchGo,
                            mTerrainMaterial
                            );

                        mGeommPatchs.Add(patch);
                    }
                }
            }
        }
        public void UpdatePatch(Camera viewCamera, Vector3 vectorScale, List <float> lodLevels, bool isFrustumCull)
        {
            if (null == viewCamera)
            {
                Debug.LogError("[UpdatePatch]View Camera is Null!");
                return;
            }

            if (null == lodLevels || 0 == lodLevels.Count)
            {
                Debug.LogError("[UpdatePatch]LOD Levels is Null!");
                return;
            }

            Profiler.BeginSample("Geomipmapping.CalculateFrustumPlanes");
            Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(viewCamera);
            Profiler.EndSample();


            for (int z = 0; z < mNumPatchesPerSize; z++)
            {
                for (int x = 0; x < mNumPatchesPerSize; x++)
                {
                    CGeommPatch patch = GetPatch(x, z);
                    if (null == patch)
                    {
                        continue;
                    }

                    bool patchIsVisible = true;
                    if (frustumPlanes != null)
                    {
                        Profiler.BeginSample("Geomipmapping.TestPlanesAABB");
                        patchIsVisible = GeometryUtility.TestPlanesAABB(frustumPlanes, patch.PatchBounds);
                        Profiler.EndSample();
                    }

                    patch.mbIsVisible = patchIsVisible || !isFrustumCull;
                    if (patch.mbIsVisible)
                    {
                        float patchCenterX = patch.PatchCenterXInHeight * vectorScale.x;
                        float patchCenterZ = patch.PatchCenterZInHeight * vectorScale.z;
                        float patchCenterY = mHeightData.GetRawHeightValue(patch.PatchCenterXInHeight, patch.PatchCenterZInHeight) * vectorScale.y;

                        Profiler.BeginSample("Geomipmapping.CalcDistance");
                        patch.mDistance = Mathf.Sqrt(
                            Mathf.Pow(viewCamera.transform.position.x - patchCenterX, 2) +
                            Mathf.Pow(viewCamera.transform.position.y - patchCenterY, 2) +
                            Mathf.Pow(viewCamera.transform.position.z - patchCenterZ, 2)
                            );
                        Profiler.EndSample();

                        patch.mLOD = mMaxLOD;
                        for (int i = 0; i < lodLevels.Count; ++i)
                        {
                            float lodDistance = lodLevels[i];
                            if (patch.mDistance < lodDistance)
                            {
                                patch.mLOD = i;
                                break;
                            }
                        }
                    }
                }
            }
        }