While doing one Unity3d project, i was need to make part of mesh subdivided. Not whole mesh, what is easy, but only few regions, defined by grayscale bitmap and threshold. After some googling, i found some nice publishings about this

Iterative Process to Improve Simple Adaptive Subdivision Surfaces Method with Butterfly Scheme
Adaptive Subdivision Schemes for Triangular Meshes
Incremental Subdivision for Triangle Meshes

and code below



private List<int> finalTriangles; // vertex indexes
private List<Vector2> finalUVs; // uv coords
private List<Vector3> finalVertices; // vertex coords
private Dictionary<uint, int> newVertices; // temp list for new vertices

// how to use
private void updateMesh(Mesh originalMesh)
    {
		newVertices = new Dictionary<uint, int>();
		finalVertices = new List<Vector3>(originalMesh.vertices);
		finalUVs = new List<Vector2>(originalMesh.uv);
		finalTriangles = new List<int>(originalMesh.triangles);

        IterativeSubdiv(SubdivThreshold); // 0.0 - 1.0
    }


private void IterativeSubdiv(float threshold)
    {

        var triangles = new List<int>();

        var noSubTriangles = new List<int>();
        var subdivided = new List<int>();
        var notSubdivided = new List<int>();

        for (int t = 0; t < finalTriangles.Count; t += 3)
        {
            int v1 = finalTriangles[t + 0];
            int v2 = finalTriangles[t + 1];
            int v3 = finalTriangles[t + 2];

            if (needSubdivision(v1, v2, v3, threshold))
            {
                 int v12 = GetNewVertex(v1, v2);
                int v23 = GetNewVertex(v2, v3);
                int v31 = GetNewVertex(v3, v1);
                triangles.Add(v1);
                triangles.Add(v12);
                triangles.Add(v31);
                triangles.Add(v2);
                triangles.Add(v23);
                triangles.Add(v12);
                triangles.Add(v3);
                triangles.Add(v31);
                triangles.Add(v23);
                triangles.Add(v12);
                triangles.Add(v23);
                triangles.Add(v31);
                subdivided.Add(t);
            } else
            {
                noSubTriangles.Add(t);
            }
        }
        var noSubTriangles2 = new List<int>();

        for (int t = 0; t < noSubTriangles.Count; t++)
        {
            int v1 = finalTriangles[noSubTriangles[t] + 0];
            int v2 = finalTriangles[noSubTriangles[t] + 1];
            int v3 = finalTriangles[noSubTriangles[t] + 2];

            int cnt = checkEdge(v1, v2, newVertices) ? 1 : 0;
            cnt += checkEdge(v2, v3, newVertices) ? 1 : 0;
            cnt += checkEdge(v3, v1, newVertices) ? 1 : 0;

             if (cnt == 3 || cnt == 2)
            {
                int v12 = GetNewVertex(v1, v2);
                int v23 = GetNewVertex(v2, v3);
                int v31 = GetNewVertex(v3, v1);
                triangles.Add(v1);
                triangles.Add(v12);
                triangles.Add(v31);
                triangles.Add(v2);
                triangles.Add(v23);
                triangles.Add(v12);
                triangles.Add(v3);
                triangles.Add(v31);
                triangles.Add(v23);
                triangles.Add(v12);
                triangles.Add(v23);
                triangles.Add(v31);
                subdivided.Add(noSubTriangles[t]);
            } else
            {
                noSubTriangles2.Add(noSubTriangles[t]);
            }
        }

        for (int t = 0; t < noSubTriangles2.Count; t++)
        {
            int v1 = finalTriangles[noSubTriangles2[t] + 0];
            int v2 = finalTriangles[noSubTriangles2[t] + 1];
            int v3 = finalTriangles[noSubTriangles2[t] + 2];

             int cnt1 = checkEdge(v1, v2, newVertices) ? 1 : 0;
            int cnt2 = checkEdge(v2, v3, newVertices) ? 1 : 0;
            int cnt3 = checkEdge(v3, v1, newVertices) ? 1 : 0;

             if ((cnt1 + cnt2 + cnt3) == 3 || (cnt1 + cnt2 + cnt3) == 2)
            {
                 int v12 = GetNewVertex(v1, v2);
                int v23 = GetNewVertex(v2, v3);
                int v31 = GetNewVertex(v3, v1);
                triangles.Add(v1);
                triangles.Add(v12);
                triangles.Add(v31);
                triangles.Add(v2);
                triangles.Add(v23);
                triangles.Add(v12);
                triangles.Add(v3);
                triangles.Add(v31);
                triangles.Add(v23);
                triangles.Add(v12);
                triangles.Add(v23);
                triangles.Add(v31);
                subdivided.Add(noSubTriangles2[t]);
            } else if ((cnt1 + cnt2 + cnt3) == 1)
            {
                 if (cnt1 == 1)
                {
                    int n = GetNewVertex(v1, v2);
                    triangles.Add(v1);
                    triangles.Add(n);
                    triangles.Add(v3);
                    triangles.Add(n);
                    triangles.Add(v2);
                    triangles.Add(v3);
                } else if (cnt2 == 1)
                {
                    int n = GetNewVertex(v2, v3);
                    triangles.Add(v1);
                    triangles.Add(v2);
                    triangles.Add(n);
                    triangles.Add(v1);
                    triangles.Add(n);
                    triangles.Add(v3);
                } else
                {
                    int n = GetNewVertex(v3, v1);
                    triangles.Add(v1);
                    triangles.Add(v2);
                    triangles.Add(n);
                    triangles.Add(v2);
                    triangles.Add(v3);
                    triangles.Add(n);
                }
                subdivided.Add(noSubTriangles2[t]);
            } else
            {
                // pass triangle
                //int a = GetNewVertex(v1, v1, vertices, uvs, newVertices, uvIn);
                //int b = GetNewVertex(v2, v2, vertices, uvs, newVertices, uvIn);
                //int c = GetNewVertex(v3, v3, vertices, uvs, newVertices, uvIn);
                triangles.Add(v1);
                triangles.Add(v2);
                triangles.Add(v3);
                notSubdivided.Add(noSubTriangles2[t]);
            }
        }

        var subCountNew = 0;
        var newDict = new Dictionary<int, bool>();
        for (var i = 0; i < subdivided.Count; i++)
        {
            if (!subdividedThisFrame.ContainsKey(subdivided[i])) subCountNew++;
            newDict.Add(subdivided[i], true);
        }

        var subCountOld = 0;
        for (var i = 0; i < notSubdivided.Count; i++)
        {
            if (subdividedThisFrame.ContainsKey(notSubdivided[i])) subCountOld++;
            //newDict.Add(notSubdivided[i], true);
        }

        subdividedThisFrame = newDict;
        NewSubdividedCount = subCountNew + subCountOld;
        //Debug.Log(NewSubdividedCount + " " + subCountNew + " " + subCountOld);

      //  colliderMesh.triangles = new int[0];
      //  colliderMesh.vertices = vertices.ToArray();
      //  colliderMesh.uv = uvs.ToArray();
      //  colliderMesh.triangles = triangles.ToArray();
    	finalTriangles = triangles;
	}

 private bool needSubdivision(int v1, int v2, int v3, float threshold)
    {
        var c1b = getColorForVertexFromTexture(finalUVs[v1]);
        var c2b = getColorForVertexFromTexture(finalUVs[v2]);
        var c3b = getColorForVertexFromTexture(finalUVs[v3]);

       return  c1b < threshold || c2b < threshold || c3b < threshold;
    }

private float getColorForVertexFromTexture(Vector2 uv)
    {
        int tx = (int)(TextureForRead.width*uv.x);
        int ty = (int)(TextureForRead.height*uv.y);
        return TextureForRead.GetPixel(tx, ty).grayscale;
    }

 private int GetNewVertex(int i1, int i2)
    {
        uint t1;
        if (i1 >= i2)
        {
            t1 = ((uint)i2 << 16) | (uint)i1;
        } else
        {
            t1 = ((uint)i1 << 16) | (uint)i2;
        }
        if (newVertices.ContainsKey(t1))
            return newVertices[t1];
        // generate vertex:
        int newIndex = finalVertices.Count;
        newVertices.Add(t1, newIndex);

        // calculate new vertex
        finalVertices.Add((finalVertices[i1] + finalVertices[i2])*0.5f);
        finalUVs.Add((finalUVs[i1] + finalUVs[i2])*0.5f);

        return newIndex;
    }