Skip to content

Instantly share code, notes, and snippets.

@hmasato
Created May 10, 2013 06:13
Show Gist options
  • Select an option

  • Save hmasato/5552695 to your computer and use it in GitHub Desktop.

Select an option

Save hmasato/5552695 to your computer and use it in GitHub Desktop.
[MAYA] cfField_min.py (curveFlow Field)
#--------------------------------
# cfField.py: curveFlow Field
#--------------------------------
import math, sys
import maya.OpenMaya as om
import maya.OpenMayaUI as omUI
import maya.OpenMayaMPx as omMPx
import maya.OpenMayaRender as omRen
kPlgName = "cfField"
kPlgID = om.MTypeId(0x87102)
glFT = omRen.MHardwareRenderer.theRenderer().glFunctionTable()
def statusError(msg):
sys.stderr.write("%s\n" % msg)
raise
class cfField(omMPx.MPxFieldNode):
aConstDistance = om.MObject()
aAttractRatioIn = om.MObject()
aAttractRatioOut = om.MObject()
aSectionRatioIn = om.MObject()
aSectionRatioOut = om.MObject()
aTangentRatioIn = om.MObject()
aTangentRatioOut = om.MObject()
aInputCurve = om.MObject()
def __init__(self):
omMPx.MPxFieldNode.__init__(self)
def compute(self, plg, blk):
oForce = omMPx.cvar.MPxFieldNode_mOutputForce
if not (plg == oForce): return
mIdx = plg.logicalIndex()
hInArr = blk.outputArrayValue(omMPx.cvar.MPxFieldNode_mInputData)
hInArr.jumpToElement(mIdx)
hCmpd = hInArr.inputValue()
dP = hCmpd.child(omMPx.cvar.MPxFieldNode_mInputPositions).data()
pnts = om.MFnVectorArrayData(dP).array()
dV = hCmpd.child(omMPx.cvar.MPxFieldNode_mInputVelocities).data()
vels = om.MFnVectorArrayData(dV).array()
dM = hCmpd.child(omMPx.cvar.MPxFieldNode_mInputMass).data()
masses = om.MFnDoubleArrayData(dM).array()
f = om.MVectorArray()
self.__applyCurveFlow(blk, pnts, vels, masses, f)
hOut = blk.outputArrayValue(oForce).builder().addElement(mIdx)
hOut.setMObject(om.MFnVectorArrayData().create(f))
blk.setClean(plg)
#------------------------------------------------------------------
def __applyCurveFlow(self, blk, pnts, vels, masses, oForce):
if pnts.length() != vels.length(): return
mag = self.__magnitude(blk)
if -0.0001 < mag and mag < 0.0001: return
constDist = self.__constDistance(blk)
minDist = 0.0
maxDist = constDist
useMaxDist = self.__useMaxDistance(blk)
if useMaxDist:
minDist = constDist
maxDist = self.__maxDistance(blk)
constDist = maxDist - minDist
if maxDist < 0.0001: return
oForce.clear()
atten = self.__attenuation(blk)
fAttIn = self.__attractRatioIn(blk)
fAttOut = self.__attractRatioOut(blk)
fSectIn = self.__sectionRatioIn(blk)
fSectOut = self.__sectionRatioOut(blk)
fTanIn = self.__tangentRatioIn(blk)
fTanOut = self.__tangentRatioOut(blk)
pos = self.__ownerPos(blk)
crv = self.__inputCurve(blk)
if crv.isNull(): return
try: crvFn = om.MFnNurbsCurve(crv)
except: return
utl = om.MScriptUtil()
pk = om.MScriptUtil().asDoublePtr()
pks = om.MScriptUtil().asDoublePtr()
pke = om.MScriptUtil().asDoublePtr()
crvFn.getKnotDomain(pks, pke)
ks=utl.getDouble(pks)
ke=utl.getDouble(pke)
npnts = pnts.length()
for i in range(npnts):
f = om.MVector(0,0,0)
fallOff = 1.0
v = vels[i]
fv = v.length()
if fv < 0.0001: #-----------------
oForce.append(f)
continue
p = om.MPoint(pnts[i])
cp = crvFn.closestPoint(p, pk, 0.1, om.MSpace.kWorld)
dp = p-cp
fdp = dp.length()
if maxDist < fdp: #-----------------
oForce.append(f)
continue
k = utl.getDouble(pk)
if k <= ks or ke <= k: #-----------------
oForce.append(f)
continue
# u = (k-ks) / (ke-ks)
# n = crvFn.normal(k, om.MSpace.kObject)
t = crvFn.tangent(k, om.MSpace.kWorld)
vt = t * (t * v)
vn = v - vt
vt = vt.normal() * fv #--------force keep length
vn = vn.normal() * fv #--------force keep length
va = -dp.normal() * fv #--------force keep length
dist = 0.0
if fdp > minDist: dist=(fdp-minDist)/constDist
if useMaxDist: fallOff = self.falloffCurve(dist)
Dn = fSectIn * (1.0-dist) + fSectOut * dist
Dt = fTanIn * (1.0-dist) + fTanOut * dist
Da = fAttIn * (1.0-dist) + fAttOut * dist
# f = (vn * Dn + vt * Dt + va * Da - v ) * mag * fallOff
f = (vn * Dn + vt * Dt + va * Da) * mag * fallOff
oForce.append(f)
#------------------------------------------------------------------
def draw (self, view, path, style, status):
TORUS_2PI = 2.0 * 3.14159265
EDGES = 8
SEGMENTS = 8
view.beginGL()
for j in range(SEGMENTS):
glFT.glPushMatrix()
glFT.glRotatef(360.0 * j / SEGMENTS, 0.0, 1.0, 0.0)
glFT.glTranslatef(1.5, 0.0, 0.0)
for i in range(EDGES):
glFT.glBegin(omRen.MGL_LINE_STRIP)
p0 = TORUS_2PI * i / EDGES
p1 = TORUS_2PI * (i+1) / EDGES
glFT.glVertex2f(math.cos(p0), math.sin(p0))
glFT.glVertex2f(math.cos(p1), math.sin(p1))
glFT.glEnd()
glFT.glPopMatrix()
view.endGL()
def getForceAtPoint(self, pnts, vels, masses, oForce, dtime):
blk = forceCache()
self.__applyCurveFlow(blk, pnts, vels, masses, oForce)
def __ownerPos(self, blk):
oP = om.MVectorArray()
if self.__applyPerVertex(blk):
try: hOP = blk.inputValue(omMPx.cvar.MPxFieldNode_mOwnerPosData)
except: oP.append(self.__getWPos())
else:
fnOP = om.MFnVectorArrayData(hOP.data())
try: posArray = fnOP.array()
except: oP.append(self.__getWPos())
else:
for i in range(posArray.length()): oP.append(posArray[i])
else:
try: oC = self.__ownerCentroid(blk)
except: oP.append(self.__getWPos())
else:
oP.append(oC)
return oP
def __getWPos(self):
node = self.thisMObject()
fn = om.MFnDependencyNode(node)
wMtxAttr = fn.attribute("worldMatrix")
mtxplg = om.MPlug(node, wMtxAttr).elementByLogicalIndex(0)
mtxObj = mtxplg.asMObject(mtxObj)
wmtx = om.MFnMatrixData(mtxObj).matrix()
return om.MVector(wmtx(3, 0), wmtx(3, 1), wmtx(3, 2))
def __magnitude(self, blk):
return blk.inputValue(omMPx.cvar.MPxFieldNode_mMagnitude).asDouble()
def __attenuation(self, blk):
return blk.inputValue(omMPx.cvar.MPxFieldNode_mAttenuation).asDouble()
def __maxDistance(self, blk):
return blk.inputValue(omMPx.cvar.MPxFieldNode_mMaxDistance).asDouble()
def __useMaxDistance(self, blk):
return blk.inputValue(omMPx.cvar.MPxFieldNode_mUseMaxDistance).asBool()
def __applyPerVertex(self, blk):
return blk.inputValue(omMPx.cvar.MPxFieldNode_mApplyPerVertex).asBool()
def __constDistance(self, blk):
return blk.inputValue(cfField.aConstDistance).asDouble()
def __attractRatioIn(self, blk):
return blk.inputValue(cfField.aAttractRatioIn).asDouble()
def __attractRatioOut(self, blk):
return blk.inputValue(cfField.aAttractRatioOut).asDouble()
def __sectionRatioIn(self, blk):
return blk.inputValue(cfField.aSectionRatioIn).asDouble()
def __sectionRatioOut(self, blk):
return blk.inputValue(cfField.aSectionRatioOut).asDouble()
def __tangentRatioIn(self, blk):
return blk.inputValue(cfField.aTangentRatioIn).asDouble()
def __tangentRatioOut(self, blk):
return blk.inputValue(cfField.aTangentRatioOut).asDouble()
def __inputCurve(self, blk):
try:
return blk.inputValue(cfField.aInputCurve).asNurbsCurve()
# return blk.inputValue(cfField.aInputCurve).asNurbsCurveTransformed()
except:
return om.MObject().kNullObj;
def __ownerCentroid(self, blk):
hX = blk.inputValue(omMPx.cvar.MPxFieldNode_mOwnerCentroidX)
hY = blk.inputValue(omMPx.cvar.MPxFieldNode_mOwnerCentroidY)
hZ = blk.inputValue(omMPx.cvar.MPxFieldNode_mOwnerCentroidZ)
return om.MVector(hX.asDouble(), hY.asDouble(), hZ.asDouble())
def nodeCreator():
return omMPx.asMPxPtr(cfField())
def nodeInitializer():
nTyp=om.MFnNumericData
numAttr = om.MFnNumericAttribute()
cfField.aConstDistance = numAttr.create("constDistance", "ctd", nTyp.kDouble, 10.0)
numAttr.setKeyable(True)
cfField.addAttribute(cfField.aConstDistance)
cfField.aAttractRatioIn = numAttr.create("attractRatioIn", "ati", nTyp.kDouble, 0.0)
numAttr.setKeyable(True)
cfField.addAttribute(cfField.aAttractRatioIn)
cfField.aAttractRatioOut = numAttr.create("attractRatioOut", "ato", nTyp.kDouble, 0.0)
numAttr.setKeyable(True)
cfField.addAttribute(cfField.aAttractRatioOut)
cfField.aSectionRatioIn = numAttr.create("sectionRatioIn", "sci", nTyp.kDouble, 0.0)
numAttr.setKeyable(True)
cfField.addAttribute(cfField.aSectionRatioIn)
cfField.aSectionRatioOut = numAttr.create("sectionRatioOut", "sco", nTyp.kDouble, -1.0)
numAttr.setKeyable(True)
cfField.addAttribute(cfField.aSectionRatioOut)
cfField.aTangentRatioIn = numAttr.create("tangentRatioIn", "tgi", nTyp.kDouble, 0.0)
numAttr.setKeyable(True)
cfField.addAttribute(cfField.aTangentRatioIn)
cfField.aTangentRatioOut = numAttr.create("tangentRatioOut", "tgo", nTyp.kDouble, 0.0)
numAttr.setKeyable(True)
cfField.addAttribute(cfField.aTangentRatioOut)
typAttr = om.MFnTypedAttribute()
cfField.aInputCurve = typAttr.create('inputCurve', 'icv', om.MFnData.kNurbsCurve)
typAttr.setStorable(True)
cfField.addAttribute(cfField.aInputCurve)
cfField.attributeAffects(cfField.aInputCurve, omMPx.cvar.MPxFieldNode_mOutputForce)
def initializePlugin(mobj):
mplg = omMPx.MFnPlugin(mobj, "Autodesk", "1.0", "Any")
try: mplg.registerNode(kPlgName, kPlgID, nodeCreator, nodeInitializer, omMPx.MPxNode.kFieldNode)
except: statusError("Failed to register node: %s" % kPlgName)
def uninitializePlugin(mobj):
mplg = omMPx.MFnPlugin(mobj)
try: mplg.deregisterNode(kPlgID)
except: statusError("Failed to deregister node: %s" % kPlgName)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment