private static List<VertexData> splitVertices(Mesh mesh, List<VertexData> vertexData, boolean splitMirrored) {
        
        int nbVertices = mesh.getBuffer(Type.Position).getNumElements();
        List<VertexData> newVertices = new ArrayList<>();
        Map<Integer, Integer> indexMap = new HashMap<>();
        FloatBuffer normalBuffer = mesh.getFloatBuffer(Type.Normal);

        for (int i = 0; i < vertexData.size(); i++) {
            ArrayList<TriangleData> triangles = vertexData.get(i).triangles;
            Vector3f givenNormal = new Vector3f();
            populateFromBuffer(givenNormal, normalBuffer, i);

            ArrayList<TriangleData> trianglesUp = new ArrayList<>();
            ArrayList<TriangleData> trianglesDown = new ArrayList<>();
            for (int j = 0; j < triangles.size(); j++) {
                TriangleData triangleData = triangles.get(j);
                if (parity(givenNormal, triangleData.normal) > 0) {
                    trianglesUp.add(triangleData);
                } else {
                    trianglesDown.add(triangleData);
                }
            }

            //if the vertex has triangles with opposite parity it has to be split
            if (!trianglesUp.isEmpty() && !trianglesDown.isEmpty()) {
                log.log(Level.FINE, "Splitting vertex {0}", i);
                //assigning triangle with the same parity to the original vertex
                vertexData.get(i).triangles.clear();
                vertexData.get(i).triangles.addAll(trianglesUp);

                //creating a new vertex
                VertexData newVert = new VertexData();
                //assigning triangles with opposite parity to it
                newVert.triangles.addAll(trianglesDown);

                newVertices.add(newVert);
                //keep vertex index to fix the index buffers later
                indexMap.put(nbVertices, i);
                for (TriangleData tri : newVert.triangles) {
                    for (int j = 0; j < tri.index.length; j++) {
                        if (tri.index[j] == i) {
                            tri.index[j] = nbVertices;
                        }
                    }
                }
                nbVertices++;
            }
        }

        if (!newVertices.isEmpty()) {

            //we have new vertices, we need to update the mesh's buffers.
            for (Type type : VertexBuffer.Type.values()) {
                //skip tangent buffer as we're gonna overwrite it later
                if (type == Type.Tangent || type == Type.BindPoseTangent) {
                    continue;
                }
                VertexBuffer vb = mesh.getBuffer(type);
                //Some buffer (hardware skinning ones) can be there but not 
                //initialized, they must be skipped. 
                //They'll be initialized when Hardware Skinning is engaged
                if (vb == null || vb.getNumComponents() == 0) {
                    continue;
                }

                Buffer buffer = vb.getData();
                //IndexBuffer has special treatment, only swapping the vertex indices is needed
                if (type == Type.Index) {
                    boolean isShortBuffer = vb.getFormat() == VertexBuffer.Format.UnsignedShort;
                    for (VertexData vertex : newVertices) {
                        for (TriangleData tri : vertex.triangles) {
                            for (int i = 0; i < tri.index.length; i++) {
                                if (isShortBuffer) {
                                    ((ShortBuffer) buffer).put(tri.triangleOffset + i, (short) tri.index[i]);
                                } else {
                                    ((IntBuffer) buffer).put(tri.triangleOffset + i, tri.index[i]);
                                }
                            }
                        }
                    }
                    vb.setUpdateNeeded();
                } else {
                    //copy the buffer in a bigger one and append nex vertices to the end
                    Buffer newVerts = VertexBuffer.createBuffer(vb.getFormat(), vb.getNumComponents(), nbVertices);
                    if (buffer != null) {
                        buffer.rewind();
                        bulkPut(vb.getFormat(), newVerts, buffer);

                        int index = vertexData.size();
                        newVerts.position(vertexData.size() * vb.getNumComponents());
                        for (int j = 0; j < newVertices.size(); j++) {
                            int oldInd = indexMap.get(index);
                            for (int i = 0; i < vb.getNumComponents(); i++) {
                                putValue(vb.getFormat(), newVerts, buffer, oldInd * vb.getNumComponents() + i);
                            }
                            index++;
                        }
                        vb.updateData(newVerts);
                        //destroy previous buffer as it's no longer needed
                        destroyDirectBuffer(buffer);
                    }
                }
            }
            vertexData.addAll(newVertices);

            mesh.updateCounts();
        }

        return vertexData;
    }
A private constructor to inhibit instantiation of this class.
jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java