Maya positionPP

Hi All,

im roughing out something quickly as a vfx test with the vray metaball plugin. The idea being to bind nParticles to locator positions, the end result of which ill probably use an objectSet of sorts and swap out locators, add an extension to query vertex positions if a mesh is in the object set instead of a locator.

anyway, Im not typically required to work much with dynamics/particles but ive managed to get the below working as a prototype. The only issue is that i cant get it to evaluate every frame. At the moment, it only calculated on the first frame.

Ive placed it under a script node ( on demand / time change ), and within the nparticle itself ( positioned within an expression for the attribute ) neither seem to force a recalculation. I’m assuming because its not marking the dependency node as dirty - but then again, im not an expert on DG plugins so i could be off.

If anyone could lead me in the right direction that would be great. below is what ive done in python. Im calling it in the expression editor using “python calcPositions()”; - with the function simply loaded into pythons global space.


def calcPositions():
	nParticle_obj = pm.ls(type='nParticle')
	
	if len(nParticle_obj) < 1:
		pm.nParticle()
	
	nParticle_obj = pm.ls(type='nParticle')[0]
	nParticle_Trans = nParticle_obj.getParent()
	
	nCount = pm.nParticle(nParticle_obj, count=True, query=True)
	locCount = len(pm.ls(type='locator'))
	
	nPositions = []
	
	for l in pm.ls(type='locator'):
		trans = pm.listRelatives(l, p=True)[0]
		nPositions.append(pm.xform(trans, ws=True, q=True, t=True))
		
	for p in range(locCount):
		if p > nCount - 1:
			pm.emit(o=nParticle_Trans, pos=nPositions[p])
		else:	
			pm.setParticleAttr(nParticle_obj.pt[p], at="position", vv=nPositions[p])

What version of Maya? I have a couple of solutions at hand. If you have Maya2016 this will work…



import maya.cmds as cmds

mel_expr = '''
$this = `ls "{0}"`;
$driver_set = `ls "{1}"`;
$drivers = `sets -q $driver_set[0]`;
int $pid = YEAH_dps2Shape.particleId;

if(id==0){{
	$pcount = count;
	while($pcount < size($drivers)){{
		emit -pos 0 0 0 -object $this[0];
		$pcount += 1;
	}}
}}

if($pid < size($drivers)){{
	float $pos[] = `xform -q -ws -rp $drivers[$pid]`;
    vector $vpos = <<$pos[0], $pos[1], $pos[2]>>;
    if(frame<=startFrame + 1){{
        position = $vpos;
    }} else {{
        velocity = ($vpos - position) * 24;
    }}
}} else {{
	YEAH_dps2Shape.lifespanPP = 0;
}}
'''


def particle_driver_set(name, transforms):   
    # Create our set and get a UUID
    set = cmds.sets(name=name + '_pds#')
    cmds.sets(transforms, e=True, addElement=set)
    set_uuid = cmds.ls(set, uuid=True)[0]
    
    # Create one particle for each transform and get another UUID
    particles = [cmds.xform(t, q=True, ws=True, rp=True) for t in transforms]
    np, npshape = cmds.nParticle(p=particles, name=name + '_dps#')
    cmds.setAttr(npshape + '.lifespanMode', 3)
    np_uuid = cmds.ls(npshape, uuid=True)[0]
    
    # Create our runtimeBeforeDynamicExpression
    before_expr = mel_expr.format(np_uuid, set_uuid)
    cmds.dynExpression(npshape, runtimeBeforeDynamics=True, string=before_expr)


particle_driver_set('Particle_Driver', cmds.ls(sl=True))

Select a bunch of locators and run that bit. The really interesting thing here is that it uses node UUID’s instead of names directly. So this expression even though it’s using standard mel commands within it, should work even when referenced. Exposing uuids to mel and python is pretty amazing!

The other solution would be to use Soup nodes and do this using goals.
1. Connect the transforms to a transformsToArray node
2. Connect transformsToArray.outArray >> pointCloudToMesh.inPositionPP
3. Connect pointCloudToMesh.outMesh >> mesh.inMesh
4. Use the mesh as a goal for some nParticles

I think the mel expression method is kind of cool, especially since it will dynamically add or remove particles on playback so you always have 1 particle per transform. However, I’d probably go the Soup route and script bits of it for convenience, it just requires so much less maintenance than mel particle expressions.