private bool AddBlendShape(
        string targetShapeName,
        string sourceShapeName,
        float magnitudeScale,
        float yScale,
        bool keepLeft,
        bool keepRight,
        bool keepUpward,
        bool keepDownward,
        ScaleNormalization scaleNormalization,
        int onlyIncludeThisSubmesh,
        int onlyExcludeThisSubmesh)
    {
        if (mesh.GetBlendShapeIndex(targetShapeName) >= 0)
        {
            // Blend shape already exists. Don't try to add it again.
            return(false);
        }

        Vector3[] deltaVertices = new Vector3[mesh.vertexCount];
        Vector3[] deltaNormals  = new Vector3[mesh.vertexCount];
        Vector3[] deltaTangents = new Vector3[mesh.vertexCount];

        // Find the source shape index.
        int shapeIndex = FindShapeIndex(sourceShapeName);

        if (shapeIndex < 0)
        {
            // Failed to find the source shape.
            return(false);
        }

        // Copy across the keyframes in the blendshape (most have 1 keyframe).
        int frameCount = mesh.GetBlendShapeFrameCount(shapeIndex);

        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
        {
            float frameWeight = mesh.GetBlendShapeFrameWeight(shapeIndex, frameIndex);
            mesh.GetBlendShapeFrameVertices(shapeIndex, frameIndex, deltaVertices, deltaNormals, deltaTangents);
            AdjustBlendShape(deltaVertices, deltaNormals, deltaTangents, magnitudeScale, yScale, keepLeft, keepRight, keepUpward, keepDownward, scaleNormalization, onlyIncludeThisSubmesh, onlyExcludeThisSubmesh);
            mesh.AddBlendShapeFrame(targetShapeName, frameWeight, deltaVertices, deltaNormals, deltaTangents);
        }

        return(true);
    }
    private void AdjustBlendShape(
        Vector3[] deltaVertices,
        Vector3[] deltaNormals,
        Vector3[] deltaTangents,
        float magnitudeScale,
        float yScale,
        bool keepLeft,
        bool keepRight,
        bool keepUpward,
        bool keepDownward,
        ScaleNormalization scaleNormalization,
        int onlyIncludeThisSubmesh,
        int onlyExcludeThisSubmesh)
    {
        Vector3[] vertices = mesh.vertices;
        Bounds    bounds   = mesh.bounds;
        float     minX     = bounds.center.x - bounds.extents.x;
        float     maxX     = bounds.center.x + bounds.extents.x;

        for (int i = 0; i < mesh.vertexCount; i++)
        {
            Vector3 v = vertices[i];
            Debug.Log("v=" + V3ToString(v) + "  dv=" + V3ToString(deltaVertices[i]));

            bool zeroIt = false;

            if (v.x > 0.0f && !keepRight)
            {
                zeroIt = true;
                Debug.Log("ZA");
            }

            if (v.x < 0.0f && !keepLeft)
            {
                zeroIt = true;
                Debug.Log("ZB");
            }

            if (deltaVertices[i].y > 0.0f && !keepUpward)
            {
                zeroIt = true;
                Debug.Log("ZC");
            }

            if (deltaVertices[i].y < 0.0f && !keepDownward)
            {
                zeroIt = true;
                Debug.Log("ZD");
            }

            if (zeroIt)
            {
                deltaVertices[i] = Vector3.zero;
                deltaNormals[i]  = Vector3.zero;
                deltaTangents[i] = Vector3.zero;
            }
            else
            {
                Debug.Log("KEEP");

                // Adjust the scaling factor based on position on face.
                float scaleFactor = magnitudeScale;
                switch (scaleNormalization)
                {
                case ScaleNormalization.LeftToRight:
                {
                    float localScale = (v.x - minX) / (maxX - minX);
                    Debug.Log("1.v.x=" + v.x + ", minX=" + minX + ", maxX=" + maxX + ", lscale=" + localScale);
                    if (localScale < 0.0f)
                    {
                        localScale = 0.0f;
                    }
                    if (localScale > 1.0f)
                    {
                        localScale = 1.0f;
                    }
                    scaleFactor *= localScale;
                    break;
                }

                case ScaleNormalization.RightToLeft:
                {
                    float localScale = (v.x - minX) / (maxX - minX);
                    Debug.Log("2.v.x=" + v.x + ", minX=" + minX + ", maxX=" + maxX + ", lscale=" + localScale);
                    if (localScale < 0.0f)
                    {
                        localScale = 0.0f;
                    }
                    if (localScale > 1.0f)
                    {
                        localScale = 1.0f;
                    }
                    scaleFactor *= (1.0f - localScale);
                    break;
                }

                case ScaleNormalization.ZeroAtCenter:
                {
                    float localScale = v.x / (maxX / 4.0f);
                    Debug.Log("localScale = " + localScale);
                    Debug.Log("2.v.x=" + v.x + ", minX=" + minX + ", maxX=" + maxX + ", lscale=" + localScale);
                    if (localScale < 0.0f)
                    {
                        localScale = -localScale;
                    }
                    if (localScale > 1.0f)
                    {
                        localScale = 1.0f;
                    }
                    Debug.Log("final localScale = " + localScale);
                    scaleFactor *= localScale;
                    Debug.Log("scaleFactor= " + scaleFactor);
                    break;
                }
                }

                // Multiply in magnitude scale.
                deltaVertices[i] *= scaleFactor;
                deltaNormals[i]  *= scaleFactor;
                deltaTangents[i] *= scaleFactor;

                // Multiple in Y scale (e.g. scale = -1 to invert)
                deltaVertices[i].y *= yScale;
                deltaNormals[i].y  *= yScale;
                deltaTangents[i].y *= yScale;
            }
        }

        if (onlyIncludeThisSubmesh >= 0)
        {
            // Set everything to zero not in requested submesh
            UnityEngine.Rendering.SubMeshDescriptor smd = mesh.GetSubMesh(onlyIncludeThisSubmesh);
            for (int i = 0; i < smd.firstVertex; i++)
            {
                deltaVertices[i] = Vector3.zero;
                deltaNormals[i]  = Vector3.zero;
                deltaTangents[i] = Vector3.zero;
            }
            for (int i = smd.firstVertex + smd.vertexCount; i < mesh.vertexCount; i++)
            {
                deltaVertices[i] = Vector3.zero;
                deltaNormals[i]  = Vector3.zero;
                deltaTangents[i] = Vector3.zero;
            }
        }

        if (onlyExcludeThisSubmesh >= 0)
        {
            // Set everything to zero in requested submesh
            UnityEngine.Rendering.SubMeshDescriptor smd = mesh.GetSubMesh(onlyExcludeThisSubmesh);
            for (int i = smd.firstVertex; i < smd.firstVertex + smd.vertexCount; i++)
            {
                deltaVertices[i] = Vector3.zero;
                deltaNormals[i]  = Vector3.zero;
                deltaTangents[i] = Vector3.zero;
            }
        }
    }