PDA

View Full Version : beginner questions on nodes


BenDstraw
03-31-2009, 12:09 AM
Hello All,

Typical scenario I'm learning maxscript and since i dont come from a programming background(besides some BASIC) I'm having a hard time with some more advanced topics and jargon especially within maxscript. Already just from reading the maxscript help I piece together a auto save tool which i already find useful along side autoback.

Problem is i can't seem to go much more advanced than that. I'm trying to get the poly count of the current selection using getpolygoncount() but when I run my script an error tells me that selection can't be be converted to type : <node>. I tried to help my self and not bother anyone with such a beginner question but I tried the maxscript help, google, and the forum search function but no help.

so my questions are:
1.What is a node?
2.How do I convert a selection into a node?
3.How do I use nodes beneficially
4.Am i going in the wrong direction using getpolygoncount() to get the poly amount?
5.If so can you lead me in the right direction and answer 1 and 2 just so i can know


thank you,
sorry for all the writing it wont happen again:D

MarcoBrunetta
03-31-2009, 12:52 AM
AFAIK within maxscript a node refers to any element that can be in the scene. In other words, meshes, lights, cameras, xrefs etc etc.

And you don't need to "convert" the selection into a node. That kind of error message means that the variable you are feeding to the command is not of the type the command wants.

Now, the best way to get help would be to post your code (using the CODE tags ). That way people can point out the errors and give you a hand.

CerberusC
03-31-2009, 12:54 AM
I'm a newbie in maxscript, but i'll try to answer your questions:

1.- A node is an entity of the scene, a geometry object, a camera, a material, and entity in the end.

2.- If you have a selection then the current selection is represented by a dollar sign $, so if you want to apply a function like getpolygoncount() you need to type something like "getpolygoncount $", if you want to pick the objects from a list...well i don't have this part very clear, but you may need to play around with arrays, a pickbutton, or something like that, check it in the maxscript help.

3.- i don't understand this question :p

4.- nope, i think you are in the right direction, you will get two values, i did not search that function in the maxscript help, but i assume that it gives you the polygon count and the triangle count.

5.- i think that is answered, but just in case, i think the best way to learn maxscript is to look into others code and try to understand what are they doing, you can start with the How To's inside the maxscript help, there are really great tools scripted in there and you will learn a lot, also here are really good people that will help you a lot, i know because they helped me a lot, only you need to try hard and use the time that you need (i mean...if it's a lot you will need to spend a lot, but don't give up, once you know how to script some simple tools it becomes better and better, it's fantastic and really helpfull with the team work)

Hope that helped you, i want to see your tools going out!!

Cheers!.

BenDstraw
03-31-2009, 01:16 AM
MarcoBrunetta: Thanks man, I posted my code. Its sloppy and very beginner like(my programmer friend always reminds me my code is sloppy:p). Obviously too this code is far from complete. Also I added comments on places I know to be problem areas.

--Define Varibles
global polyCountAll
global polyCountSel
global triCountAll
global triCountSel
global objectCount


rollout rloutStats "Poly Statistics"
(
-- my attempt at saving current selection to a varible
local currentSel = getcurrentselection()

--Editable labels printed to rollout
label labPolyCountAll "0"
label labPolyCountSel "0"
label labTriCountAll "0"
label labTriCountSel "0"
label labObjCount "0"

--Labels for editable labels(it makes sense in my head)
label labPolyAllTxt "Scene Poly Count:" pos:[42,6]
label labPolySelTxt "Selected Poly Count:" pos:[30,24]
label labTriAllTxt "Scene Tri Count:" pos:[50,42]
label labTriSelTxt "Selected Tri Count:" pos:[38,60]
label labObjCountTxt "Scene Object Count:" pos:[30,78]
button btnCalc "Calculate"

-- I only added this because maxscript wont let me change the .text property outside a loop. is this normal?
on btnCalc pressed do
(
if currentSel != undefined then
(
getpolygoncount currentSel
)
)
)


rollout rloutAbout "About" rolledup:true
(

label labAbout "Scripted by Ben Dirilo"



)

-- Make main UI window
mainFloater = newRolloutFloater "Poly Watch" 280 320

-- create rollout with new rollout name and the floating window its being added to.
addRollout rloutStats mainFloater
addRollout rloutAbout mainFloater


CerberusC: Thank you for your answers they are what I assumed in the first place but I can't seem to put it into practice :sad:. I have current selection saved in a local varible and I thought since the current selection is a scene object(a primitive but ive tried edit poly objects as well) that it would work but perhaps my understanding of maxscript is flawed:D

thank you once again for your guy's time.

MarcoBrunetta
03-31-2009, 02:46 AM
Ok, so the reason you are having problems is that the getCurrentSelection() method returns an ARRAY of objects, and the getpolygoncount() function requires a single object. In case you are not clear on this, an array is pretty much a "group" or "list" of things; it can be anything, nodes, variables, strings, etc etc.

So even if you have only one object selected, getCurrentSelection will give you an array with a single member. This will look like #($Teapot:Teapot01 @ [47.133118,21.164185,0.000000]). What you need to do is acces the individual members in the array (assuming several object where selected), get their polycounts, and then add them all togheter. The away to acces an array would be arrayName[1] for the first element of the array arrayName[2] for the second etc etc. Check the help file for more info.

Let's see if you can figure it out with that...:)

A couple of tips about the code:
* Try to use as few GLOBAL variables as possible. It's ok if you are debugging or trying out stuff, but for the final code try to keep everything as LOCAL whenever possible.
* The way your code is written, the script will store the current selection when the rollout is created. However you probably want the current selection to be checked when the button is pressed as the user could change the selection AFTER the rollout was created. In other words, your currentSel variable inside the rollout WILL NOT be dynamically updated when you change the selection. It would be easier (and cleaner) to remove the local variable inside the rollout and just check the selection when the button is pressed.

eek
03-31-2009, 03:11 AM
1. A node is an object in the scene, be it an geometrical, spline, helper, camera etc It's not a system to my knowledge such as a pflow object, etc. Nodes have attributes, such as a spheres.baseObject parameters or a point helpers size variable.

2. A selection isn't a node, a node is an element of a selection like an element of a array. Infact you can turn selections into array simply by passing 'as array'. The function is asking for a single node, not a group of them - thats why its throwing an error.

3. Many ways - by accessing them as elements of arrays, accessing there controls directly or passing there controls via other methods, and systems such as script controllers and custom attributes.

4. If that function works on its own thats fine, but a lot rely on an 'interface' essentially this is a struct - like the meshOps interface or skinOps. An example of this is getting the number of bones in a skin modifier. Access is by interface > function affecting object > modifier (generally)

skinOps.getNumberBones selection[1].skin or selection[1].modifiers[#skin] or $.skin..etc The $ is the current object, node etc active in the scene - and generally a bad idea in scripts unless you need to sometimes access the modifier panel, like with the skin modifier.

5. So basically the getpolygoncount() is a function, which you need to provide generally parameters to, unless there defined by default. eg.

fn test a = (print a as string) means 'a' is a parameter that needs to be defined. You cant just call test() as a hasnt been defined yet depending on global scope.

now if you had fn test a:10 = (print a as string) you can call the function as: test() because a is already defined. It depends on how you build the function in the end.

So if you want to get the poly count depending on whether its a selection or not you would just do this - I would basically build a function and then use that in a scripted rollout


fn getPolyCountBySelection =
(
local numPolys = 0

for o in objects do
(
if o.isSelected do
(
numPolys += (getPolyCount o)
)
)
numPolys as string
)

now you can embed this into a rollout:

try(destroyDialog pCount)catch(false)
rollout pCount "Poly Counter"
(
label theResult ""
button getSelectionCount "Get Selection Count"

on getSelectionCount pressed do
(
theResult.text = (getPolyCountBySelection() + " in current selection.")
)
)
createDialog pCount

BenDstraw
03-31-2009, 04:53 AM
:p alright so this is how it went.

I used eek's code snippet adjusted it to my code and tried to run it. It said something along the lines incompatible types. Using what you guys taught me I figured out it was because you use the expression += because you cant add 0 to an array. So I'm actually glad to say i learned something instead of just copying and pasting your guy's help.


Heres the new working code. I used your keep variables local advice Ill end up changing the others too. Why is it important to keep variables local is it for performance?
--Define Varibles
global polyCountAll
global triCountAll
global triCountSel
global objectCount

fn getPolyCountBySelection =
(

local polyCountSel = 0

for o in objects do
(

if o.isSelected do
(
local poly = (getPolygonCount o)
polyCountSel += (poly[1])
)

)
polyCountSel as string
)


rollout rloutStats "Poly Statistics"
(


--Editable Integers printed to rollout
label labPolyCountAll ""
label labPolyCountSel "" pos:[145,24]
label labTriCountAll ""
label labTriCountSel ""
label labObjCount ""

--Labels for editable integers
label labPolyAllTxt "Scene Poly Count:" pos:[42,6]
label labPolySelTxt "Selected Poly Count:" pos:[30,24]
label labTriAllTxt "Scene Tri Count:" pos:[50,42]
label labTriSelTxt "Selected Tri Count:" pos:[38,60]
label labObjCountTxt "Scene Object Count:" pos:[30,78]
button btnCalc "Calculate"

on btnCalc pressed do
(
local currentSel = getcurrentselection()
labPolyCountSel.text = getPolyCountBySelection()


)
)


rollout rloutAbout "About" rolledup:true
(

label labAbout "Scripted by Ben Dirilo"



)

-- Make main UI window
mainFloater = newRolloutFloater "Poly Watch" 280 320

-- create rollout with new rollout name and the floating window its being added to.
addRollout rloutStats mainFloater
addRollout rloutAbout mainFloater


thank you guys so much for your help. You taught me to look out for more things such as things returning an array instead of a single value. Also if you could point me to a function that returns the triangle count. Ill try to figure out the rest my self. Once again I'm thankful

thatoneguy
03-31-2009, 05:27 AM
It's not for performance it's mostly just to keep things tidy.

If you have a variable that's called "StringVar" and another script uses a variable called "StringVar" then you start getting bugs. Since Global space is a shared commons you don't want to use up all the variables which might interfere with someone else.

It also doesn't get cleared from memory. Which most of the time isn't a problem since most variables don't contain much data. But it's possible to load a lot of data into a variable at which point Max won't know when to free it and will simply hold onto that variable forever. Again this is 99% of the time not going to actually have any impact on performance which is why I say it's mostly to avoid conflicts. I've encountered this with my own scripts conflicting with one another. If you run two scripts and they both have "ObjectCount" you can very easily see how quickly that would become a problem.

As far as memory goes one thing you can do that I try to remember to do is clear all of your global variables on exit. If you have a rollout then when the rollout closes go through your global list and set them all to = undefined. That way even if on the off chance someone else does happen to collide with your minimal global variables it's less likely and you've manually done what max doesn't know how to do on its own.

One last problem with global variables is that they can conflict within your own script.

The classic example is obj. Obj is my favorite variable name. But if it's a global variable you can get some wonky results in functions as you pass in Obj (the global variable) into the function which then becomes obj the local variable... but then occasionally instead of using the obj passed in it pulls from the global... and you have a big mess. So using local variables frees you to use the same variable name elsewhere in your own script without having to come up with confusing variable names like StripLeadingZerosObj in a function.

MarcoBrunetta
03-31-2009, 01:31 PM
A few pointers on the new code:

* What's the point of the four global variables at the top? They are not used in the rest of the code...

* The getPolyCountBySelection() function is now a GLOBAL function, and there is no reason why it should be. You could easily store it INSIDE the rollout for example.

* The getPolyCountBySelection() now works correctly, however is not really efficient. You can see that what it's doing is scanning EVERY object in the scene and checking if that object is selected. However you already have a function that will return you the current selection (getCurrentSelection()). Using that function you keep the computer from scanning the WHOLE scene, wich is quicker and less computational intensive. Get used to optimizing your scripts, software should use as little resources as possible.

eek
03-31-2009, 02:44 PM
A few pointers on the new code:

* What's the point of the four global variables at the top? They are not used in the rest of the code...

* The getPolyCountBySelection() function is now a GLOBAL function, and there is no reason why it should be. You could easily store it INSIDE the rollout for example.

* The getPolyCountBySelection() now works correctly, however is not really efficient. You can see that what it's doing is scanning EVERY object in the scene and checking if that object is selected. However you already have a function that will return you the current selection (getCurrentSelection()). Using that function you keep the computer from scanning the WHOLE scene, wich is quicker and less computational intensive. Get used to optimizing your scripts, software should use as little resources as possible.


You could also check the objects classOf to see if its a mesh or not, I was just making it simple to start.

for i in selection do
(
if superClassOf i == geometry do
(
-- the code
)
)

MarcoBrunetta
03-31-2009, 03:15 PM
True that. ;)

thatoneguy
03-31-2009, 05:40 PM
I'm a big fan of try/catch in these sorts of cases. Since a classof (light target node) == geometry as well.

I just throw a try/catch

try(getpolycount(Sel[i]))catch()

BenDstraw
03-31-2009, 10:46 PM
MarcoBrunetta: the unused varibles are for future use and will of course be made local as advised. Also I didn't know about the function being global sorry the maxscript help said something about placing your functions in beginning but it makes sense since the function isn't needed outside the rollout thank you. any other advice on how to make scripts generally more optimized not included in the "how to make it faster" page of the help? Also, is there a way to tell how optimized my script is(perhaps something that returns how much memory its using?) because in basic I print the fps to the screen and tried to optimize from there albeit very basically(pun intended)

EEK: can you explain the try, catch, and throw expression? The help files explanation of these is vague for me because I'm not familiar with exception handling since my is in basic. Also if I were to implement your for loop where would I put that? I seem to have a hard time figuring where things go in a script:argh:

eek
03-31-2009, 11:47 PM
MarcoBrunetta: the unused varibles are for future use and will of course be made local as advised. Also I didn't know about the function being global sorry the maxscript help said something about placing your functions in beginning but it makes sense since the function isn't needed outside the rollout thank you. any other advice on how to make scripts generally more optimized not included in the "how to make it faster" page of the help? Also, is there a way to tell how optimized my script is(perhaps something that returns how much memory its using?) because in basic I print the fps to the screen and tried to optimize from there albeit very basically(pun intended)

EEK: can you explain the try, catch, and throw expression? The help files explanation of these is vague for me because I'm not familiar with exception handling since my is in basic. Also if I were to implement your for loop where would I put that? I seem to have a hard time figuring where things go in a script:argh:

Try, catch and throw to me are essentially break points. The code or function etc, will 'try' to execute that piece of code and if it finds an error it'll either catch it and/or throw it depending on your code. Basically if it breaks you can use the catch ( messageBox "error") to return the problem, reset values etc. And you can use error to throw an error string.

I hardly use them as it can eat memory, for example resently i had a script that i was doing error check with and used the try/catch - it jumped to 1,700 megs usage in a few seconds ( and crashed with no warning on any click afterwards) With correct formatting and putting in the work without the try/catch it hardly jumped 3 or so megs. Try and catch should be used sparingly.


Q. Also if I were to implement your for loop where would I put that? I seem to have a hard time figuring where things go in a script?

A.
try(destroyDialog myTest) catch(false)
rollout myTest "MyTest"
(
local faceCount = 0
local vertCount = 0

button getCount "Get Count"

on getCount pressed do
(
faceCount = 0
vertCount = 0


for i = 1 to selection.count do
(
if (superClassOf selection[i]) == geometryClass do
(
faceCount += (getPolygonCount selection[i])[1]
vertCount += (getPolygonCount selection[i])[2]
)
)
messagebox (faceCount as string + " Faces & " + vertCount as string + " Verts in current selection" )
)
)
createDialog myTest

BenDstraw
04-01-2009, 01:08 AM
I tried putting your for loop and if statement as my function but it always returns as 0.


fn calcPolySel =
(

local polyCountSel = 0


for o=1 to selection.count do
(


if (superClassOf selection[o]) == geometryClass do
(

polyCountSel += (selection[o])[1]


)

)
polyCountSel as string

)


Im guessing its because the condition for the if statement isn't being met. But i do have objects selected and they are meshes. Also the function is being executed on button pressed.

ZeBoxx2
04-02-2009, 08:49 AM
you forgot to use getPolygonCount to get the number of polies on the object. Right now you're not actually getting the polygon count for the object.

In fact.. the code you have 'as is' should throw an error:
-- Incompatible types: 0, and SubAnim:Visibility

BenDstraw
04-02-2009, 09:25 AM
woo oops thank you. not sure how i missed that one.:shrug::surprised

CGTalk Moderation
04-02-2009, 09:25 AM
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.