MetaBox/Scripts/Modeling/Edit/CreasePlus/CreasePlusNodes.py
2025-01-14 02:59:09 +08:00

507 lines
15 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
_____ _____ ______ _____ ______
/ ____| __ \| ____| /\ / ____| ____|_
| | | |__) | |__ / \ | (___ | |__ _| |_
| | | _ /| __| / /\ \ \___ \| __|_ _|
| |____| | \ \| |____ / ____ \ ____) | |____|_|
\_____|_| \_\______/_/ \_\_____/|______|
"""
# import maya.cmds as mc
import maya.api.OpenMaya as om
# import copy
# uses python maya 2
maya_useNewAPI = True
#################
def cPhardEdgeIds(mesh):
edgeIter = om.MItMeshEdge(mesh)
ids = []
while not edgeIter.isDone():
if not edgeIter.isSmooth:
ids.append(edgeIter.index())
edgeIter.next()
return ids
def cPcompToIds(compdata, cptyp):
compDataFn = om.MFnComponentListData(compdata)
# compDataFn
ids = []
for i in range(compDataFn.length()):
curcomp = compDataFn.get(i)
if curcomp.hasFn(cptyp):
sic = om.MFnSingleIndexedComponent(curcomp)
for j in range(sic.elementCount):
curIdx = sic.element(j)
ids.append(curIdx)
return ids
def cPidsToComp(ids, cptyp):
sic = om.MFnSingleIndexedComponent()
sic.create(cptyp) # om.MFn.kMeshEdgeComponent
sic.addElements(ids)
compData = om.MFnComponentListData()
compObj = compData.create()
compData.add(sic.object())
return (sic.object(), compObj)
def cPtransformMeshPoints(mesh, mat):
meshFn = om.MFnMesh(mesh)
pts = meshFn.getPoints()
for pt in pts:
pt *= mat
meshFn.setPoints(pts)
"""
input: mesh
output: componentlist
"""
MayaNodeT = om.MPxNode
class CpCurveBevel(MayaNodeT):
kNodeName = "creasePlusCurveBevel"
kNodeId = om.MTypeId(0x1154)
aCvs = None
aOffset = None
aSeg = None
aOffsetFrac = None
aInputCurve = None
aOutput = None
def __init__(self):
super(CpCurveBevel, self).__init__()
@classmethod
def creator(cls):
return cls()
@classmethod
def initialize(cls):
nAttr = om.MFnNumericAttribute()
tAttr = om.MFnTypedAttribute()
cls.aCvs = tAttr.create("cvComponentList", "cvs",
om.MFnComponentListData.kComponentList)
cls.aOffset = nAttr.create("offset", "off", om.MFnNumericData.kFloat)
nAttr.setMin(0)
nAttr.default = 0.5
nAttr.keyable = True
cls.aSeg = nAttr.create("segments", "seg", om.MFnNumericData.kInt)
nAttr.setMin(1)
nAttr.default = 1
nAttr.keyable = True
cls.aOffsetFrac = nAttr.create("offsetAsFraction", "oaf",
om.MFnNumericData.kBoolean)
nAttr.default = False
nAttr.keyable = True
cls.aInputCurve = tAttr.create("inCurve", "inc",
om.MFnData.kNurbsCurve)
cls.aOutput = tAttr.create("outCurve", "out", om.MFnData.kNurbsCurve)
tAttr.storable = False
tAttr.writable = False
MayaNodeT.addAttribute(cls.aCvs)
MayaNodeT.addAttribute(cls.aOffset)
MayaNodeT.addAttribute(cls.aSeg)
MayaNodeT.addAttribute(cls.aOffsetFrac)
MayaNodeT.addAttribute(cls.aInputCurve)
MayaNodeT.addAttribute(cls.aOutput)
MayaNodeT.attributeAffects(cls.aCvs, cls.aOutput)
MayaNodeT.attributeAffects(cls.aOffset, cls.aOutput)
MayaNodeT.attributeAffects(cls.aSeg, cls.aOutput)
MayaNodeT.attributeAffects(cls.aOffsetFrac, cls.aOutput)
MayaNodeT.attributeAffects(cls.aInputCurve, cls.aOutput)
def setOutputToCopy(self, data):
inCurveHandle = data.inputValue(CpCurveBevel.aInputCurve)
outHandle = data.outputValue(CpCurveBevel.aOutput)
outHandle.copy(inCurveHandle)
outHandle.setClean()
def compute(self, plug, data):
if plug != CpCurveBevel.aOutput:
return None
inCurveHandle = data.inputValue(CpCurveBevel.aInputCurve)
inCurve = inCurveHandle.asNurbsCurveTransformed()
inCvsHandle = data.inputValue(CpCurveBevel.aCvs)
compData = inCvsHandle.data()
ids = cPcompToIds(compData, om.MFn.kCurveCVComponent)
#
inOffset = data.inputValue(CpCurveBevel.aOffset).asFloat()
inSeg = data.inputValue(CpCurveBevel.aSeg).asInt()
inFrac = data.inputValue(CpCurveBevel.aOffsetFrac).asBool()
if len(ids) == 0 or inOffset == 0:
self.setOutputToCopy(data)
return
curveFn = om.MFnNurbsCurve(inCurve)
curveDegree = curveFn.degree
curveForm = curveFn.form
# curveKnots = curveFn.knots()
curvePts = curveFn.cvPositions() # to be modified
numcv = len(curvePts) # to be modified
bevelParam = 1 / float(inSeg)
bevelPts = []
ids.sort()
for cvIdx in ids:
mpos = om.MVector(curvePts[cvIdx])
if curveForm == curveFn.kPeriodic:
lpos = om.MVector(curvePts[(cvIdx + numcv -
(1 + curveDegree)) %
(numcv - curveDegree)])
rpos = om.MVector(curvePts[(cvIdx + 1) %
(numcv - curveDegree)])
else:
lpos = om.MVector(curvePts[(cvIdx + numcv - 1) % numcv])
rpos = om.MVector(curvePts[(cvIdx + 1) % numcv])
lvec = lpos - mpos
rvec = rpos - mpos
lanchor = None
ranchor = None
if inFrac:
lanchor = mpos + (inOffset * lvec)
ranchor = mpos + (inOffset * rvec)
else:
lanchor = mpos + (inOffset * lvec.normal())
ranchor = mpos + (inOffset * rvec.normal())
bevelPts.append(lanchor)
t = 1 * bevelParam
for i in range(inSeg - 1):
# (1-t)^2A+2t(1-t)B+t^2C
res = (1 - t)**2 * lanchor + (2 * t * (1 - t) * mpos) + (
t**2 * ranchor)
bevelPts.append(res)
t += bevelParam
bevelPts.append(ranchor)
#
i = len(bevelPts) - (inSeg + 1)
ids.sort(reverse=True)
for cvIdx in ids:
curvePts[cvIdx] = bevelPts[i]
curvePts[cvIdx + 1:cvIdx + 1] = bevelPts[i + 1:i + inSeg + 1]
i -= (inSeg + 1)
numcv = len(curvePts)
if curveForm == curveFn.kPeriodic:
curvePts[-curveDegree:] = curvePts[:curveDegree]
if curveDegree == 1:
knots = [float(i) for i in range(numcv)]
else:
knots = [None] * (numcv - curveDegree + (2 * curveDegree) - 1)
if curveForm == curveFn.kPeriodic:
knots[:curveDegree] = [
float(i) for i in reversed(range(0, -curveDegree, -1))
]
knots[curveDegree:] = [
float(i) for i in range(1,
len(knots) - curveDegree + 1)
]
else:
knots[:curveDegree] = [float(0)] * curveDegree
knots[-curveDegree:] = [float(numcv - curveDegree)
] * curveDegree
knots[curveDegree:-curveDegree] = [
float(i)
for i in range(1,
len(knots) - (2 * curveDegree) + 1)
]
curveDataFn = om.MFnNurbsCurveData()
curveDataFn.create()
knots = om.MDoubleArray(knots)
curveFn.create(
curvePts,
knots,
curveDegree,
curveForm,
False,
False,
parent=curveDataFn.object())
out = data.outputValue(CpCurveBevel.aOutput)
out.setMObject(curveDataFn.object())
out.setClean()
class CpCurveToPoly(MayaNodeT):
kNodeName = "creasePlusCurveToPoly"
kNodeId = om.MTypeId(0x12547)
aCount = None
aRevNorm = None
aControlPts = None
aInputCurve = None
aOutput = None
def __init__(self):
super(CpCurveToPoly, self).__init__()
@classmethod
def creator(cls):
return cls()
@classmethod
def initialize(cls):
nAttr = om.MFnNumericAttribute()
tAttr = om.MFnTypedAttribute()
cls.aRevNorm = nAttr.create("reverse", "rev",
om.MFnNumericData.kBoolean)
nAttr.default = False
nAttr.keyable = True
cls.aCount = nAttr.create("count", "cnt", om.MFnNumericData.kInt)
nAttr.setMin(3)
nAttr.default = 12
nAttr.keyable = True
cls.aControlPts = nAttr.create("controlPts", "cv",
om.MFnNumericData.kBoolean)
nAttr.default = True
nAttr.keyable = True
cls.aInputCurve = tAttr.create("inCurve", "inc",
om.MFnData.kNurbsCurve)
cls.aOutput = tAttr.create("outPoly", "out", om.MFnData.kMesh)
tAttr.storable = False
tAttr.writable = False
MayaNodeT.addAttribute(cls.aRevNorm)
MayaNodeT.addAttribute(cls.aCount)
MayaNodeT.addAttribute(cls.aControlPts)
MayaNodeT.addAttribute(cls.aInputCurve)
MayaNodeT.addAttribute(cls.aOutput)
MayaNodeT.attributeAffects(cls.aRevNorm, cls.aOutput)
MayaNodeT.attributeAffects(cls.aCount, cls.aOutput)
MayaNodeT.attributeAffects(cls.aControlPts, cls.aOutput)
MayaNodeT.attributeAffects(cls.aInputCurve, cls.aOutput)
def setOutputToNull(self, data):
out = data.outputValue(CpCurveToPoly.aOutput)
out.setMObject(om.MObject.kNullObj)
out.setClean()
def compute(self, plug, data):
if plug != CpCurveToPoly.aOutput:
return None
reverseNormal = data.inputValue(CpCurveToPoly.aRevNorm).asBool()
inCurveHandle = data.inputValue(CpCurveToPoly.aInputCurve)
inCurve = inCurveHandle.asNurbsCurveTransformed()
inCount = data.inputValue(CpCurveToPoly.aCount).asInt() #
useCvs = data.inputValue(CpCurveToPoly.aControlPts).asBool()
curveFn = om.MFnNurbsCurve(inCurve)
curveForm = curveFn.form
curveDegree = curveFn.degree
polyPts = None
meshDataFn = om.MFnMeshData()
meshDataFn.create()
if useCvs:
if curveForm == curveFn.kPeriodic:
polyPts = curveFn.cvPositions()[:-curveDegree]
else:
polyPts = curveFn.cvPositions()
else:
polyPts = []
domain = curveFn.knotDomain
param = domain[1] / float(inCount)
t = 0.0
for i in range(inCount):
polyPts.append(curveFn.getPointAtParam(t))
t += param
if reverseNormal:
polyPts = [pt for pt in reversed(polyPts)]
# create(vertices, polygonCounts, polygonConnects, uValues=None, vValues=None, parent=kNullObj) -> MObject
meshFn = om.MFnMesh()
meshFn.create(
polyPts, [len(polyPts)], [i for i in range(len(polyPts))],
parent=meshDataFn.object())
out = data.outputValue(CpCurveToPoly.aOutput)
out.setMObject(meshDataFn.object())
out.setClean()
class CpHeIds(MayaNodeT):
kNodeName = "creasePlusBevelHe"
kNodeId = om.MTypeId(0x1157)
aForceComp = None
aInputMesh = None
aIds = None
def __init__(self):
super(CpHeIds, self).__init__()
self.numVertices = 0
self.numPolygons = 0
self.numNormals = 0
self.dummycompute = False
@classmethod
def creator(cls):
return cls()
@classmethod
def initialize(cls):
tAttr = om.MFnTypedAttribute()
nAttr = om.MFnNumericAttribute()
cls.aForceComp = nAttr.create("forceCompute", "fc",
om.MFnNumericData.kBoolean, 0)
nAttr.default = False
nAttr.keyable = True
cls.aInputMesh = tAttr.create("inMesh", "i", om.MFnData.kMesh)
cls.aIds = tAttr.create("componentList", "cl",
om.MFnComponentListData.kComponentList)
tAttr.storable = False
tAttr.writable = False
MayaNodeT.addAttribute(cls.aForceComp)
MayaNodeT.addAttribute(cls.aInputMesh)
MayaNodeT.addAttribute(cls.aIds)
def attrToPlug(self, attr):
return om.MPlug(self.thisMObject(), attr)
def setDependentsDirty(self, plug, affect):
if plug == CpHeIds.aForceComp:
if self.dummycompute == False:
self.dummycompute = True
affect.append(self.attrToPlug(CpHeIds.aIds))
else:
self.dummycompute = False
elif plug == CpHeIds.aInputMesh:
affect.append(self.attrToPlug(CpHeIds.aIds))
def compute(self, plug, data):
if plug != CpHeIds.aIds:
return None
doingit = False
data.inputValue(CpHeIds.aForceComp)
inMeshHandle = data.inputValue(CpHeIds.aInputMesh)
inmesh = inMeshHandle.asMesh()
meshFn = om.MFnMesh(inmesh)
if self.dummycompute == True:
doingit = True
elif (self.numVertices != meshFn.numVertices
or self.numPolygons != meshFn.numPolygons
or self.numNormals != meshFn.numNormals):
doingit = True
if doingit == True:
heIds = cPhardEdgeIds(inmesh)
compObj = cPidsToComp(heIds, om.MFn.kMeshEdgeComponent)[1]
outIdsHandle = data.outputValue(CpHeIds.aIds)
outIdsHandle.setMObject(compObj)
outIdsHandle.setClean()
if self.dummycompute == True:
forceCompplug = self.attrToPlug(CpHeIds.aForceComp)
forceCompplug.setBool(False)
def initializePlugin(obj):
mplugin = om.MFnPlugin(obj, "Baidhir Hidair", "1.0")
nodeName = None
try:
nodeName = CpHeIds.kNodeName
mplugin.registerNode(CpHeIds.kNodeName, CpHeIds.kNodeId,
CpHeIds.creator, CpHeIds.initialize)
nodeName = CpCurveBevel.kNodeName
mplugin.registerNode(CpCurveBevel.kNodeName, CpCurveBevel.kNodeId,
CpCurveBevel.creator, CpCurveBevel.initialize)
nodeName = CpCurveToPoly.kNodeName
mplugin.registerNode(CpCurveToPoly.kNodeName, CpCurveToPoly.kNodeId,
CpCurveToPoly.creator, CpCurveToPoly.initialize)
except:
raise Exception('failed to register node: ' + nodeName)
def uninitializePlugin(obj):
mplugin = om.MFnPlugin(obj)
nodeName = None
try:
nodeName = CpHeIds.kNodeName
mplugin.deregisterNode(CpHeIds.kNodeId)
nodeName = CpCurveBevel.kNodeName
mplugin.deregisterNode(CpCurveBevel.kNodeId)
nodeName = CpCurveToPoly.kNodeName
mplugin.deregisterNode(CpCurveToPoly.kNodeId)
except:
raise Exception('failed to deregister node: ' + nodeName)