Skip to content

Instantly share code, notes, and snippets.

@mottosso

mottosso/test.py Secret

Created December 28, 2023 08:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mottosso/f967b388a2540fdf165dd5b3b6f1c2ca to your computer and use it in GitHub Desktop.
Save mottosso/f967b388a2540fdf165dd5b3b6f1c2ca to your computer and use it in GitHub Desktop.
Performance test of cmdx
# 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