-
-
Save mottosso/f967b388a2540fdf165dd5b3b6f1c2ca to your computer and use it in GitHub Desktop.
Performance test of cmdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Execute in Maya Script Editor, or mayapy | |
# Based on https://animallogic.github.io/AL_omx/introduction/perf_compare.html | |
import random | |
import time | |
import cmdx | |
from maya import cmds | |
def getRandomPosition(furthestDist): | |
return [(random.random() - 0.5) * furthestDist for _ in range(3)] | |
def getRandomScale(): | |
return [random.random() * 2.0 for _ in range(3)] | |
def getRandomColor(): | |
return random.randint(0, 31) | |
def getRandomIndex(maxValue): | |
return random.randint(0, maxValue) | |
def getMaxValue(locCount): | |
return int(locCount / 10) | |
class PerfMeasurement: | |
def __init__(self, label): | |
self._label = label | |
self._gap = 0.0 | |
def __enter__(self,): | |
self._start = time.time() | |
self._gap = 0.0 | |
def __exit__(self, *_, **__): | |
self._gap = time.time() - self._start | |
print(f"{self._label} took {round(self._gap, 4)} seconds.") | |
def timeConsumed(self): | |
return self._gap | |
class TotalPerfMeasurement: | |
def __init__(self, label): | |
self._measurers = [] | |
self._label = label | |
def add(self, label): | |
measurement = PerfMeasurement(label) | |
self._measurers.append(measurement) | |
return measurement | |
def __enter__(self,): | |
print("-" * 20) | |
return self | |
def __exit__(self, *_, **__): | |
total = 0.0 | |
for m in self._measurers: | |
total = total + m.timeConsumed() | |
print(f"{self._label} took {round(total, 4)} seconds.") | |
print("-" * 20) | |
NUM_NODES_LIST = (100, 1000, 10000) | |
REFINED_NUM_NODES_LIST = (10, 50, 100, 500, 1000, 5000, 10000, 50000) | |
def createInCmdx(locCount): | |
maxValue = getMaxValue(locCount) | |
dgmod = cmdx.DGModifier() | |
mod = cmdx.DagModifier() | |
controller = mod.createNode("joint", name="controller") | |
attr = cmdx.Integer("flash", shortName="flash", min=0, max=maxValue) | |
mod.addAttr(controller, attr) | |
parent = mod.createNode("transform", name="stars") | |
stars = [None] * locCount | |
toDelete = [None] * locCount | |
for i in range(locCount): | |
condition = dgmod.createNode("condition") | |
loc = mod.createNode("transform", parent=parent) | |
mod.createNode("locator", parent=loc) | |
attr = cmdx.Integer("flashIndex", | |
shortName="flashIndex", | |
min=0, | |
max=maxValue) | |
mod.addAttr(loc, attr) | |
testDel = mod.createNode("transform", parent=parent) | |
mod.createNode("locator", parent=testDel) | |
testDel.isAlive() | |
stars[i] = (loc, condition) | |
toDelete[i] = testDel | |
mod.doIt() | |
dgmod.doIt() | |
return controller, stars, toDelete | |
def editInCmdx(controller, stars): | |
maxValue = getMaxValue(len(stars)) | |
mod = cmdx.DGModifier() | |
mod.setAttr(controller["radius"], 10) | |
mod.setKeyable(controller["radius"], True) | |
mod.setAttr(controller["radius"], { | |
1: 0, | |
120: maxValue | |
}) | |
for loc, condition in stars: | |
mod.setAttr(condition["colorIfTrue"], (1.0, 1.0, 1.0)) | |
mod.setAttr(condition["colorIfFalse"], (1.0, 1.0, 1.0)) | |
mod.setAttr(loc["overrideEnabled"], True) | |
mod.setAttr(loc["overrideColor"], getRandomColor()) | |
mod.setAttr(loc["t"], getRandomPosition(maxValue)) | |
mod.setAttr(loc["s"], getRandomScale()) | |
# here we don't care about plug state change undoability as the whole | |
# node creation is done in the same DGModifier. | |
# otherwise we would use mod.setLocked(loc["displayHandle"], True) | |
loc["displayHandle"].lock() | |
loc["overrideDisplayType"].lock() | |
loc["overrideDisplayType"].lock() | |
mod.setAttr(loc["flashIndex"], getRandomIndex(maxValue)) | |
mod.connect(controller["r"], loc["r"]) | |
mod.connect(controller["overrideShading"], loc["overrideShading"]) | |
mod.disconnect(loc["overrideShading"], source=True) | |
mod.connect(controller["flash"], condition["firstTerm"]) | |
mod.connect(loc["flashIndex"], condition["secondTerm"]) | |
mod.connect(condition["outColorR"], loc["visibility"]) | |
mod.doIt() | |
def renameInCmdx(nodesToRename): | |
mod = cmdx.DagModifier() | |
for node in nodesToRename: | |
transformName = str(node) | |
mod.renameNode(node, f"{transformName}New") | |
mod.renameNode(node, f"{transformName}") | |
mod.doIt() | |
def queryInCmdx(controller, stars): | |
list(controller["flash"].outputs()) # It's a generator, for performance | |
for loc, _ in stars: | |
loc.isAlive() | |
loc["t"].read() | |
loc["wm"][0].read() | |
loc["overrideDisplayType"].locked | |
def deleteInCmdx(nodesToDelete): | |
mod = cmdx.DagModifier() | |
for toDel in nodesToDelete: | |
mod.deleteNode(toDel) | |
mod.doIt() | |
def createInCmdxNoUndo(locCount): | |
maxValue = getMaxValue(locCount) | |
controller = cmdx.createNode("joint", name="controller") | |
attr = cmdx.Integer("flash", shortName="flash", min=0, max=maxValue) | |
controller.addAttr(attr) | |
parent = cmdx.createNode("transform", name="stars") | |
stars = [None] * locCount | |
toDelete = [None] * locCount | |
for i in range(locCount): | |
condition = cmdx.createNode("condition") | |
loc = cmdx.createNode("transform", parent=parent) | |
cmdx.createNode("locator", parent=loc) | |
attr = cmdx.Integer("flashIndex", | |
shortName="flashIndex", | |
min=0, | |
max=maxValue) | |
loc.addAttr(attr) | |
testDel = cmdx.createNode("transform", parent=parent) | |
cmdx.createNode("locator", parent=testDel) | |
testDel.isAlive() | |
stars[i] = (loc, condition) | |
toDelete[i] = testDel | |
return controller, stars, toDelete | |
def editInCmdxNoUndo(controller, stars): | |
maxValue = getMaxValue(len(stars)) | |
controller["radius"] = 10 | |
controller["radius"].keyable = True | |
controller["radius"] = { | |
1: 0, | |
120: maxValue | |
} | |
for loc, condition in stars: | |
condition["colorIfTrue"] = (1.0, 1.0, 1.0) | |
condition["colorIfFalse"] = (1.0, 1.0, 1.0) | |
loc["overrideEnabled"] = True | |
loc["overrideColor"] = getRandomColor() | |
loc["t"] = getRandomPosition(maxValue) | |
loc["s"] = getRandomScale() | |
loc["displayHandle"].lock() | |
loc["overrideDisplayType"].lock() | |
loc["overrideDisplayType"].lock() | |
loc["flashIndex"] = getRandomIndex(maxValue) | |
controller["r"] >> loc["r"] | |
controller["overrideShading"] >> loc["overrideShading"] | |
loc["overrideShading"].disconnect(source=True) | |
controller["flash"] >> condition["firstTerm"] | |
loc["flashIndex"] >> condition["secondTerm"] | |
condition["outColorR"] >> loc["visibility"] | |
def renameInCmdxNoUndo(nodesToRename): | |
mod = cmdx.DagModifier() | |
for node in nodesToRename: | |
transformName = str(node) | |
mod.renameNode(node, f"{transformName}New") | |
mod.renameNode(node, f"{transformName}") | |
mod.doIt() | |
def queryInCmdxNoUndo(controller, stars): | |
list(controller["flash"].outputs()) # It's a generator, for performance | |
for loc, _ in stars: | |
loc.isAlive() | |
loc["t"].read() | |
loc["wm"][0].read() | |
loc["overrideDisplayType"].locked | |
def deleteInCmdxNoUndo(nodesToDelete): | |
cmdx.delete(nodesToDelete) | |
def categorizedPerformanceTestInCmdxNoUndo(): | |
for num in NUM_NODES_LIST: | |
cmds.file(new=True, force=True) | |
with TotalPerfMeasurement( | |
f"Deal with {num} nodes in cmdx without undo" | |
) as measure: | |
with measure.add( | |
f"Create {num}+ nodes in cmdx without undo" | |
): | |
controller, stars, nodes = createInCmdxNoUndo(num) | |
with measure.add(f"Edit {num}+ nodes in cmdx without undo"): | |
editInCmdxNoUndo(controller, stars) | |
with measure.add( | |
f"Rename {num} nodes in cmdx without undo" | |
): | |
renameInCmdxNoUndo(nodes) | |
with measure.add( | |
f"Query {num}+ nodes in cmdx without undo" | |
): | |
queryInCmdxNoUndo(controller, stars) | |
with measure.add( | |
f"Remove {num} nodes in cmdx without undo" | |
): | |
deleteInCmdxNoUndo(nodes) | |
def categorizedPerformanceTestInCmdx(): | |
for num in NUM_NODES_LIST: | |
cmds.file(new=True, force=True) | |
with TotalPerfMeasurement( | |
f"Deal with {num} nodes in cmdx" | |
) as measure: | |
with measure.add( | |
f"Create {num}+ nodes in cmdx" | |
): | |
controller, stars, nodes = createInCmdx(num) | |
with measure.add(f"Edit {num}+ nodes in cmdx"): | |
editInCmdx(controller, stars) | |
with measure.add( | |
f"Rename {num} nodes in cmdx" | |
): | |
renameInCmdx(nodes) | |
with measure.add( | |
f"Query {num}+ nodes in cmdx" | |
): | |
queryInCmdx(controller, stars) | |
with measure.add( | |
f"Remove {num} nodes in cmdx" | |
): | |
deleteInCmdx(nodes) | |
# In case we're called from mayapy | |
try: | |
from maya import standalone | |
standalone.initialize() | |
except RuntimeError: | |
pass | |
categorizedPerformanceTestInCmdx() | |
categorizedPerformanceTestInCmdxNoUndo() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment