Hi,
A friend of mine told me that it is easier to learn how to code with a project. Now I have a project, and i don't know how to code. So here begin my journey on maxscript.
My project: For some time, i used to make a relatively easy rig for my character,(i don't like CAT for some reason) And i managed to make it pretty solid. But it still take almost a day per character to put it in place. So I want to write a code wich will set it up for me.
Right now, I manage to write the setup of the basic bones which will be use with the skin modifier. But in order to keep the scene clean, i'd like to move all the bones in a new layer. That's where i'm stuck.
As I said I don't know how to code, and i'm asking for help
/*create base*/
boneSys.createBone [0,0,0] [0,-30,0] [1,0,0]
select $Bone001
$.name = "base"
boneSys.createBone [0,-30,0] [0,-40,0] [1,0,0]
select $Bone001
$.name = "nub_base"
$.parent = $base
/*select all bones*/
select (for b in objects where classof b == boneGeometry collect b)
/* create new layer and store bones */
Layer = LayerManager.newLayerFromName "MC_bones"
So here a part of what I have so far:
a bone and his nub
then a selection of all bones
then the creation of a new layer.
Now how can i make all the bone to go ine the new layer?
Or how can i create a new layer, select it and create the bone inside?
Thanks for reading
Replies
http://docs.autodesk.com/3DSMAX/16/ENU/MAXScript-Help/index.html?url=files/GUID-78B79975-7BA5-4A03-8FEF-27E78D14B575.htm,topicNumber=d30e259872
You will need to define the layer probably with "getLayerFromName" and then use ".addnode" to put whatever on that layer. The code could look something like this...
I did read the doc, and search over google , but as i said, i really started programming like 5 hour ago... So it is still hard to figure out what all the stuff mean or how to use it.
Like in your piece of code, i have am not sur to understand:
"Selection as array"
"Layer.addNode $"
and why the second line start with "layer ="
I'll try to figure it out^^
In this case the word Layer is more than just a word in the lines above I told it that Layer = "get Layer From this Name: MyLayerName" So anytime it sees the word layer it will go looking for a layer with that specific name.
Then maxscript has a function called ".addnode" which adds whatever comes next to the layer. In this case what comes after .addNode is $ which means selection to maxscript.
So the line Layer.addnode $ means:
Get this specific layer name and add selection to it.
CurSel = Selection as array
This means take whatever is selected and create a group of objects (technically called an array) called "CurSel" (CURrent SELection). It could be called Bob if you wanted to it doesn't really matter.
So now instead of having to know the name of every bone you now have a group of things from a selection. Which is handy because a literal script with hard coded names will only work if the names match. What if you didn't want to write the name of every bone or what if the names or number of bones were not the same from rig to rig? That's a lot of typing the same thing over and over again.
So now you don't need to know the exact name and hard code that into your script you can select the first thing in the array by calling "CurSel[1]".
Note 1: If you really wanted to find out the name of the first object you could do: But it's not really necessary, because you can just say "get the first thing in the array" CurSel[1].
Note 2: You can also do things like "count" the things in an array to find out how many items there are. CurSel.count = Number of items in the array. So if you wanted to count how many things you have selected you can do:
But handling each thing (CurSel[1], CurSel[2] ect...) one at a time, turns into a huge list of the exact same commands over and over again. If you wanted to change the commands you have to edit a bunch of different entries. But once we have an array you can do things like "the for-loop", which tells it to count the items in the array and do a list of commands to each thing. So now you have a short list of commands to edit, yeah!
For i=1 Anytime you see an "i" insert an item number. "CurSel" is CurSel[1] then CurSel[2] ect...
to CurSel.count We are only going to do the following commands for the number of things in the array. You could say "to 100" but it will do it 100 times even if you have 5 or 200 things. Its smarter to only do it the number of times you need.
do ( ) Anything inside the parentheses gets treated as a group of commands.
select CurSel{i} Select the items in CurSel, as the for loop counts replace i with 1 and when it runs out of commands switch it to 2 and run through the same commands.
Layer.addNode $ Layer means get a specific layer and add whatever is selected.
The commands are done so it goes back to the top of the list grabs the next item and goes through the commands again.
Confusing at first, and I hope I didn't confuse you more, but its how a lot of scripts operate and it's a really fast way to do a lot of commands to a large group of objects.
Right now I have my basic bone structure generated by one button. Tomorow i'll start handling all the contraints with another button^^ Thanks again
Right now I have a bone generator, and a part of script that create some controler for the legs and hip...
until now, each action was hardcoded but i am now working on the spine. I have 3 spine bone named spine1,spine2,spine3, wich will receive the same kind of controler... Time to try to make a loop. Here is what i coded: I edited the message to make it easier.
I want to do the same thing with spine2 and spine3 but i can't figure out a working loop
you do not need to use ' ' after $ if there's no space in the name. You would only need them for something like $'spine 1' $spine1 is good enough
rather than trying to select an object or keeping it selected after his creation you could assign him to a variable when you create it (like I did with the ctrl variable)
how to do a loop:
there's a few way to start a loop
you can either do something like: or
or
or
or
sometime you need to work with an index sometime you don't... but the index will always work. It's up to you.
Good luck
This "("ctrl"+o.name)" is actually the part i couldn't guess.
As for the ', i use them just to be sure there is no error since some of the name i use have space.
I have a couple follow up question, why is there a "local" before circle? and does the letter i use as index matter? you use "o" while Mark Dygert above used "i"...
Thanks anyway
local and global variable... a local variable inside the scope of the ( ) they're in while global variable can be accessed anytime. I suggest to stick with local as much as you can.
ie: this will give an undefined error as the variable test is not defined outside the () works fine
works fine
it doesn't matter you could even use a word... like foo, pizza or whatever
ie: for polycount in #("aa","bb") do print polycount
There is one last thing i would like to do, but can't think of a method :
When you create the bone structure, depending on the character, it might be out of place. You can still go in bone tool to adjust that, but if your character is symetrical, it might be easier to miror the position of the bone name *.L over those named *.R .
This one might be a bit tricky for a newbie like me but If you have an answer, i would like to try
thanks
I have no idea how I should proceed...
the script on the left work unless you moved them with the bone tool. I don't know why yet, but if there is no solution, i'll work my around another method
Interesting thread. It's been long time since I've touched something similar, but here it goes. There are some points to consider and obvious omissions in you script seen in last image you posted:
1. I don't see the script even working; there is no copy made for the other side.
2. There are no bone specific properties set. Node (anykind of node for that matter, not just bone representation) must be using $.boneEnable set to true, otherwise you don't see proper (bone) behavior at all.
3. Mirror axis, looks quite OK to me, but then again it's been long time since I've done anything similar.
You end up with non-negative scaled bones - which is good. Then again, remember that you won't end up with "mirror rotations" during animation time. Maybe someone with proper knowledge can refresh if this was even possible with max bones. Might be that I remember this incorrectly.
4. Axis setup - If you draw a left arm from top down view, you notice that bone length in max is always along x-axis (no matter what), z-axis will be projecting out of outside of side of arm. Y-axis will be the one facing in different direction on right side compared to left side in this case.
5. Hierarchy. I don't see any parentation happening. In general, you'd have to parent bones. Store parent for each node, then do loop of create bones, then a loop of parenting bones.
However, here you can cheat, double click the root bone, then your selection will contain bones in hierarchical order. This would only work for an arm or a leg, not for a full rig if hierarchy is broken - but this is OK for testing your script on a limb.
6. Structure of script. Overall, I'd first collect all the properties of source object, then proceed to copying, and then apply these settings to a node on mirrored side.
P.S.
I made a quick hacks to your script. Not everything you need though. Search for posts by Eek and Paul Neale on CGSociety. They know their rigging stuff. Good luck!
*EDIT* I hope this won't cause any headaches - I didn't test mirroring that much, only with couple of poses, I accidentally flipped position of mirrorMatrix and ref.transform (I have fixed it in code below now).
*EDIT* sorry for edits - fixed lots of typos and such (long week, too little sleep)