Mon, Dec 23, 8:43 AM CST

Renderosity Forums / Poser Python Scripting



Welcome to the Poser Python Scripting Forum

Forum Moderators: Staff

Poser Python Scripting F.A.Q (Last Updated: 2024 Dec 02 3:16 pm)

We now have a ProPack Section in the Poser FreeStuff.
Check out the new Poser Python Wish List thread. If you have an idea for a script, jot it down and maybe someone can write it. If you're looking to write a script, check out this thread for useful suggestions.

Also, check out the official Python site for interpreters, sample code, applications, cool links and debuggers. This is THE central site for Python.

You can now attach text files to your posts to pass around scripts. Just attach the script as a txt file like you would a jpg or gif. Since the forum will use a random name for the file in the link, you should give instructions on what the file name should be and where to install it. Its a good idea to usually put that info right in the script file as well.

Checkout the Renderosity MarketPlace - Your source for digital art content!



Subject: Need help with simple material script


232bird ( ) posted Tue, 27 September 2011 at 11:16 PM · edited Sun, 03 November 2024 at 11:22 PM

file_473314.txt

I am trying to write a script to change the diffuse color of all materials for a selected figure.  I was able to get the script to run without errors, but it didn't actually do anything, so I thought I should ask for help.  I have been through all Poser-related Python reference materials, so I think this is more an inability on my part to put together a functioning workflow in a script (yet).  Could someone point out what I am doing wrong?  Here is the script, and I also attached the .py file in .txt format.

 import poser
scene = poser.Scene()
materials = poser.Scene().CurrentFigure().Materials()[0]
diffcol = materials
print diffcol
materials.SetDiffuseColor(1.0, 0.1, 0.1)
diffcol2 = materials
print diffcol2
scene.DrawAll()
print "Done" 


PhilC ( ) posted Wed, 28 September 2011 at 3:00 AM

I suggest that you do not use:-

material.SetDiffuseColor(r,g,b)

because it has become outdated.

Work on the shader tree as shown below:-

<br></br>
# script to change diffuse colour<br></br>
# For simple materials with no textures or extra shaders the<br></br>
# lines below will work.<br></br>
#<br></br>
# import poser<br></br>
# material = poser.Scene().CurrentFigure().Materials()[0]<br></br>
# material.SetDiffuseColor(0.123, 0.345, 0.456)<br></br>
#<br></br>
# However with anything more complex use the script below<br></br>
# because this will control the shader tree whereas the above<br></br>
# only affects what may be considered as "legacy"
materials.

import poser

for this example use the currently selected material.

material = poser.Scene().CurrentMaterial()

define the shader tree

shaderTree = material.ShaderTree()

define the first node, i.e the main "PoserSurface" node

poserSurface = shaderTree.Node(0)

define the required node in the poser surface.

diffuseNode = poserSurface.InputByInternalName("Diffuse_Color")

set its colour (r,g,b), (0,0,0) = black, (1,1,1) = white

diffuseNode.SetColor(0.6,0.2,0.2)

update the shader tree preview

shaderTree.UpdatePreview()

update the scene preview

scene.DrawAll()


EnglishBob ( ) posted Wed, 28 September 2011 at 5:07 AM

Ah, this explains why my "AllBlack" and "AllWhite" scripts are less than totally effective. Thanks Phil. 


232bird ( ) posted Wed, 28 September 2011 at 11:17 AM

Whew, thanks PhilC, that clears up a lot of confusion.  Your script works fine, except that for me 

scene.DrawAll()

causes an error.  I even tried adding 

scene = poser.Scene

after "import poser", but it didn't help.  I'm still using Pro2010, if it matters. 


PhilC ( ) posted Wed, 28 September 2011 at 11:51 AM

Sorry yes, I've omitted:-

scene = poser.Scene()

Include the parentheses.


232bird ( ) posted Wed, 28 September 2011 at 12:43 PM · edited Wed, 28 September 2011 at 12:45 PM

Lol yep, I did too.  Now everything works.

I tried to add to the script to make it recurse through all figures and materials.  Came up with this.

import poser
#declare variables
scene = poser.Scene()
allfigs = scene.Figures()
#set FOR loop to recurse through figures
for figure in allfigs:
#declare materials
mats = figure.Materials()
#FOR loop to recurse through materials
for material in mats:
#declare shader tree down to diffuse node
 shaderTree = material.ShaderTree()
poserSurface = shaderTree.Node(0)
diffuseNode = poserSurface.InputByInternalName("Diffuse_Color")
#apply color
try:
mat.diffuseNode.SetColor(1.0,0.2,0.2)
except:
pass
#refresh scene
shaderTree.UpdatePreview()
scene.DrawAll()
print "Done"

 at line 11, "for material in mats", I get the error 

for material in mats:
^
SyntaxError: invalid syntax 

What I am trying to do with that line is go through all materials for a figure and apply the color to each. 


markschum ( ) posted Wed, 28 September 2011 at 5:57 PM

I avoid any names which are part of a command so I would use

for mat in mats:

       do something

dont forget to indent

if you are chnanging the value for everything in the ecene you have to do actors as well, and test they are props rather than lights, cameras etc. 

 

 


232bird ( ) posted Thu, 29 September 2011 at 12:37 AM

That's something that confused me.  How do I assign/declare mat to be the material?  Does Python know that 

for mat in mats

means that "mat" means "whatever is lower in the tree from mats(defined)?"

 I think I need a good flowchart of the hierarchy in order to get the recursive stuff sorted out.  Or I may just be over thinking it, if my above assumption is correct. 

Sorry about the indentation, when I did copy/paste it didn't keep the formatting.  I'll be careful of that.  The formatting was correct in my text editor, though. 


markschum ( ) posted Thu, 29 September 2011 at 9:00 AM

The forums here tend to mess up formatting, so no worries there.

In python  for x in y:    y must exist and be a iterable variable. X is the variable that exch value gets placed in, and can be anything.  You might find the python manuals to be a help, the Poser document only covers specific poser functions.

http://www.python.org/ has the manuals but make sure you get the right version.


232bird ( ) posted Thu, 29 September 2011 at 2:32 PM

Thanks for the link, I need to go read those manuals again.  I even tried using your set minshader script as a reference since it can recurse through everything, but no matter what I do I get either syntax errors or iteration errors.  I'll go through the manuals and see if that doesn't set me straight, then report back.


232bird ( ) posted Sun, 30 October 2011 at 8:17 PM

I am happy to report that after way too long I have been able to make some progress, and learn some things as well.  This script has evolved a bit, my goal is now to be able to take any material set and strip it down to the bare essentials.  My motivation for doing this is that

  1. Older material sets employ "tricks" that are no longer necessary and don't work well with render gamma correction, IDL, and now built-in SSS

  2.  Complex shader trees are not needed with and sometimes don't even work with Pose2Lux and other exporters

 3) I've been lurking long enough and have learned quite a lot since I first found this website, so now I want to start contributing 

So... this script is intended to clean out the surface node, for example get rid of the kd_lite_multiplier, diffuse colors, ambience, etc. that were used way back in the day but are no longer needed.  Then, follow the connections from the color inputs down to the image maps and plug those image maps directly to the color inputs.  Then the user can apply the new SSS, or VSS, or whatever without worrying about things going haywire, or export to another program/renderer without having an all black figure because the maths didn't bake properly.

 Here is what I have so far:

 

import poser

#declare materials
mats = poser.Scene().CurrentFigure().Materials()
shaderTree = poser.Scene().CurrentMaterial().ShaderTree()

Clean up surface shader

for mat in mats:
shaderTree = mat.ShaderTree()
      node = shaderTree.NodeByInternalName("PoserSurface")
      node.Input(0).SetColor(1.0,1.0,1.0)
      node.Input(1).SetFloat(0.8)
      node.Input(2).SetColor(1.0,1.0,1.0)
      node.Input(3).SetFloat(0.2)
      node.Input(6).SetFloat(0.0)
      node.Input(20).SetFloat(0.0)
      #node.Input(21).setInput(0)

#Function to test if a node is an image map
def testIMG():
      Diff_Color_Input = node0.InNode()
      node2 = Diff_Color_Input
      node2_type = node2.Type()
      print node2_type
      if node2_type == "image_map": 
           print "node is an image map"
           return
      else:
           print "Node is not an image map, moving to next input..."
           node1 = node2
           node2 = node1.InNode(0)
           testIMG()

#Find Diffuse image map
for mat in mats:
      shaderTree = mat.ShaderTree()
      node = shaderTree.NodeByInternalName("PoserSurface")
      Diff_Color = node.InputByInternalName("Diffuse_Color")
      node0 = Diff_Color
      testIMG()

shaderTree.UpdatePreview()
poser.Scene().DrawAll() 

 Forgive me if I missed an indent or such, that is a copy/paste from my editor and then liberal use of the spacebar applied.

I have hit a couple problems so far.  The biggest is that the script exits with

Traceback (most recent call last):
File "V:Pythonmats.py", line 40, in ?
testIMG()
File "V:Pythonmats.py", line 23, in testIMG
node2_type = node2.Type()
AttributeError: 'NoneType' object has no attribute 'Type'

as the error.  I thought the "return" command would break the function, but it appears it isn't doing what I thought it would.  As a sidenote to that, I'm pretty sure there is a problem with how I am reassigning the nodes after the "else:" line.

The other is the line

#node.Input(21).setInput(0)

I cannot for the life of me get the Reflection_kd_Mult to uncheck in the script.  It worked fine for Reflection_lite_mult by giving it a 0.0 floating number.  For what it's worth I ran a Type() command on the Reflection_kd_Mult and Poser returned "4", whatever that means.  Oh, and I know it has a # in front, I just stuck that there so I could move on to other things for the time being.


markschum ( ) posted Sun, 30 October 2011 at 9:38 PM

I would suggest you not use Input(x) although it does work. If poser adds something to PoserSurface it will break, and it makes it hard to undrstand what is going on.

the firt shadertree statement seems like its not needed.

Node(0).InNode() i think is wrong - InNode(0 is a input method)

so Diff_color_input = Node.Input(0).InNode() is what you need

dont understand this at all:

  print "Node is not an image map, moving to next input..."
           node1 = node2
           node2 = node1.InNode(0)
           testIMG()

its saying make node1 = node2

then its wrongly trying to get the node connected to node1

that wont work.

#node.Input(21).setInput(0)  try setfloat(0)

try fixing you Innode problem and see what breaks then ;-)


markschum ( ) posted Sun, 30 October 2011 at 9:45 PM

oh, by the way look at the shader type codes near the beginning of the poser manual.

 

they are defined words like kTypeCodeAMBIANTOCCLUSION which can be used to compare a node type. 

use them like this  AOnodetype = poser.kTypeCodeAMBIANTOCCLUSION

if node2_type = AOnodetype:

or directly  if node2.type = poser.kTypeCodeAMBIANTOCCLUSION :


232bird ( ) posted Sun, 30 October 2011 at 11:31 PM · edited Sun, 30 October 2011 at 11:36 PM

Quote - I would suggest you not use Input(x) although it does work. If poser adds something to PoserSurface it will break, and it makes it hard to undrstand what is going on. 

  Good point, I'll change it to use internal names when I do the cleanup.

 

 

For the poser surface I tried

node.Input(21).setFloat(0) 

before but it didn't work. I SHOULD have used  

 node.Input(21).SetFloat(0)   

                          ^

been getting bitten by capitalization all day, glad I noticed that.

 

Quote - dont understand this at all:

 Print "Node is not an image map, moving to next input..."
node1 = node2
node2 = node1.InNode(0)
testIMG()
its saying make node1 = node2
then its wrongly trying to get the node connected to node1
that wont work. 

  I agree, I took it out for now to do more testing.  What I was trying to do with that statement is:

                          A                                               B                                        C 

PoserSurface(Diffuse Color)input    ->non image map node       -> image map node 

Node A is the current focus, so find the input for that node, which is node B.  Yes?  Cool, exit the function and move on.  No?  Ok, focus on node B, and grab its input which is node C.  Restart the loop and test again.  The problem with doing it cut and dry like that is that I don't know how many extraneous nodes are in the path before I hit the image map, and I need a way to feed node B to the beginning of the function so it doesn't keep trying to start with node A over and over again.  Probably have to use an incremented integer with a FOR loop.  Or something. 

 

 

For testing the node, I followed your input and rewrote it to

if node2.Type() == poser.kNodeTypeCodeIMAGEMAP:  

but it still didn't work.  Here is what is really confusing me on that whole part part. The line 

print node2.Type()

returns image_map.   So if I use 

if node2.Type() == "image_map":

Python returns

image_map
node is an image map 

fourteen times, the the attribute error

File "V:Pythonmats.py", line 40, in ?
testIMG()
File "V:Pythonmats.py", line 24, in testIMG
print node2.Type()
AttributeError: 'NoneType' object has no attribute 'Type'

But if I use 

   if node2.Type() == poser.kNodeTypeCodeIMAGEMAP:  

I still get

image_map
node is an image map 

returned fourteen times, then I get the same attribute error.  It seems like Python is reassigning node2, even after I took out all that funky node1 = node2 stuff.  Almost forgot, I checked the typecode with the Poser Python Methods manual as well as Phillc's book, and they both used the same code, so no luck there.


markschum ( ) posted Mon, 31 October 2011 at 5:44 PM

your testimg routine is called from a for mat in mats:   do you have 14 materials in that figure ?

I would say when your else clause executes then your fault occurs. If you have corrected the logic to get the node input innode you also need to account for each input in the node.

 

for example a blender node may be connected to the diffuse color input, blender node has three inputs, so an image map may be logged into one , two or all three inputs.

example skin image map to input 1, tatoo image map to input 2 and a mask image to input 3.

I have no idea how you sort that out :-(  

remember though you can build a list of nodes and then go back and work through the list.

 

could you post you script again ? attach a copy as a txt file would be fine.


markschum ( ) posted Mon, 31 October 2011 at 7:34 PM

file_474747.txt

ok, this took me a bit of time but might help you with your script. This script starts at the PoserSurface node , diffuse color, and looks for any image map nodes that are attached, it checks all inputs of all nodes for an image map node in the chain. It prints the node name and image file name as it finds things and adds the internal node name to a list, which it then prints out when it finishes.

I have only used the first material for testing. You should be able to fix it to loop through all materials.

If the len(imgnodes)==1 then there will only be one image node and you can use the name to get the node and connect it directly to the diffuse channel.

the script should be recursive through the chain of nodes. I have only tested it with three nodes in the chain.

 

hope this helps


232bird ( ) posted Mon, 31 October 2011 at 9:14 PM

That makes sense. I didn't think to account for a mat with no nodes into the diffuse channel. I'm eager to see the script you posted, because I realized that if I hit a node with multiple inputs that will open up a world of hurt. It will be late before I get home, but I will post the full version of what I have so far when I do.


232bird ( ) posted Tue, 01 November 2011 at 12:25 AM

file_474755.txt

Here is what I have been working with up to this point.  

 I took a closer look at the script you posted, and I like your idea of using a list.  My way, were I able to get it working, would get very ugly very fast.  With that being said, don't pay much attention to the attached file, since I will pursue a new course of action with a list.

As to your example with the blender node, you raise a very good point.  I don't think it would break the process, but would reduce the number of successful outcomes to 1/number of image maps in the chain.  I can't think of any way to avoid that without being able to find some clue or assignment left by the developer, but since there isn't really standardization I don't see that being possible.  I'm not too worried about it though, since I can't think of a single product that uses proper application of the node system (but not saying there aren't any out there); most products I see/own simply change the  reference image to deal with masks, tattoos, etc.   

I'm done for tonight, gonna play with it tommorrow and report back. 


Snarlygribbly ( ) posted Sat, 05 November 2011 at 7:09 AM

Attached Link: Scene Fixer script

Hi 232,

You might find this script useful as reference - it trawls through the scene elements in a similar fashion to that which you are doing.

Scene fixer

Free stuff @ https://poser.cobrablade.net/


Privacy Notice

This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.