Forum Moderators: Staff
Poser Python Scripting F.A.Q (Last Updated: 2024 Sep 18 2:50 am)
When dealing with compound nodes, you need to address the compounddata ....
Locked Out
This works for me (P11):
import poser
scene = poser.Scene()
character = scene.CurrentFigure()
actor = character.Actor("Body")
materials = actor.Materials()
main = ["SkinHead", "SkinLimbs", "SkinTorso", "Iris", "Fingernails", "Teeth", "Gums", "Tongue"]
for (material, zone) in [(mat, mat.Name()) for mat in actor.Materials() if mat.Name() in main]:
nodes = material.ShaderTree().Nodes()
for node in [n for n in nodes if "||" in n.Name()]:
label, p, numberstring = node.Name().partition("||")
if p and numberstring:
numberlist = [int(n) for n in numberstring.strip().split("_")]
for number in numberlist:
node.Input(number).SetAnimated(1)
scene.DrawAll()
for number in numberlist:
parameter = node.Input(number).Parameters()[0]
identifier = zone + "_" + label + "_" + input.Name()
parameter.SetInternalName(identifier)
parameter.SetName(identifier)
print(identifier)
try
Locked Out
The reason why my version works is
scene.DrawAll()
The Poser UI is wxPython. A running Python script will interrupt Poser completely until the next request to do a refresh. This can be a refresh sent directly to the affected window, or Poser's global refresh command "scene.DrawAll()".
@
Iuvenis_Scriptor: Insert the resfresh into your own code and it will work as expected.
@adp when looking for solutions, I find that a number of options offered is always better than one solution, while you think your solution is best (and maybe it is) It may not fit a coder's particular style, the user can look and try various versions to see which is best for him/her, without being criticized for how they prefer to code.
The code I offered works to find the node. And while it may not be the most effective solution - it is a solution.
also my code takes into account the case of names, so "SkinHead" will be found as will "skinhead", "Skinhead", and "skinHead" etc.
Locked Out
The task was to find a "label" and a list of index numbers. Label and list separated by "||", the numbers separated by "_".
Your regular expression is not really helpful. As far as I know, the extraction can't be done in one go with regular expressions.
Separating label and number string is easy. You can do that with Python's standard "split". Or even with a regular expression (which split does anyway). I like to do this with "partition". This often saves a few tests and conversions.
label, p, numberstring = node.Name().partition("||")
(if p is now not equal to "||" label and numberstring exist but are None).
or:
if "||" in node.Name():
label, numberstring = node.Name().split("||", 1)
The numberlist can be created very elegant and very "pythonic" with a list:
numbers = [int(n) for n in numberstring.split("_")]
or with a regular expression:
r = [int(n) for n in re.split(r"_", numberstring)]
Your regex:
result = re.search('[||0-90-9]', label)
doesn't find anything particularly helpful (apart from the fact that "|" in a regex means "or", so it should be "\|\|"; twice "0-9" doesn't make much sense either - why not "\d"?). The first matching character from the string specified in square brackets is found (this should actually always be the first "|"). To get the desired result (a label and a list of arbitrarily large integers) you now have to do some work (examine the result and extract what is of interest). I find this quite cumbersome compared to a simple "split" and a generated list.
structure posted at 9:22 AM Mon, 9 May 2022 - #4438338
also my code takes into account the case of names, so "SkinHead" will be found as will "skinhead", "Skinhead", and "skinHead" etc.
what about this:
...
Preserves the original Nodename.
Thanks for all the suggestions, guys! Alas, it has so far been to no avail. With a temporary focus on just animating the right node inputs and getting the corresponding dials to appear (i.e. no renaming yet), my code now looks like this:
import poser
scene = poser.Scene()
character = scene.CurrentFigure()
actor = character.Actor("Body")
materials = actor.Materials()
main = ["SkinHead","SkinLimbs","SkinTorso","Iris","Fingernails","Teeth","Gums","Tongue"]
for (material,zone) in [(mat,mat.Name()) for mat in materials if mat.Name() in main]:
nodes = (material.ShaderTree()).Nodes()
for node in [element for element in nodes if " || " in element.Name()]:
label,numbers = (node.Name()).split(" || ",1)
indices = [int(number) for number in numbers.split("_")]
name = node.InternalName()
print("\t"+label)
for index in indices:
input = node.Input(index)
print("\t\t"+input.Name())
input.SetAnimated(1)
scene.DrawAll()
The same problem persists. The node inputs display as animated (with the white key symbol) in the Material Room, but the Parameters palette in the Pose Room remains barren, which means the dials are most likely not being created, and any attempt to rename them is doomed to fail.
I have tested the following version extensively with Poser 11 and it works fine. If it doesn't work in P12, then P12 seems to be broken :)
try:
import poser
except ImportError:
import POSER_FAKE as poser
scene = poser.Scene()
character = scene.CurrentFigure()
actor = character.Actor("Body")
materials = actor.Materials()
main = ["SkinHead", "SkinLimbs", "SkinTorso", "Iris", "Fingernails", "Teeth", "Gums", "Tongue"]
for (material, zone) in [(mat, mat.Name()) for mat in actor.Materials() if mat.Name() in main]:
nodes = material.ShaderTree().Nodes()
for node in [n for n in nodes if "||" in n.Name()]:
label, p, numberstring = node.Name().partition("||")
numberlist = [int(n) for n in numberstring.strip().split("_")]
for number in numberlist:
if hasattr(node.Input(number), "SetAnimated"):
node.Input(number).SetAnimated(1)
else:
raise AttributeError("Number does not exist")
scene.DrawAll()
for number in numberlist:
inp = node.Input(number) # type: poser.ShaderNodeInputType
parameter = inp.Parameters()
for parameter in [p for p in inp.Parameters() if p]:
identifier = zone + "_" + label + "_" + inp.Name()
parameter.SetInternalName(identifier)
parameter.SetName(identifier)
print(identifier)
This version can handle RGB inputs:
from __future__ import print_function
# should work with P11 and P12
try:
import poser
except ImportError:
import POSER_FAKE as poser
scene = poser.Scene()
character = scene.CurrentFigure()
actor = character.Actor("Body")
materials = actor.Materials()
# I prefer to leave the names as defined in the material (upper-/lowercase). But
# I'm using a set to prevent duplicates.
main = {"SkinLimbs", "SkinTorso", "Iris", "Fingernails", "Teeth", "Gums", "Tongue"}
for (material, zone) in [(mat, mat.Name()) for mat in actor.Materials() if mat.Name() in main]:
print(material.Name())
nodes = material.ShaderTree().Nodes()
for node in [n for n in nodes if "||" in n.Name()]: # type: poser.ShaderNodeType
# Split the string at position "||". Spaces are simply ignored ("label || 1_2_3"
# is just as valid as "label||1_2_3").
label, p, numberstring = node.Name().partition("||")
numberlist = [int(n) for n in (numberstring.strip().split("_") if numberstring else[])]
for number in numberlist:
# Indexnumber ok?
if number < node.NumInputs():
# animatable?
if hasattr(node.Input(number), "SetAnimated"):
node.Input(number).SetAnimated(1)
else:
raise AttributeError("Input is not animatable")
else:
raise IndexError("Input number does not exist")
scene.DrawAll()
for number in numberlist:
inp = node.Input(number) # type: poser.ShaderNodeInputType
r_parm, g_parm, b_parm = inp.Parameters()
if all(inp.Parameters()):
for pre, parameter in zip("RGB", inp.Parameters()):
identifier = "%s_%s_%s_%s" % (zone, label.strip(), inp.Name(), pre)
parameter.SetInternalName(identifier)
parameter.SetName(identifier)
print("...", identifier)
else:
identifier = "%s_%s_%s" % (zone, label.strip(), inp.Name())
r_parm.SetInternalName(identifier)
r_parm.SetName(identifier)
print("...", identifier)
Nope, no luck on my end. I even tried it on my tablet, where the Poser 12 installation is much fresher (though it was version 12.0.5), and I didn't get an error, but I didn't get any visible dials either. I'm beginning to suspect it may indeed be a problem with Poser 12 itself.I have tested the following version extensively with Poser 11 and it works fine. If it doesn't work in P12, then P12 seems to be broken :)
try:
import poser
except ImportError:
import POSER_FAKE as poser
scene = poser.Scene()
character = scene.CurrentFigure()
actor = character.Actor("Body")
materials = actor.Materials()
main = ["SkinHead", "SkinLimbs", "SkinTorso", "Iris", "Fingernails", "Teeth", "Gums", "Tongue"]
for (material, zone) in [(mat, mat.Name()) for mat in actor.Materials() if mat.Name() in main]:
nodes = material.ShaderTree().Nodes()
for node in [n for n in nodes if "||" in n.Name()]:
label, p, numberstring = node.Name().partition("||")
numberlist = [int(n) for n in numberstring.strip().split("_")]
for number in numberlist:
if hasattr(node.Input(number), "SetAnimated"):
node.Input(number).SetAnimated(1)
else:
raise AttributeError("Number does not exist")
scene.DrawAll()
for number in numberlist:
inp = node.Input(number) # type: poser.ShaderNodeInputType
parameter = inp.Parameters()
for parameter in [p for p in inp.Parameters() if p]:
identifier = zone + "_" + label + "_" + inp.Name()
parameter.SetInternalName(identifier)
parameter.SetName(identifier)
print(identifier)
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.
I've been trying to write a fairly simple script that goes through various materials, identifies certain nodes based on a signature in their external names, animate certain inputs in that node based on index numbers provided by tags in their external names, and renames the resulting parameters. I've rearranged things to avoid animating any inputs to custom-built compound nodes as at least a temporary solution to this apparent problem, but I'm still getting a NoneType error when the script tries to rename the new dial. The first time I tested it, it actually seemed to work! But upon further testing, it seems to work only sporadically. I haven't yet been able to replicate the complete success of that first test, but most times, no dials seem to be created, and sometimes a few of the dials but definitely not all seem to be created before it gets stuck, apparently failing to find the very parameter it should've just created. According to the print-outs, it's clearly finding the right nodes and inputs with no problem, but it can't seem to make up it's mind over whether it can animate them or not. At least once, I've noticed a white key symbol in front of a targeted input but no corresponding dial in the parameters palette.
I use a node tagging system where the external name of a node I want to animate is tagged with signals to the script. For example, for a node named "Testing || 1_2," the " || " says "Animate me!" and the numbers following it say, "Specifically inputs 1 and 2." I have tweaked the script since that first test, but never in a way that should affect the core loop. I've only tried to restrict the materials it applies to and/or load a PZ2 after everything else is done. I'm working in Poser 12.0.757. I've tried splitting the loop in two, just animating everything all at once in one loop and renaming the dials in a completely separate loop afterwards. That did not help. My code looks like this.
import poser
scene = poser.Scene()
character = scene.CurrentFigure()
actor = character.Actor("Body")
materials = actor.Materials()
main = ["SkinHead","SkinLimbs","SkinTorso","Iris","Fingernails","Teeth","Gums","Tongue"]
for material in materials:
zone = material.Name()
if zone in main:
tree = material.ShaderTree()
nodes = tree.Nodes()
print(zone)
for node in nodes:
name = node.InternalName()
label = node.Name()
print("\t"+label)
if " || " in label:
numbers = label[label.find(" || ")+4:len(label)+1].split("_")
for number in numbers:
index = int(number)
input = node.Input(index)
print("\t\t"+input.InternalName())
input.SetAnimated(1)
parameter = input.Parameters()[0]
identifier = zone+"_"+label[0:label.find(" || ")]+"_"+input.Name()
parameter.SetInternalName(identifier)
parameter.SetName(identifier)
print("\t\t"+identifier)
Thanks in advance for any tips on what I'm doing wrong! I'll keep tinkering and researching.