PDA

View Full Version : A probably simple Python question...


surreal-reality
03-23-2010, 10:08 PM
ok, I'm kind of new to this level of scripting, and I'm just not really sure of the proper syntax required to do what I'm envisioning..

I have a variable:
arrayNC = 0
then I turn it into a string:
arrayNameInt = str(arrayNC)
then I concatenate it with a prefix, to get a name, that has an incrementally increasing end number(for use in a loop, and creating multiple objects etc.):
arrayNameFull = "arrayOfFloats_" + arrayNameInt
the resulting string looks like:
arrayOfFloats_0, arrayOfFloats_1, arrayOfFloats_2, etc etc etc.

The next part is where I get stuck, I want to take the string : "arrayOfFloats_0" and make it the name of a list.

What would be the best way to do this, so that I can say, store an xyz coord into the list?

My next problem, is when I try and use:
cmds.pointPosition( 'pPlane2.vtx[arrayNC]' )
I know that the vtx part wants an int in the []'s, but I want to use the above variable: "arrayNC = 0" as the vertex number I use.
I am totally lost as to how to do this part too! Putting the variable directly in the []'s seems to not work for me, I'm sure this is something simple.. Thanks!

NaughtyNathan
03-23-2010, 10:45 PM
you probably want a python dictionary for this kind of thing. You don't need to generate a list of names then make them into arrays (python calls them lists) you simply create it all in one go as a dictionary.

e.g.


myDict = {}

for i in range(10): # make 10 "arrays" of floats
name = 'arrayoffloats_%d' % i
myDict[name] = [0.0, 1.0, -6.5, 8.9, 0.6] # basically, generate your array content here, now

then:
print myDict['arrayoffloats_3'] # print array 3



this is a very quick example, check out the python docs for dictionaries.

as for referencing variables in strings.. the % syntax is the basic way to do it:

cmds.pointPosition( 'pPlane2.vtx[%d]' % arrayNC )


:nathaN

moonangel
03-23-2010, 10:50 PM
for your first question, i don't exactly understand, WHAT you want to do.

for the second one:
if you have a identifier in your script, and you want to add its value into a string, you cannot simply type the name of your variable inside the string (perl would actually work that way, i think). in python you have to concatenate your string and your identifiers value:

cmds.pointPosition( 'pPlane2.vtx['+str(arrayNC)+']' )

alternatively you could use regular expressions, see the python documentation for more information on that.

... too slow, and in the foregoing post, you see the example of using regular expressions :D

surreal-reality
03-24-2010, 12:37 AM
Thank you! I haven't tried this yet, but it looks like just what I needed. I appreciate it! if I get what I'm trying to do, done, I'll post it back here later.

surreal-reality
03-24-2010, 04:07 PM
So I've made some progress with your help, but I'm stuck again, hopefully it's something simple yet again!

The script is supposed to make a simple expression, constraining a cube, to a vert on a plane, and move on to the next vert, assign a new cube, etc etc, so that the plane could be deformed, and the cubes would all follow their respective verts later.

The for in loop works, up until I need to set the actual expression, this is what I have for this line:
cmds.expression(ae = True, s='hCube%d.translateX = (arrayDict["arrayOfFloats_%d"][0]))' % (arrayNC, arrayNC))

so basically, I'm telling it to take the cube who's suffix is the int, arrayNC
I got this part to work fine, it's when I tried to use %d to call the dictionary's list in conjunction with the %d I used for the cubes name that I ran into problems.

I saw a few posts on other forums describing using a tupil, and stick it at the end, which seemed to work for everyone else, but maybe I'm doing something wrong still.
Any ideas?

and for good measure, here's all I have so far, incase I was unclear.

import maya.cmds as cmds;
reload(cmds);


vertCount = 0; #variable used for holding the vert count of the selected plane
vertCount = cmds.polyEvaluate( v=True) - 1; # takes the total vert count of the plane
print vertCount; #prints it out for good measure

arrayNC = 0; # upwards counter for the dict suffix

cubeNC = 0; # int part of the cubes name
cubeNameInt = str(cubeNC); #the name part of the cubes name
cubeNameFull = "hCube" + cubeNameInt; # concatenation of the cubes name, and int

arrayDict = {}; # create the dictionary for use later

for i in range(vertCount + 1): # uses variable vertCount to know how many dict's to create
name = 'arrayOfFloats_%d' % arrayNC; #sets the name of the dict, using a prefix, and %d to use the specified int that comes later
tempArray = cmds.pointPosition( 'pPlane2.vtx[%d]' % arrayNC);
arrayDict[name] = tempArray; # basically, generate your array content here, now

cmds.polyCube(n = cubeNameFull); # create the cube
cmds.expression(ae = True, s='hCube%d.translateX = (arrayDict["arrayOfFloats_%d"][0]))' % (arrayNC, arrayNC)) # set up the expressions




print "Still Working!", str(arrayNC);
arrayNC = arrayNC + 1;
cubeNC = cubeNC + 1;


print arrayDict['arrayOfFloats_3'][0] # print array of dict
print arrayDict['arrayOfFloats_10'] # print array of dict

NaughtyNathan
03-24-2010, 05:19 PM
Hey Lucas, you have a fair few problems here unfortunately.. I think the basic problem you have is that expressions have to be written purely in a MEL style code. And whether you meant it or not, you've put the dictionary reference directly into the expression string and you can't use any python in an expression (well, not like this anyway).

also, this expression simply won't work the way you've constructed it. if you want the cube to be constrained to the vert you'll have to make the actual expression query the pointPosition, and you know expressions like this only evaluate during playback right?

:nathaN

What exactly is it you want to do?, have a polyPlane that has a polyCube stuck to every one of it's verts in realtime?

surreal-reality
03-24-2010, 05:47 PM
Yes, I see what you mean, the expression did have a bit of python mixed in there, good to know for the future that those don't mix in expressions.
What about the %d
I take it that is mel then, I was able to use that in the expression when it was only used for the cube's name.
What about the mel.eval command? is this an appropriate or even possible use for that?

If it only queried during playback, that would be better than nothing actually, but if it is possible somehow to have it 100% realtime, that would be best.
See I wanted to make deformations to the underlying plane, and I could use that as a visual reference, then on time for render, or play blasts, just leave the cubes visible and hide the plane.

maybe I'm approaching this the wrong way but the original code that gave me the idea for doing it this way, was this:

float arrayOfFloats_0[]=`pointPosition pPlane1.vtx[13]`;
pCube4.translateX = $arrayOfFloats_13[0];
pCube4.translateY = $arrayOfFloats_13[1];
pCube4.translateZ = $arrayOfFloats_13[2];

and it's quite different with mel, so that's why I was having troubles getting this concept to python, and also the loop made things a bit more complex..

Essentially, yes. I simply want a poly plane with a cube at every vert stuck to it.

my end goal, was to simulate water, or animate displacement, then either skin or apply it to the plane, then have it control the cubes, really just in Y. Kind of wanted that pixel/cube/tron look or whatever you call it, where instead of a smooth plane, it's represented by cubes.

What do you think? is there a better way to approach this? I'm not stuck on this method, but I liked it because it seemed like it would be a fairly small amount of code.

Thanks again,

Lucas

NaughtyNathan
03-24-2010, 10:10 PM
you can execute pretty much any MEL inside an expression (afaik) although some commands are less desireable than others (i.e. setAttr/getAttr) so theoretically you could use the python MEL command and run any python code you like in an expression...

the %d syntax is totally python, because in python you can only catenate strings together, but in MEL you don't need anything like this because you can just catenate any variables to a string using +:


py: myStr = 'a string which contains a float: %f and an int: %d' % ( floatVar , intVar )
MEL: $myStr = ("a string which contains a float: "+$floatVar+" and an int: "+$intVar );


as for your ultimate aim, I can think of quite a few different ways it could be approached, but I couldn't say for sure which would work best... if it were me, I'd probably go the connectAttr route rather than expressions.

One way I can think of off the top of my head, is to ditch the poly plane in favour of a nurbs one (far easier to work in nurb UV space than to get poly position info)
Then create a pointOnSurfaceInfo utility node for each cube, and connect this to a UV position on the nurbs plane and to the cube position.

here's some code as an example:


import maya.cmds as mc
res = 8 # how many cubes x,y do you want?
plane = mc.nurbsPlane(d=3,u=1,v=1,w=(res-1),ax=(0,1,0))[0]
for i in range(res):
for j in range(res):
posi = mc.createNode('pointOnSurfaceInfo',ss=1)
cube = mc.polyCube()[0]
mc.setAttr(posi+'.turnOnPercentage',1)
mc.setAttr(posi+'.parameterU', float(i)/(res-1))
mc.setAttr(posi+'.parameterV', float(j)/(res-1))
mc.connectAttr(plane+'.local', posi+'.is')
mc.connectAttr(posi+'.position', cube+'.t')

# these lines just set an initial offset on the plane to show the effect:
mc.setAttr(plane+'.cv[0][3]', 0,2,0)
mc.setAttr(plane+'.cv[2][1]', 0,4,0)
mc.setAttr(plane+'.cv[3][0]', 0,3,0)



and this is cool as it's all fully realtime... you can edit/deform the nurbs plane however you like. You can even move the plane to somewhere else in the scene to edit it without the cubes obscuring it... but of course if you wanted the cubes to follow it just make them children.

:nathaN

surreal-reality
03-24-2010, 11:12 PM
I can't believe it! you're totally awesome, thank you. I've been toying with a way to do this with scripting, or automate it somehow for months now.. and in one day(quite alot less probably) you come up with an even better solution.
Again thank you, I will go and study this code more closely tonight, but this is perfect. Nurbs was a good idea!

Have a good one!

Lucas

surreal-reality
03-24-2010, 11:15 PM
One more quick question, is there anything special about the i and the j? I always see that being used..

NaughtyNathan
03-25-2010, 02:09 PM
heh, no worries... the stuff I have to do at work is tediously boring* compared to this fun stuff, so I enjoy it :D

I have no idea where the i and j convention came from, it was like that even 25 odd years ago programming ZX81 and Spectrum BASIC.. probably "i" because it's an int counter and once i is used you move on to the next available letter... n and m are another common pair...

But they're just arbitrary variable names so there's no actual reason for "i" and "j", they may as well be labelled gary and ash or pee and poo lol!

:nathaN

*only joking if you're reading this Boss Sir.

CGTalk Moderation
03-25-2010, 02:09 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.