/**
         * @param pDieMesh a mesh of a Die to process
         * @return a list of DieAreas based on all the triangles of the FIRST submesh.
         */
        private static List <DieArea> convertMeshTrianglesToDieAreaInstances(Mesh pDieMesh)
        {
            List <DieArea> result = new List <DieArea>();

            //get all mesh data
            int[] triangleIndices       = pDieMesh.GetTriangles(0);
            int   triangleIndicesLength = triangleIndices.Length;

            Vector3[] vertices = pDieMesh.vertices;
            Vector3[] normals  = pDieMesh.normals;

            //convert all mesh data into a list of areas
            for (int i = 0; i < triangleIndicesLength; i += 3)
            {
                DieArea area = new DieArea();

                int index1 = triangleIndices[i];
                int index2 = triangleIndices[i + 1];
                int index3 = triangleIndices[i + 2];

                Vector3 vertex1 = vertices[index1];
                Vector3 vertex2 = vertices[index2];
                Vector3 vertex3 = vertices[index3];

                //first calculate normal using cross product, this is not necessarily of length one....
                area.normal = Vector3.Cross(vertex2 - vertex1, vertex3 - vertex1);
                //now use that normal to calculate area of the triangle spanned by v1,v2,v3:
                //the magnitude (or length) of the vector a×b, written as ∥a×b∥,
                //is the area of the parallelogram spanned by a and b, half of it gives us the triangle
                //a = v2-v1 here and b = v3-v1 (see Wikipedia)
                area.area = area.normal.magnitude / 2;
                //now normalize the normal since we like'm at length 1, size matters! ;).
                area.normal.Normalize();

                //average the centerpoint
                area.centerPoint = (vertex1 + vertex2 + vertex3) / 3.0f;

                //lastly add the result to our area list
                result.Add(area);
            }

            return(result);
        }
        /**
         * @param pAreasToCombine a list of all areas to search through for areas with similar normals
         * @param pMaxAreaSize (out parameter) the size of the biggest area found
         * @return a list of combined areas that all have unique normals
         */
        private static List <DieArea> combineDieAreasWithSimilarNormals(List <DieArea> pAreasToCombine, out float pMaxAreaSize)
        {
            //process all areas so that we are left with
            //combined areas that all have a unique normal
            List <DieArea> uniqueAreas = new List <DieArea>();
            float          maxAreaSize = 0;

            for (int i = 0; i < pAreasToCombine.Count; i++)
            {
                DieArea currentArea = pAreasToCombine[i];
                DieArea similarArea = findAreaWithSimilarNormal(uniqueAreas, currentArea.normal);

                if (similarArea == null)
                {
                    //if there was no area that had a similar normal, create one:
                    similarArea             = new DieArea();
                    similarArea.area        = currentArea.area;
                    similarArea.centerPoint = currentArea.centerPoint;
                    similarArea.normal      = currentArea.normal;
                    similarArea.areaCount   = 1;
                    uniqueAreas.Add(similarArea);
                }
                else
                {
                    //if there already was an area in the uniqueArea list with a similar normal
                    //combine it with the data for the current area
                    similarArea.area += currentArea.area;
                    //calculcate the new centerpoint using the weighted average of the previous centerpoint with the new one
                    similarArea.centerPoint = (similarArea.centerPoint * similarArea.areaCount + currentArea.centerPoint) / (similarArea.areaCount + 1);
                    similarArea.areaCount++;
                }

                //to be able to do the cutoff calculation in a later step we need to
                //keep track of the maximum area size thus far
                maxAreaSize = Mathf.Max(maxAreaSize, similarArea.area);
            }

            pMaxAreaSize = maxAreaSize;
            return(uniqueAreas);
        }