Help Optimizing a Maya Script to Divide a Plane Evenly

Hello!

I’m working on a Maya Python script that takes a plane and divides it into even sections, then separates those sections into distinct objects. I’ve written the script and it seems to work, but it runs very slow on large meshes and I’m scratching my head as to whether there’s a way to optimize it.

The script assumes that the provided plane has length and width resolution in powers of two (ex. 64, 128, 256, etc.). The script is intended to be used on landscape meshes in a game engine to help with optimization using occlusion culling.

Here is the script. Give it a try on a plane with resolution 32 x 32 and it should run ok. If the resolution is much higher than that, you will notice significant performance issues.

import maya.cmds as cmds
import math

# 4 divisions will result in 4 x 4 = 16 separate pieces
divisions = 4

# get the selected object
sel = cmds.ls( selection=True, long=True )
obj = sel[0]

# get the verts along the border of the plane
faces = cmds.polyListComponentConversion( obj, toFace=True )
border_edges = cmds.polyListComponentConversion( faces, toEdge=True, bo=True )
verts = cmds.polyListComponentConversion( border_edges, toVertex=True)
verts = cmds.ls( verts, flatten=True, long=True )

# get one of the corner verts
for v in verts:
    print( v )
    adj_edges = cmds.polyListComponentConversion( v, toEdge=True)
    adj_edges = cmds.ls( adj_edges, flatten=True, long=True )
    if len( adj_edges ) <= 2:
        corner_vert = v
        break

# get the corner edges
corner_edges = cmds.polyListComponentConversion( corner_vert, toEdge=True )
corner_edges = cmds.ls( corner_edges, flatten=True, long=True )

detatch_edges = set()

for k in range( 2 ):

    # get the edges of one dimension
    cmds.select( corner_edges[k] )
    cmds.polySelectConstraint( t=0x8000, pp=4 )
    edges_u = cmds.ls( selection=True, long=True, flatten=True )
    
    # get the division resolution
    resolution = len( edges_u )
    div_resolution = int( math.floor( resolution / divisions ) )
    
    # convert the border edges to a set
    border_edges = cmds.ls( border_edges, flatten=True, long=True )
    border_edges = set( border_edges )
    
    grow_faces = cmds.polyListComponentConversion( edges_u, toFace=True )
    grow_faces = cmds.ls( grow_faces, long=True, flatten=True )
    
    for j in range( divisions-1 ):
        
        # loop start
        for i in range( div_resolution ):
            step_edges = cmds.polyListComponentConversion( grow_faces, toEdge=True, bo=True )
            step_edges = cmds.ls( step_edges, flatten=True, long=True )
            step_edges = set( step_edges )
            
            leading_edge = step_edges.difference( border_edges )
                    
            new_faces = cmds.polyListComponentConversion( leading_edge, toFace=True )
            new_faces = cmds.ls( new_faces, long=True, flatten=True )
            new_faces = set( new_faces )
            grow_faces = set( grow_faces )
            
            grow_faces = grow_faces.union( new_faces )
            grow_faces = list( grow_faces )
            
        detatch_edges = detatch_edges.union( leading_edge )
    
    #cmds.select( detatch_edges )

# split edges
cmds.polySplitEdge( detatch_edges, op=1 )

# separate
cmds.polySeparate( obj, ch=0 )

Step 1: Does it really need to be optimized?
In your case, I agree, it does.

Step 2: Profile your code!
WHERE in your code do you need to optimize? What lines cause the big slowdown?
You don’t have to use some crazy profiler for this. Just put some time.time() checks into your code and see generally how long it takes.

I did this for your code, and the inner-most loop with leading_edge is where the VAST majority of the time takes place.

Step 3: Work on that chunk.
Why are you keeping track of the leading edge in that loop? The leading edge isn’t needed until after you’ve grown your selection the required number of times. Also converting between faces and verts is slightly faster. And you don’t have to flatten the grow_faces list any more.

	grow_faces = cmds.polyListComponentConversion( edges_u, toFace=True )
	for j in range( divisions-1 ):
		# If this is the first loop, then we start with a strip of faces already selected
		# so we need to do one less grow loop
		offset = 1 if j == 0 else 0

		# Grow the face selection
		for i in range( div_resolution - offset ):
			grow_verts = cmds.polyListComponentConversion( grow_faces, toVertex=True )
			grow_faces = cmds.polyListComponentConversion( grow_verts, toFace=True )

		# Get the border of the face selection, and remove any border edges to get the leading edge
		step_edges = cmds.polyListComponentConversion( grow_faces, toEdge=True, border=True )
		step_edges = set( cmds.ls( step_edges, flatten=True ) )
		leading_edge = step_edges.difference( border_edges )
		detatch_edges = detatch_edges.union( leading_edge )

With this change a 512x512 block takes 10 seconds on my machine

1 Like

Got it down to 4.8 seconds on a 512 grid using some functions I had lying around.
The idea was to not grow the selection all over the place. Instead, figure out some way to get the split loops directly. So I used my “put the verts in order” function, and then got the edge loop starting at the Nth vertex to split on.

FYI: Those “functions I had lying around” were lying here:

2 Likes

Sweet, thank you @tfox_TD ! I just tested your script on a 1024 plane and it worked great. Mine was completely unusable at that resolution.

That makes complete sense to not grow the selection all over the place. I was visualizing the solution could be to only grow the selection every n number of edges, starting from the side edge, but it looks like you did just that in your version.

Thank you!

Hello again @tfox_TD!

I just ran your script on this mesh and I am getting some funky results. For some reason, the divisions are not being made evenly. Perhaps it’s something to do with the “put the verts in order” function?

str: 171
cmds.polySelectConstraint(t=0x8000, pp=4)

On such a mesh, it will not give the result you expect, since there is a large angle between edges 12762 and 12765…

Add this flag to this command: max2dAngle(m2a) or max3dAngle(m3a)

For exemple:
cmds.polySelectConstraint(t=0x8000, pp=4, m2a=89.99, m3a=89.99)

command (Python)

polySelectConstraint

max2dAngle(m2a)
Maximum angle between two consecutive edges in the 2d tangent plane for “Contiguous Edges” propagate mode.

max3dAngle(m3a)
Maximum angle between two consecutive edges in 3d space for “Contiguous Edges” propagate mode.

Also, in Maya 2022 Py3, and Maya 2023 this code will not work.

str 99:
vk = neighborDic.viewkeys()
str 109
vertLop = [neighborDic.keys()[0]]

etk

Mapping Types — dict
PY2
PY3

from PEP 3106:

The dictionary methods keys(), values(), and items() are different in Python 3.x. They return an object called a view instead of a fully materialized list.

It’s not possible to change the return values of keys(), values(), and items() in Python 2.7 because too much code would break. Instead the 3.x versions were added under the new names viewkeys(), viewvalues(), and viewitems().

PS:
And instead of endless polyListComponentConversion conversions, get direct access to the required components right away through the MAYA PYTHON API .
For example, through MFnMesh and iterators MItMeshEdge etk…

from maya import cmds
from itertools import combinations
try: from time import perf_counter as t_clock
except ImportError: from time import clock as t_clock
from timeit import timeit

# Get Mesh Transform Node path
def get_mesh_transform():
    sel = cmds.ls(sl=1, long=1, flatten=1)
    if sel:
        mesh_transform = cmds.ls(sel, transforms=1, long=1, flatten=1)
        if mesh_transform: return mesh_transform[0]
        mesh_transform = cmds.ls(sel, shapes=1, long=1, flatten=1)
        if mesh_transform: return (cmds.listRelatives(sel, parent=1, fullPath=1))[0]
        mesh_transform = cmds.listRelatives(sel, parent=1,shapes=1, fullPath=1)
        if mesh_transform: return (cmds.listRelatives(mesh_transform, parent=1, fullPath=1))[0]
    else:
        cmds.confirmDialog(title="Nothing selected", message="Select mesh or any mesh component.")
        cmds.error("Select is empty...")

# Get two edges from any corner mesh
def get_one_corner_edges(mesh_transform):
    all_border_edges = cmds.polyListComponentConversion("{}.f[*]".format(mesh_transform), toEdge=1, border=1)
    all_border_edges_flaten = set(cmds.ls(all_border_edges, long=1, flatten=1))
    all_border_vertices_full = cmds.polyListComponentConversion(all_border_edges, toVertex=1, border=0)
    all_border_vertices_full = set(cmds.ls(all_border_vertices_full, long=1, flatten=1))
    all_border_vertices_pre = cmds.polyListComponentConversion(all_border_edges, toVertex=1, border=1)
    all_border_vertices_pre = set(cmds.ls(all_border_vertices_pre, long=1, flatten=1))
    all_corners_vertices = list(all_border_vertices_full - all_border_vertices_pre)
    one_corner_edges = cmds.polyListComponentConversion(all_corners_vertices[0], toEdge=1, border=1)
    all_border_edges_count = len(all_border_edges_flaten)
    return one_corner_edges, all_border_edges_flaten, all_border_edges_count

# Get edges for edge split loop
def get_edges_for_split(divisions):
    mesh_transform = get_mesh_transform()
    one_corner_edges, all_border_edges_flaten, all_border_edges_count = get_one_corner_edges(mesh_transform)
    edge_distance = all_border_edges_count // 4 // divisions # get edges count for separate mesh h/w size
    cmds.select(one_corner_edges)
    set_00 = set()
    all_sets = []
    for i in range(divisions): # get start vertex for edge loops. Start vertex count = two sides x division-1.(for divisions=4 -> 6 start vtx)
        if i==0:
            cmds.polySelectConstraint( t=0x8000, pp=4, m2a = 180, m3a = 180, ed = edge_distance - 1 )
        else:
            cmds.polySelectConstraint( t=0x8000, pp=4, m2a = 180, m3a = 180, ed = edge_distance )
        b=cmds.ls(sl=1,fl=1)
        b=set(b)-set_00
        all_sets.append(set(cmds.ls(cmds.polyListComponentConversion(b, toVertex=1), fl=1)))
        if i==divisions: break
        set_00.update(b)
    cmds.polySelectConstraint(m=0, disable=1)
    vertices_start = set()
    for i in combinations(enumerate(all_sets,1),2):
        vertices_start.update(i[0][1].intersection(i[1][1]))
    edges_start_all = set(cmds.ls(cmds.polyListComponentConversion(vertices_start, toEdge=1), long=1, flatten=1))
    edges_start_for_loops = edges_start_all - all_border_edges_flaten
    cmds.select(clear = 1)
    set_all_edges_for_loop = set()
    for item in edges_start_for_loops:
        idx= int(item.rsplit("[",1)[1].rsplit("]",1)[0])
        set_all_edges_for_loop.update(set(cmds.polySelect(mesh_transform, edgeLoop = idx, asSelectString=1, ns=1)))
    return set_all_edges_for_loop, mesh_transform


def general(divisions = 4):
    timer_00 = t_clock()
    set_all_edges_for_loop, mesh_transform = get_edges_for_split(divisions)
    timer_01 = t_clock()
    # split edges
    cmds.polySplitEdge(set_all_edges_for_loop, op=1, ch=0)
    timer_02 = t_clock()
    # separate
    cmds.polySeparate(mesh_transform, ch=0)
    # deselect
    cmds.select(cl=1)
    timer_03 = t_clock()
    print(
        "\n\t\t  Calculate edges for loop: {} s. \
        \n\t\t\t\t\t   Split edges: {} s. \
        \n\t\t\t\t\t Poly Separate: {} s. \
        \n\t\t\t\t\t    Total time: {} s. \
        \n".format(timer_01-timer_00, timer_02-timer_01, timer_03-timer_02, timer_03-timer_00)
        )
    cmds.flushUndo()


general(divisions = 4)

Threw out the useless and inefficient from the script.
In principle, the same polyListComponentConversion and polySelectConstraint remain.
Without using Open Maya (Maya Python API).
Creating an edges set for polySplitEdge takes very little time.
For example, on the grid you provided, generation takes less than a second for divisions = 64:
HeightMap_512.fbx
in Mesh “HeightMap”: 262,144 faces 512 x 512
Divisions = 64 = 4096 separate meshes 8 x 8

general(divisions = 64)
# Calculate edges for loop: 0.6455691999999544 s.

Almost all time is spent on Split edges and Poly Separate
For huge meshes and a lot of divisions, it will be easier to rewrite the re-creation of meshes “from scratch” to the “Maya API”.
The essence of the method used:
We count the number of edges in the perimeter of the grid.
get edges count for separate mesh h/w size:
edge_distance = all_border_edges_count // 4 // divisions
We find any angular vertex.
Convert it to a pair of edges
Expand selection at a time by edge_distance
(For the first iteration, one less edge, since one has already been allocated )
cmds.polySelectConstraint( t=0x8000, pp=4, m2a = 180, m3a = 180, ed = edge_distance - 1 )
The resulting selection is placed in a set, converted to a list of vertices and placed in a set of vertices.
Extending the selection one more step.
From the previous set of edges we subtract a new set of selected edges, convert to vertices and intersect with the previous set of vertex (in sets this happens very quickly).
As a result, we get the first two starting points (since the selection expands simultaneously on two adjacent sides) for loops for Split edges.
And so on. Until we get all the starting points.
We also take into account that for Split edges we will not need corner points.
Start vertex count = two sides x division - 1.
(for divisions = 4 → 6 start vtx)
Convert starting points to edges, subtract border edges (since they are also not needed for Split edges)
Thus, we get one edge for each starting vertex.
For example, for divisions = 4 we get 6 starting edges.
For each edge we run polySelect. Something like that:
set_all_edges_for_loop.update(set(cmds.polySelect(mesh_transform, edgeLoop = idx, asSelectString=1, ns=1)))
Now it remains only to pass this set to the polySplitEdge command:
cmds.polySplitEdge(set_all_edges_for_loop, op=1, ch=0)
and further:
cmds.polySeparate(mesh_transform, ch=0)
How fast will this code be for large grids and large Divisions values?
For example, for a mesh of 4 million polygons (2048 x 2048) and Divisions = 16, creating a set of edges already takes almost 2 seconds. But against the background of 40 seconds for “Split edges/Poly Separate” operations, this is a very insignificant part of the total time.
# polyPlane -w 2048 -h 2048 -sx 2048 -sy 2048 -ax 0 1 0 -cuv 2 -ch 0;
# in Mesh "polyPlane": 4,194,304 faces 2048 x 2048 # Divisions = 16 = 256 separate meshes 128 x 128`

Calculate edges for loop: 2.013220500000898 s.
			 Split edges: 21.434371699999247 s.
		   Poly Separate: 19.730168899999626 s.
			  Total time: 43.17776109999977 s.

Another important point, “Split edges/Poly Separate” is traditionally very buggy!
Even on rectangular meshes without nonmanifold geometry…
The result will need to be checked.
For some reason, Maya loves to connect a pair of meshes with one common angular vertex.
Of course, this can be quickly eliminated, but still unpleasant.

Well, something like this…
Good luck and harmony!

general(divisions = 4)

# HeightMap_512.fbx
# in Mesh "HeightMap": 262,144 faces 512 x 512
# Divisions = 4 = 16 separate meshes 128 x 128

general(divisions = 4)

	Calculate edges for loop: 0.23555409999971744 s.
				 Split edges: 0.28817849999904865 s.
			   Poly Separate: 0.35460560000137775 s.
				  Total time: 0.8783382000001438 s.

# HeightMap_512.fbx
# in Mesh "HeightMap": 262,144 faces 512 x 512
# Divisions = 8 = 64 separate meshes 64 x 64

general(divisions = 8)

	Calculate edges for loop: 0.2611658999994688 s.
				 Split edges: 0.5596146000007138 s.
			   Poly Separate: 0.5313575000000128 s.
				  Total time: 1.3521380000001955 s.

# HeightMap_512.fbx
# in Mesh "HeightMap": 262,144 faces 512 x 512
# Divisions = 16 = 256 separate meshes 32 x 32

general(divisions = 16)

	Calculate edges for loop: 0.3004595000002155 s.
				 Split edges: 1.6644132999999783 s.
			   Poly Separate: 1.3874107999999978 s.
				  Total time: 3.3522836000001917 s.

# HeightMap_512.fbx
# in Mesh "HeightMap": 262,144 faces 512 x 512
# Divisions = 32 = 1024 separate meshes 16 x 16

general(divisions = 32)

	Calculate edges for loop: 0.4130881999999474 s.
				 Split edges: 5.913958199999797 s.
			   Poly Separate: 4.919814900000347 s.
				  Total time: 11.246861300000091 s.

# HeightMap_512.fbx
# in Mesh "HeightMap": 262,144 faces 512 x 512
# Divisions = 64 = 4096 separate meshes 8 x 8

general(divisions = 64)

	Calculate edges for loop: 0.6455691999999544 s.
				 Split edges: 25.510512000000745 s.
			   Poly Separate: 20.41917089999879 s.
				  Total time: 46.57525209999949 s.

# HeightMap_512.fbx
# in Mesh "HeightMap": 262,144 faces 512 x 512
# Divisions = 128 = 16384 separate meshes 4 x 4

general(divisions = 64)

	Calculate edges for loop:   1.12 s.
				 Split edges: 107.22 s.
			   Poly Separate: 159.10 s.
				  Total time: 267.43 s.

# polyPlane -w 2048 -h 2048 -sx 2048 -sy 2048 -ax 0 1 0 -cuv 2 -ch 0;
# in Mesh "polyPlane": 4,194,304 faces 2048 x 2048
# Divisions = 4 = 16 separate meshes 512 x 512

general(divisions = 4)

	Calculate edges for loop: 1.2764158000009047 s.
				 Split edges: 2.796179699998902 s.
			   Poly Separate: 6.522453999999925 s.
				  Total time: 10.595049499999732 s.

# polyPlane -w 2048 -h 2048 -sx 2048 -sy 2048 -ax 0 1 0 -cuv 2 -ch 0;
# in Mesh "polyPlane": 4,194,304 faces 2048 x 2048
# Divisions = 16 = 256 separate meshes 128 x 128

	Calculate edges for loop: 2.013220500000898 s.
				 Split edges: 21.434371699999247 s.
			   Poly Separate: 19.730168899999626 s.
				  Total time: 43.17776109999977 s.

As I reported earlier, polySplitEdge is a very unreliable operation.
For example, in the proposed test scene with a division value of 32 or more,
polySplitEdge produces the following result:

What needs to be corrected so as not to check the result and not to clean up defective shapes?
You need to replace polySplitEdge with a more reliable tool: polySplitVertex.
Having previously converted the set of final eges loops into vertices set.
polySplitVertex is somewhat slower than polySplitEdge, but with more predictable results:

Here is the revised and corrected code:

from maya import cmds
from itertools import combinations
try: from time import perf_counter as t_clock
except ImportError: from time import clock as t_clock
from timeit import timeit

# Get Mesh Shape Node path
def get_mesh_shape():
    sel = cmds.ls(selection = 1, long = 1)
    if sel:
        sel_filter = cmds.filterExpand( selectionMask = (12, 31, 32, 34, 35, 70), ex = 0, fullPath =1)
        if sel_filter:
            mesh_shapes = set()
            sel = cmds.filterExpand( selectionMask = 12, ex = 0, fullPath =1)
            if sel: mesh_shapes.update(set(sel))
            sel = cmds.filterExpand( selectionMask = (31, 32, 34, 35, 70), ex = 0, fullPath =1)
            if sel: mesh_shapes.update(set(cmds.listRelatives(sel, parent=1,shapes=1, fullPath=1)))
            if len(mesh_shapes) == 1: return list(mesh_shapes)[0]
            else:
                cmds.confirmDialog(title = "Incorrect select",
                                 message = "Select contains items for more than one mesh.\n" +
                                           "Select one polygonal mesh or any components on the same mesh.")
                cmds.error("Incorrect select...")
        else:
            cmds.confirmDialog(title = "Incorrect select",
                             message = "Select does not contain polygonal elements.\n" +
                                       "Select one polygonal mesh or any components on the same mesh.")
            cmds.error("Incorrect select...")
    else:
        cmds.confirmDialog(title = "Nothing selected",
                         message = "Nothing selected.\n" +
                                   "Select one polygonal mesh or any components on the same mesh.")
        cmds.error("Nothing selected...")

# Get two edges from any corner mesh
def get_one_corner_edges(mesh_shape):
    all_border_edges = cmds.polyListComponentConversion("{}.f[*]".format(mesh_shape), toEdge=1, border=1)
    all_border_edges_flaten = set(cmds.ls(all_border_edges, long=1, flatten=1))
    all_border_vertices_full = cmds.polyListComponentConversion(all_border_edges, toVertex=1, border=0)
    all_border_vertices_full = set(cmds.ls(all_border_vertices_full, long=1, flatten=1))
    all_border_vertices_pre = cmds.polyListComponentConversion(all_border_edges, toVertex=1, border=1)
    all_border_vertices_pre = set(cmds.ls(all_border_vertices_pre, long=1, flatten=1))
    all_corners_vertices = list(all_border_vertices_full - all_border_vertices_pre)
    one_corner_edges = cmds.polyListComponentConversion(all_corners_vertices[0], toEdge=1, border=1)
    all_border_edges_count = len(all_border_edges_flaten)
    return one_corner_edges, all_border_edges_flaten, all_border_edges_count

# Get edges for edge split loop
def get_vertises_for_split(divisions):
    mesh_shape = get_mesh_shape()
    one_corner_edges, all_border_edges_flaten, all_border_edges_count = get_one_corner_edges(mesh_shape)
    edge_distance = all_border_edges_count // 4 // divisions # get edges count for separate mesh h/w size
    cmds.select(one_corner_edges)
    set_00 = set()
    all_sets = []
    for i in range(divisions): # get start vertex for edge loops. Start vertex count = two sides x division-1.(for divisions=4 -> 6 start vtx)
        if i==0:
            cmds.polySelectConstraint( t=0x8000, pp=4, m2a = 180, m3a = 180, ed = edge_distance - 1 )
        else:
            cmds.polySelectConstraint( t=0x8000, pp=4, m2a = 180, m3a = 180, ed = edge_distance )
        b=cmds.ls(sl=1,fl=1)
        b=set(b)-set_00
        all_sets.append(set(cmds.ls(cmds.polyListComponentConversion(b, toVertex=1), fl=1)))
        if i==divisions: break
        set_00.update(b)
    cmds.polySelectConstraint(m=0, disable=1)
    vertices_start = set()
    for i in combinations(enumerate(all_sets,1),2):
        vertices_start.update(i[0][1].intersection(i[1][1]))
    edges_start_all = set(cmds.ls(cmds.polyListComponentConversion(vertices_start, toEdge=1), long=1, flatten=1))
    edges_start_for_loops = edges_start_all - all_border_edges_flaten
    set_all_vertex_for_loop = set()
    for item in edges_start_for_loops:
        idx= int(item.rsplit("[",1)[1].rsplit("]",1)[0])
        set_edges_for_loop = set(cmds.polySelect(mesh_shape, edgeLoop = idx, asSelectString=1, ns=1))
        set_all_vertex_for_loop.update(cmds.polyListComponentConversion(set_edges_for_loop, toVertex=1))
    return set_all_vertex_for_loop, mesh_shape


def general(divisions = 4):
    timer_00 = t_clock()
    set_all_vertex_for_loop, mesh_shape = get_vertises_for_split(divisions)
    timer_01 = t_clock()
    # split vertices
    cmds.polySplitVertex(set_all_vertex_for_loop, ch=0)
    timer_02 = t_clock()
    # separate meshes
    cmds.polySeparate(mesh_shape, ch=0)
    # deselect
    cmds.select(clear = 1)
    timer_03 = t_clock()
    print(
           (
            "\n\t   Create vertices set for split loops: {} s." +
            "\n\t\t\t\t\t   Poly Split Vertices: {} s." +
            "\n\t\t\t\t\t\t\t Poly Separate: {} s." +
            "\n\t\t\t\t\t\t\t\tTotal time: {} s."
           ).format(timer_01 - timer_00,
                    timer_02 - timer_01,
                    timer_03 - timer_02,
                    timer_03 - timer_00)
         )
    cmds.flushUndo()

general(divisions = 4)

UPD:
Sorry, I was very wrong…
If you use the polySplitVertex command, you will have to merge vertices, restore normals and other “nice things”…
Therefore, we return to the variant with the “buggy” polySplitEdge .
After the polySplitEdge and polySeparate operations:
We check all the created meshes for the presence of nonmanifold vertices.
If there are meshes with such vertices, then Split these vertices polySplitVertex .
Separate these meshes again…
The fully corrected code is posted a few posts below.

@VVVSLAVA thanks for this corrected version! This is amazing! THANK YOU!

Your solution of setting m2a and m3a solved the issue of uneven divisions.

All of your other improvements helped give more predictable results.

I am noticing one small glitch after running the script on the mesh I provided. I am noticing that some of the vertices have random vertex normals. Before running the script, the normals look fine, but after there are patches of vertices where some vertices are pointing on an angle, resulting in strange shading.

Perhaps this has to do with the polySplitVertex command?

I can solve the issue after running the script by doing Mesh Display > Set to Face, followed by Mesh Display > Soften Edge. However, if I’m working on a 1024 x 1024 plane, this takes many minutes for Maya to process the command.

Is there a way to modify the script so that it splits the mesh without affecting the vertex normals?

We can also save some time by optimizing the list retrieval for edges loops.
For example, instead of:

cmds.select(one_corner_edges)
set_00 = set()
all_sets = []
for i in range(divisions): # get start vertex for edge loops. Start vertex count = two sides x division-1.(for divisions=4 -> 6 start vtx)
    if i==0: cmds.polySelectConstraint( t=0x8000, pp=4, m2a = 180, m3a = 180, ed = edge_distance - 1 )
    else: cmds.polySelectConstraint( t=0x8000, pp=4, m2a = 180, m3a = 180, ed = edge_distance )
    b=cmds.ls(sl=1,fl=1)
    b=set(b)-set_00
    all_sets.append(set(cmds.ls(cmds.polyListComponentConversion(b, toVertex=1), fl=1)))
    if i==divisions: break
    set_00.update(b)
cmds.polySelectConstraint(m=0, disable=1)
vertices_start = set()
for i in combinations(enumerate(all_sets,1),2):
    vertices_start.update(i[0][1].intersection(i[1][1]))
edges_start_all = set(cmds.ls(cmds.polyListComponentConversion(vertices_start, toEdge=1), long=1, flatten=1))
edges_start_for_loops = edges_start_all - all_border_edges_flaten
set_all_edges_for_loop = set()
for item in edges_start_for_loops:
    idx= int(item.rsplit("[",1)[1].rsplit("]",1)[0])
    set_all_edges_for_loop.update(set(cmds.polySelect(mesh_transform, edgeLoop = idx, asSelectString=1, ns=1)))

we can write like this:


cmds.select( one_corner_edges_twin )
evalution_set = set()
vertices_start = set()
for i in range( divisions ): # get start vertices for vertices loops. Start vertex count = two sides x division - 1. (for divisions = 4: --> 6 start vtxs)
    if i == 0:
        cmds.polySelectConstraint( type = 0x8000, propagate = 4, max2dAngle = 180.0, max3dAngle = 180.0, edgeDistance = edge_distance - 1 )
    else:
        cmds.polySelectConstraint( type = 0x8000, propagate = 4, max2dAngle = 180.0, max3dAngle = 180.0, edgeDistance = edge_distance )
    sel_list_set = set( cmds.ls( selection = True, long = True, flatten = True))
    current_set = sel_list_set - evalution_set
    tmp_set_1 = set( cmds.ls( cmds.polyListComponentConversion( current_set, toVertex = True ), long = True, flatten = True ) )
    if i != 0:
        intersect_set = tmp_set_1  &  tmp_set_2
        if intersect_set: vertices_start.update( intersect_set )
    tmp_set_2 = tmp_set_1
    if i == divisions: break
    evalution_set = sel_list_set
cmds.polySelectConstraint(mode = 0, disable = True )
edges_start_all = set( cmds.ls( cmds.polyListComponentConversion( vertices_start, toEdge = True ), long = True, flatten = True ) )
edges_start_for_loops = edges_start_all - all_border_edges_flaten
list_all_edges_for_loops = cmds.polySelectSp( edges_start_for_loops, query = True, loop = True )

This will allow us to get a sorted and grouped (not flattened) list for edges loops in one iteration.

But, we can further improve this operation.
Using instead of the polySelect command, its analogue is the polySelectSp command:

list_all_edges_for_loops = cmds.polySelectSp(edges_start_for_loops, query = 1, loop = 1)

In our case, the polySelectSp command will run almost twice as fast as polySelect.
As a result, we will get the same sorted and grouped (not flatten) list of components.
For the proposed TS mesh of 512 x 512 faces, with divisions = 256, i.e. for 510 starting edges, polySelectSp generates the set_all_edges_for_loops list (for 261,120 edges) in ~0.2 seconds.
For some reason this command is not mentioned in the Autodesk documentation.
This command can work in selection mode and in query mode.
Has three flags: -query/-q, -loop/-l and -ring/-r.
Can work with any polycomponents.

Further optimization of the process of creating a list of split-vertices is not very justified, because it takes an insignificant part of the time from the overall process.
Therefore, a dramatic increase in execution speed is possible using the Maya Python API (or Maya C++ API).
Instead of splitting/separate, simply recreate new meshes from the source mesh data.
Recreating empty meshes is very fast.
But transferring additional data (such as shading data, UVs, colors, normals, blind-data, etc) can add a lot of overhead.

Is it actually necessary to cut up the existing topology?

Did you consider making an X*X grid of planes and then using TransferAttributes to reproduce your original heights? That would essentially substitute 1 raycast per vertex for all of the topology changes…

Sorry, I was very wrong…
If you use the polySplitVertex command, you will have to merge vertices, restore normals and other “nice things”…
Therefore, we return to the variant with the “buggy” polySplitEdge.
After the polySplitEdge and polySeparate operations:
We check all the created meshes for the presence of nonmanifold vertices.
If there are meshes with such vertices, then Split these vertices polySplitVertex.
Separate these meshes again.
Profit
And there is no need to worry about the correctness of the normals…
And the total time spent will be less than in previous versions.

# split edges from edges loops
cmds.polySplitEdge( list_all_edges_for_loops, operation = 1, constructionHistory = False )

# separate meshes
new_meshes = cmds.polySeparate( mesh_shape, constructionHistory = False )

# poly cleanup
for mesh in new_meshes:
    non_manifold_vertises = cmds.polyInfo( mesh, nonManifoldVertices = True )
    if non_manifold_vertises:
        cmds.polySplitVertex( non_manifold_vertises, constructionHistory = False )
        sub_separate_meshes = cmds.polySeparate( mesh, constructionHistory = False )
        up_parent = (cmds.listRelatives( sub_separate_meshes, parent = True, fullPath = True ))[0]
        cmds.ungroup( up_parent )

Corrected code, taking into account the above (+ added renaming of all final meshes):

#
# Python 2.7.11, or 3.7.7, or 3.9.7
# Tested: Maya 2019.3.1, Maya 2020.4, Maya 2022.4(Py2/Py3), Maya 2023.2

from maya import cmds
try: from time import perf_counter as t_clock
except ImportError: from time import clock as t_clock

# Get Mesh Shape Node path
def get_mesh_shape():
    sel = cmds.ls( selection = True, long = True )
    if sel:
        sel_filter = cmds.filterExpand( selectionMask = ( 12, 31, 32, 34, 35, 70 ), expand = False, fullPath = True )
        if sel_filter:
            mesh_shapes = set()
            sel = cmds.filterExpand( selectionMask = 12, expand = False, fullPath = True )
            if sel: mesh_shapes.update( set( sel ) )
            sel = cmds.filterExpand( selectionMask = ( 31, 32, 34, 35, 70 ), expand = False, fullPath = True )
            if sel: mesh_shapes.update( set( cmds.listRelatives( sel, parent = True, shapes = True, fullPath = 1 ) ) )
            if len(mesh_shapes) == 1: return list( mesh_shapes )[0]
            else:
                cmds.confirmDialog( title = "Incorrect select",
                                  message = "Select contains items for more than one mesh.\n" +
                                            "Select one polygonal mesh or any components on the same mesh." )
                cmds.error( "Incorrect select..." )
        else:
            cmds.confirmDialog( title = "Incorrect select",
                              message = "Select does not contain polygonal elements.\n" +
                                        "Select one polygonal mesh or any components on the same mesh." )
            cmds.error( "Incorrect select..." )
    else:
        cmds.confirmDialog( title = "Nothing selected",
                          message = "Nothing selected.\n" +
                                   "Select one polygonal mesh or any components on the same mesh." )
        cmds.error( "Nothing selected..." )

# Get two edges from any corner mesh
def get_one_corner_edges( mesh_shape ):
    all_border_edges = cmds.polyListComponentConversion( "{}.f[*]".format( mesh_shape ), toEdge = True, border = True )
    all_border_edges_flaten = set( cmds.ls(all_border_edges, long = True, flatten = True ) )
    all_border_vertices_full = cmds.polyListComponentConversion( all_border_edges, toVertex = True, border = False )
    all_border_vertices_full = set( cmds.ls( all_border_vertices_full, long = True, flatten = True ) )
    all_border_vertices_pre = cmds.polyListComponentConversion( all_border_edges, toVertex = True, border = True )
    all_border_vertices_pre = set( cmds.ls( all_border_vertices_pre, long = True, flatten = True ) )
    all_corners_vertices = list( all_border_vertices_full - all_border_vertices_pre )
    one_corner_edges_twin = cmds.polyListComponentConversion( all_corners_vertices[0], toEdge = True, border = True )
    all_border_edges_count = len( all_border_edges_flaten )
    return  one_corner_edges_twin,  all_border_edges_flaten,  all_border_edges_count

# Get vertices for vertices split loops
def get_vertises_for_split( divisions ):
    mesh_shape = get_mesh_shape()
    one_corner_edges_twin,  all_border_edges_flaten,  all_border_edges_count  =  get_one_corner_edges( mesh_shape )
    edge_distance = all_border_edges_count // 4 // divisions # get edges count for separate mesh h/w size
    cmds.select( one_corner_edges_twin )
    evalution_set = set()
    vertices_start = set()
    for i in range( divisions ): # get start vertices for vertices loops. Start vertex count = two sides x division - 1. (for divisions = 4: --> 6 start vtxs)
        if i == 0:
            cmds.polySelectConstraint( type = 0x8000, propagate = 4, max2dAngle = 180.0, max3dAngle = 180.0, edgeDistance = edge_distance - 1 )
        else:
            cmds.polySelectConstraint( type = 0x8000, propagate = 4, max2dAngle = 180.0, max3dAngle = 180.0, edgeDistance = edge_distance )
        sel_list_set = set( cmds.ls( selection = True, long = True, flatten = True))
        current_set = sel_list_set - evalution_set
        tmp_set_1 = set( cmds.ls( cmds.polyListComponentConversion( current_set, toVertex = True ), long = True, flatten = True ) )
        if i != 0:
            intersect_set = tmp_set_1  &  tmp_set_2
            if intersect_set: vertices_start.update( intersect_set )
        tmp_set_2 = tmp_set_1
        if i == divisions: break
        evalution_set = sel_list_set
    cmds.polySelectConstraint(mode = 0, disable = True )
    edges_start_all = set( cmds.ls( cmds.polyListComponentConversion( vertices_start, toEdge = True ), long = True, flatten = True ) )
    edges_start_for_loops = edges_start_all - all_border_edges_flaten
    list_all_edges_for_loops = cmds.polySelectSp( edges_start_for_loops, query = True, loop = True )
    return  list_all_edges_for_loops,  mesh_shape

def general( divisions = 4 ):
    timer_00 = t_clock()
    list_all_edges_for_loops,  mesh_shape  =  get_vertises_for_split( divisions )
    timer_01 = t_clock()
    mesh_transform_long = (cmds.listRelatives( mesh_shape, parent = True, fullPath = True ))[0]
    mesh_transform_short = (cmds.listRelatives( mesh_shape, parent = True, fullPath = False ))[0]
    # split edges from edges loops
    cmds.polySplitEdge( list_all_edges_for_loops, operation = 1, constructionHistory = False )
    # separate meshes
    timer_02 = t_clock()
    new_meshes = cmds.polySeparate( mesh_shape, constructionHistory = False )
    # poly cleanup and rename meshes
    timer_03 = t_clock()
    for mesh in new_meshes:
        non_manifold_vertices = cmds.polyInfo( mesh, nonManifoldVertices = True )
        if non_manifold_vertices:
            cmds.polySplitVertex( non_manifold_vertices, constructionHistory = False )
            sub_separate_meshes = cmds.polySeparate( mesh, constructionHistory = False )
            up_parent = (cmds.listRelatives( sub_separate_meshes, parent = True, fullPath = True ))[0]
            cmds.ungroup( up_parent )
    all_meshes = cmds.listRelatives( mesh_transform_long, fullPath = True )
    for i in range( len( all_meshes ) ):
        cmds.rename( all_meshes[i], "{}_sub_{:04}".format( mesh_transform_short, i + 1 ) )
    timer_04 = t_clock()
    # deselect
    cmds.select( clear = True )
    print(
           (
            "\n\t\t\t\t\t\t\t\t  Divisions: {}" +
            "\n\t\t  Create edges list for split loops: {} s." +
            "\n\t\t\t\t\t\t   Poly Split Edges: {} s." +
            "\n\t\t\t\t\t\t\t  Poly Separate: {} s." +
            "\n\t\t\t\t\t\t\t\tPoly Clenup: {} s." +
            "\n\t\t\t\t\t\t\t\t Total time: {} s."
           ).format(
                     divisions,
                     timer_01 - timer_00,
                     timer_02 - timer_01,
                     timer_03 - timer_02,
                     timer_04 - timer_03,
                     timer_04 - timer_00
                    )
         )
    cmds.flushUndo()


general(divisions = 4)

Statistics:

                          Divisions: 4
  Create edges list for split loops: 0.22957379999934346 s.
                   Poly Split Edges: 0.3156940000008035 s.
                      Poly Separate: 0.3725806999991619 s.
                        Poly Clenup: 0.014264299999922514 s.
                         Total time: 0.9321127999992314 s.

                          Divisions: 8
  Create edges list for split loops: 0.2440655999998853 s.
                   Poly Split Edges: 0.6109243999999308 s.
                      Poly Separate: 0.5419459999993705 s.
                        Poly Clenup: 0.023443699999916134 s.
                         Total time: 1.4203796999991027 s.

                          Divisions: 16
  Create edges list for split loops: 0.28682990000015707 s.
                   Poly Split Edges: 1.930006599999615 s.
                      Poly Separate: 1.4054766000008385 s.
                        Poly Clenup: 0.07786940000005416 s.
                         Total time: 3.7001825000006647 s.

                          Divisions: 32
  Create edges list for split loops: 0.3682673999992403 s.
                   Poly Split Edges: 7.196249500000704 s.
                      Poly Separate: 4.957847899999251 s.
                        Poly Clenup: 0.3955370000003313 s.
                         Total time: 12.917901799999527 s.

                          Divisions: 64
  Create edges list for split loops: 0.5306158000003052 s.
                   Poly Split Edges: 26.667770999998538 s.
                      Poly Separate: 21.650358900000356 s.
                        Poly Clenup: 4.052774300000237 s.
                         Total time: 52.90151999999944 s.

The list of edges for polySplitEdge command can be obtained much easier and much faster !
polySelect comamnd return values is an integer array containing the ID’s of the components in the selection in order.
If the -as Select String(as) flag is False, the polySelect command returns a flattened array of ID’s (int).
We pass to the polySelect command (as an argument): corner edge ID’s.
Run the polySelect command with the -edgeRing(er) flag.
Selection an edge ring at the given edge.
The command returns a list of edges from edges order.
Now we simply select edges from this list by index, at intervals equal to the size of the output meshes.

edges_start_for_loops = []
for idx in one_corner_edges_twin_idx:
    edges_ring = cmds.polySelect( mesh_shape, query = True, edgeRing = idx )
    count_edges_in_ring = len(edges_ring)
    size = count_edges_in_ring - 1
    step = size // divisions
    end_range = count_edges_in_ring - step
    for i in range (step, end_range, step):
        edges_start_for_loops.append( "{}.e[{}]".format( mesh_shape, edges_ring[i] ) )

Pros:

  1. We got rid of the polySelectConstraint command, which is unreliable for us (in this context).
  2. No need to select polygonal components in the viewport.
  3. It is not necessary to perform sophisticated manipulations with secretions.
  4. The code has become more compact and clearer.
  5. The speed of execution has increased by an order of magnitude.

Also, we can optimize the code to get corner vertices.
Corner vertices can be obtained with just two polyListComponentConversion commands.
The “magic” comes from using the -internal(internal) flag:

all_border_edges = cmds.polyListComponentConversion( "{}.f[*]".format( mesh_shape ), toEdge = True, border = True )
all_corner_vertices = cmds.polyListComponentConversion( all_border_edges, toVertex = True, internal = True )

By running three more commands, you can get a pair of edges for any corner vertex:

# Get first element for flatten component list:
first_corners_vertex = cmds.ls( all_corner_vertices, long = True, flatten = True )[0]
# Get ID vertex for string component notation:
first_corners_vertex_idx = int(first_corners_vertex.rsplit("[", 1)[1].rsplit("]", 1)[0])
# Get edges ID's for vertex ID:
one_corner_edges_twin_idx = cmds.polyIterOnPoly( mesh_shape, vertex = first_corners_vertex_idx, vertexToEdge = True, silent = True )

polyIterOnPoly is an undocumented command.
polyIterOnPoly command: input - ID’s of the components(int), return - ID’s of the components(int).
The specifics of the polyIterOnPoly command have been clarified in this thread.

Complete, revised code, taking into account the above:

# Python 2.7.11, or 3.7.7, or 3.9.7
# Tested: Maya 2019.3.1, Maya 2020.4, Maya 2022.4(Py2/Py3), Maya 2023.2
from maya import cmds
try: from time import perf_counter as t_clock
except ImportError: from time import clock as t_clock

# Get Mesh Shape Node path
def get_mesh_shape():
    sel = cmds.ls( selection = True, long = True )
    if sel:
        sel_filter = cmds.filterExpand( selectionMask = ( 12, 31, 32, 34, 35, 70 ), expand = False, fullPath = True )
        if sel_filter:
            mesh_shapes = set()
            sel = cmds.filterExpand( selectionMask = 12, expand = False, fullPath = True )
            if sel: mesh_shapes.update( set( sel ) )
            sel = cmds.filterExpand( selectionMask = ( 31, 32, 34, 35, 70 ), expand = False, fullPath = True )
            if sel: mesh_shapes.update( set( cmds.listRelatives( sel, parent = True, shapes = True, fullPath = 1 ) ) )
            if len(mesh_shapes) == 1: return list( mesh_shapes )[0]
            else:
                cmds.confirmDialog( title = "Incorrect select",
                                  message = "Select contains items for more than one mesh.\n" +
                                            "Select one polygonal mesh or any components on the same mesh." )
                cmds.error( "Incorrect select..." )
        else:
            cmds.confirmDialog( title = "Incorrect select",
                              message = "Select does not contain polygonal elements.\n" +
                                        "Select one polygonal mesh or any components on the same mesh." )
            cmds.error( "Incorrect select..." )
    else:
        cmds.confirmDialog( title = "Nothing selected",
                          message = "Nothing selected.\n" +
                                   "Select one polygonal mesh or any components on the same mesh." )
        cmds.error( "Nothing selected..." )

# Get two edges IDs from any corner mesh
def get_one_corner_edges_twin_idx( mesh_shape ):
    all_border_edges = cmds.polyListComponentConversion( "{}.f[*]".format( mesh_shape ), toEdge = True, border = True )
    all_corner_vertices = cmds.polyListComponentConversion( all_border_edges, toVertex = True, internal = True )
    first_corners_vertex = cmds.ls( all_corner_vertices, long = True, flatten = True )[0]
    first_corners_vertex_idx = int(first_corners_vertex.rsplit("[", 1)[1].rsplit("]", 1)[0])
    # "polyIterOnPoly" command: input - id's of the components(int), return - id's of the components(int).
    one_corner_edges_twin_idx = cmds.polyIterOnPoly( mesh_shape, vertex = first_corners_vertex_idx, vertexToEdge = True, silent = True )
    return  one_corner_edges_twin_idx

# Get edges for edges split loops
def get_edges_for_split( one_corner_edges_twin_idx, mesh_shape, divisions ):
    edges_start_for_loops = []
    demensions = []
    for idx in one_corner_edges_twin_idx:
        # "polySelect" comamnd return values is an integer array containing
        # the id's of the components in the selection in order.
        # if flag -asSelectString(ass) False, to return flatten id's(int) array.
        edges_ring = cmds.polySelect( mesh_shape, query = True, edgeRing = idx )
        count_edges_in_ring = len(edges_ring)
        size = count_edges_in_ring - 1
        demensions.append(size)
        step = size // divisions
        end_range = count_edges_in_ring - step
        for i in range (step, end_range, step):
            edges_start_for_loops.append( "{}.e[{}]".format( mesh_shape, edges_ring[i] ) )
        list_all_edges_for_loops = cmds.polySelectSp( edges_start_for_loops, query = True, loop = True )
    return  list_all_edges_for_loops,  demensions


def general( divisions = 4 ):
    # get mesh shape long name from selection mesh / mesh components
    timer_00 = t_clock()
    mesh_shape = get_mesh_shape()
    mesh_transform_long =  ( cmds.listRelatives( mesh_shape, parent = True, fullPath = True  ) )[0]
    mesh_transform_short = ( cmds.listRelatives( mesh_shape, parent = True, fullPath = False ) )[0]
    # get one corner edges twin (id's)
    timer_01 = t_clock()
    one_corner_edges_twin_idx = get_one_corner_edges_twin_idx( mesh_shape )
    # get edges list (for split)
    timer_02 = t_clock()
    list_all_edges_for_loops,  demensions  =  get_edges_for_split( one_corner_edges_twin_idx, mesh_shape, divisions )
    # split edges from edges loops
    timer_03 = t_clock()
    cmds.polySplitEdge( list_all_edges_for_loops, operation = 1, constructionHistory = False )
    # separate meshes
    timer_04 = t_clock()
    new_meshes = cmds.polySeparate( mesh_shape, constructionHistory = False )
    # poly cleanup
    timer_05 = t_clock()
    for mesh in new_meshes:
        non_manifold_vertises = cmds.polyInfo( mesh, nonManifoldVertices = True )
        if non_manifold_vertises:
            cmds.polySplitVertex( non_manifold_vertises, constructionHistory = False )
            sub_separate_meshes = cmds.polySeparate( mesh, constructionHistory = False )
            up_parent = ( cmds.listRelatives( sub_separate_meshes, parent = True, fullPath = True ) )[0]
            cmds.ungroup( up_parent )
    # rename meshes
    timer_06 = t_clock()
    all_meshes = cmds.listRelatives( mesh_transform_long, fullPath = True )
    for i in range( len( all_meshes ) ):
        cmds.rename( all_meshes[i], "{}_sub_{:04}".format( mesh_transform_short, i + 1 ) )
    timer_07 = t_clock()
    # deselect
    cmds.select( clear = True )
    print(
           (
            "\n\t\t\t\t\t\t\t\t  Divisions: {}" +
            "\n\t\t\t\t\t  Input mesh demensions: {} x {} faces" +
            "\n\t\t\t\t\tNumber of output meshes: {} pieces" +
            "\n\n\t\t\t\t   Get mesh shape long name: {:.5f} s." +
            "\n\t\t\t  Get one corner edges-twin IDs: {:.5f} s." +
            "\nCreate edges list ({:07} edges) for split: {:.5f} s." +
            "\n\t\t\t\t\t\t   Poly Split Edges: {:.5f} s." +
            "\n\t\t\t\t\t\t\t  Poly Separate: {:.5f} s." +
            "\n\t\t\t\t\t\t\t\tPoly Clenup: {:.5f} s." +
            "\n\t\t\t\t\t\t Rename {:04} meshes: {:.5f} s." +
            "\n\n\t\t\t\t\t\t\t\t Total time: {:.5f} s."
           ).format(
                     divisions,
                     demensions[0],
                     demensions[1],
                     divisions ** 2,
                     timer_01 - timer_00,
                     timer_02 - timer_01,
                     ( divisions - 1 ) * demensions[0] + ( divisions - 1 ) * demensions[1],
                     timer_03 - timer_02,
                     timer_04 - timer_03,
                     timer_05 - timer_04,
                     timer_06 - timer_05,
                     divisions ** 2,
                     timer_07 - timer_06,
                     timer_07 - timer_00
                    )
         )
    cmds.flushUndo()


general( divisions = 4 )

Statistics:

############################################################
#
								  Divisions: 4
					  Input mesh demensions: 512 x 512 faces
					Number of output meshes: 16 pieces

				   Get mesh shape long name: 0.00028 s.
			  Get one corner edges-twin IDs: 0.05985 s.
Create edges list (0003072 edges) for split: 0.00847 s.
						   Poly Split Edges: 0.31111 s.
							  Poly Separate: 0.34223 s.
								Poly Clenup: 0.01214 s.
						 Rename 0016 meshes: 0.00215 s.

								 Total time: 0.73624 s.
#
############################################################
#
								  Divisions: 8
					  Input mesh demensions: 512 x 512 faces
					Number of output meshes: 64 pieces

				   Get mesh shape long name: 0.00027 s.
			  Get one corner edges-twin IDs: 0.05892 s.
Create edges list (0007168 edges) for split: 0.01421 s.
						   Poly Split Edges: 0.55268 s.
							  Poly Separate: 0.54380 s.
								Poly Clenup: 0.01514 s.
						 Rename 0064 meshes: 0.00846 s.

								 Total time: 1.19348 s.
#
############################################################
#
								  Divisions: 16
					  Input mesh demensions: 512 x 512 faces
					Number of output meshes: 256 pieces

				   Get mesh shape long name: 0.00028 s.
			  Get one corner edges-twin IDs: 0.06011 s.
Create edges list (0015360 edges) for split: 0.02659 s.
						   Poly Split Edges: 1.52320 s.
							  Poly Separate: 1.38804 s.
								Poly Clenup: 0.04506 s.
						 Rename 0256 meshes: 0.03351 s.

								 Total time: 3.07677 s.
#
############################################################
#
								  Divisions: 32
					  Input mesh demensions: 512 x 512 faces
					Number of output meshes: 1024 pieces

				   Get mesh shape long name: 0.00028 s.
			  Get one corner edges-twin IDs: 0.06016 s.
Create edges list (0031744 edges) for split: 0.05233 s.
						   Poly Split Edges: 5.67169 s.
							  Poly Separate: 4.90896 s.
								Poly Clenup: 0.25314 s.
						 Rename 1024 meshes: 0.14131 s.

								 Total time: 11.08787 s.
#
############################################################
#
								  Divisions: 64
					  Input mesh demensions: 512 x 512 faces
					Number of output meshes: 4096 pieces

				   Get mesh shape long name: 0.00028 s.
			  Get one corner edges-twin IDs: 0.05934 s.
Create edges list (0064512 edges) for split: 0.09911 s.
						   Poly Split Edges: 23.14652 s.
							  Poly Separate: 21.09346 s.
								Poly Clenup: 3.36263 s.
						 Rename 4096 meshes: 0.56406 s.

								 Total time: 48.32540 s.
#
############################################################
#
								  Divisions: 128
					  Input mesh demensions: 512 x 512 faces
					Number of output meshes: 16384 pieces

				   Get mesh shape long name: 0.00029 s.
			  Get one corner edges-twin IDs: 0.05921 s.
Create edges list (0130048 edges) for split: 0.18757 s.
						   Poly Split Edges: 87.37042 s.
							  Poly Separate: 163.06877 s.
								Poly Clenup: 84.42518 s.
						 Rename 16384 meshes: 2.34613 s.

								 Total time: 337.45755 s.
#
############################################################