• Welcome to the Community Forums at HiveWire 3D! Please note that the user name you choose for our forum will be displayed to the public. Our store was closed as January 4, 2021. You can find HiveWire 3D and Lisa's Botanicals products, as well as many of our Contributing Artists, at Renderosity. This thread lists where many are now selling their products. Renderosity is generously putting products which were purchased at HiveWire 3D and are now sold at their store into customer accounts by gifting them. This is not an overnight process so please be patient, if you have already emailed them about this. If you have NOT emailed them, please see the 2nd post in this thread for instructions on what you need to do

Learning Poser Python...

Ken1171

Esteemed
Contributing Artist
I initially created a script to reset hand poses, with the option to include the fingers, or instead, keep the hand pose, and zero only the fingers - which is something I need quite often. PhilC has this included in his Poser Tools, but it has a performance problem: it refreshes the figure after resetting the joint rotations for every bone, which is very slow and can potentially crash Poser. In addition, it doesn't have an option to reset only the fingers. It's either the hand or everything. My version offers the extra option, and only refreshes the preview AFTER all joints have been reset, so it's much faster and efficient than PhilC's.

More specifically for Dawn, one problem I often find myself in is when I have a custom character with all morphs applied, and I need to reset just the pose or the hands, but those were posed using the build-in ERC controls instead of join rotations. If we reset the "pose" (joint rotations), the torso, neck and hands will keep the bends anyway, because the ERC dials are considered as "morphs", even if they just control joint rotations. They will not be affected, and need to be zeroed one-by-one, which is a PITA.

So I've started writing another script that instead of zeroing rotations, it zeroes specific ERC control dials in Dawn's Body actor. Examples of these ERC control dials in Dawn are Torso Bend, Torso Twist, and Torso Side-Side, which control several torso groups in one dial. Controlling the 2 neck groups, we have Neck Bend, Neck Side-Side, and Neck Twist. On the hands we have several control dials that pose all parts of the hand at once, like Left Hand Grasp, Left Hand Fist, and so on. All of these dials are not affected by Joint Editor's "Zero Rotations". You can try - it has no effect because they are considered morphs instead of joint rotations.

My second script is to handle these things in specific, the ERC controls on Dawn. I have placed the list of affected dials on a text file the script reads at start up, so we can customize it by figure. It has options to zero the torso, the neck, and the left and right hands. I have also included an option to zero everything at once. This will complement the first script, which handles only joint rotations. Once I make a GUI, I can use the 2 scripts to control everything from one place. On my pipeline, this will be useful.
 

Robynsveil

Admirable
Seems you're working primarily with materials, Ken. Have you had a look at Bagginsbill's Matmatic? I realise he sort-of hasn't done much with it, particularly for PP11, which is a shame, but perhaps he could be persuaded... ;)

Makes me grateful to be working in Blender (Python), as it supports Python 3x and you can refresh the cache with the press of the [F8] button. :)
 

Ken1171

Esteemed
Contributing Artist
I have started with materials, and now I am doing things with poses. The basic idea was to be able to reset a pose made with joint rotations and ERC controls, which Poser cannot handle on its own without also resetting all character morphs. These 2 last scripts resolve that, and I think no other script can do it because it includes dials that only Dawn has. The script reads the dials from a text file, so we can customize it and also use it with any figure by creating new profiles.

Poser is using old school Python 2.7, which is sort of a PITA. I am used to version 3, so it has been confusing having to use the old version, which by the way, has already been set for deprecation soon. Once Python 2.x reaches its end-of-life date, it will no longer be supported. This can be a dilemma, because if Poser upgrades to 3.x, all the existing scripts and plugins will stop working. Basically all the major Poser Python guys have already retired, so there will be no updates.

Most of ShaderWorks scripts don't work in P11, causing crashes and freeze-ups. I love and depend on many of Dimension3D scripts, but he has passed away. NetherWorks went to work on something else and has been absent for a long time. That's what motivated me to learn how to make my own scripts. We got to a point where we can no longer depend on 3rd party for this.
 

Rowan54

Dragon Queen
Contributing Artist
Sounds like a very good reason for learning scripting. I've read some of the documentation, but haven't tried the scripting. (Though how much more complicated than learning to talk to a mainframe in Fortran like I did in 1975 could it be?)
Sounds like you need to start a series of USEFUL tutorials for those of us who'd like to learn to do a just a few simple things with just a few simple commands. Like maybe just a few materials commands, maybe. Build from there.
 

Ken1171

Esteemed
Contributing Artist
The thing about the Poser Python documentation is that it doesn't teach any programming. It just covers what a person (who already knows Python 2.7) needs to know to use the Poser API. So you first need to learn Python, and then use the Poser Python reference material to get into controlling Poser from the inside. In this aspect, the PDF manual is quite incomplete, and I have found myself spending days trying to fill the blanks to get things to work. In other words, it's not enough to know Python and the API - we have to know how Poser needs things to be done.

For example, after I wrote all the commands to reset Dawn's ERCs to straighten the torso, I run the script and.... nothing happens. Then you move the camera, and the torso suddenly snaps straight. I realized something was missing, some kind of refresh. I have searched the manual and found nothing. At some point I figured out it was the "DRAW" command, instead of "refresh". But still, if you call DRAW for every bone that is reset, Poser crawls to a drag, with a great chance of a crash. We have to call it sparingly. However, most scripts I've purchased from the market call it every time, so I just can't use it. Just today, I have hit "refresh" from D3D's Material Editor, and Poser crashed. I know exactly what needs to be changed to fix it, but D3D has passed away, so his scripts are final.

I am still learning this, and I have been taking a beating from the vague/incomplete manual, but I am happy with the results so far. For example, now I know it is possible to automate the use of my "universal" heads, by letting Python do all of the tasks on its own. Like hiding the base figure's head, parenting the universal head, and even matching the materials. Maybe the only manual task would be to adjust the head position. I want to try that next. :)
 

Rowan54

Dragon Queen
Contributing Artist
Given all that's going on and how useful Python is for Poser (and elsewhere), I went to the site of my local library and ordered a half dozen beginner's books (including a Python for Dummies) on Python in general to see if I can get a grasp on how to use it (in general) and then go see if I can make sense out of the information I have for Python for Poser (I'm sure I've a doc about that on this computer somewhere.) I had Fortran (like I said), back in 1975. Since then, I've dinked with Pascal and Basic, and other stuff on that order. (Including attempting to learn some c-sharp not all that long ago while playing with Unity.)
Over the last while, I've kept looking at Python and going, "gee, I wish".
Today I said, "I'm going to go see if this is possible".
Granted, I wasn't a good programmer in any of the languages I've tried. However, I did manage to get simple stuff to run.
 

Ken1171

Esteemed
Contributing Artist
Last night I have managed to fully automate the use of my universal heads. I have started with the Chibi head. The plan was to use Python to automate all of the tasks to create a composite figure:

1. Load the base figure
2. Load the universal head.
3. Run the script. You don't have to select anything on the scene.

The script will:

1. Identify the base figure
2. Identify the universal head
3. Hide the head parts from the base figure
4. Parent the universal head to the base figure's head
5. Move the head up into place (*** more to this below)
6. Copy the face material from the universal head
7. Apply it to the base figure's body.

*** The exact position varies from one figure to another, so in the current version we have to type in the values. I was trying to see if I can use the position of the base figure's head as a reference, but in Poser, it appears that actors that are body parts do not have a XYZ position, because that's defined by the conforming process with bones.

So in short, you load the base figure and the head, and the script creates the composite figure with 1-click. I like that! To be able to do this, the script needs a profile for the base figure and the universal head. Those are provided from a profile text file, so we can use the same script with different base figures and heads.

Don't have this script, but for materials Shadertree().UpdatePreview() is faster IIRC.

It's called "XS", or "Extended Shader Manager". Very good stuff, one of the best, because it's small, well organized, and powerful. However, one thing I miss on it is ShaderWorks Advanced Material Manager, which can identify and group MAT zones that share the same contents, and you can filter which attributes you want to use for that. This allows us to edit only ONE material, and all others that share the same attributes automatically update. Unfortunately, ShaderWorks has retired, and his stuff malfunctions in Poser 11. Here again, we will have to do it ourselves from now on.

Given all that's going on and how useful Python is for Poser (and elsewhere), I went to the site of my local library and ordered a half dozen beginner's books (including a Python for Dummies) on Python in general to see if I can get a grasp on how to use it (in general) and then go see if I can make sense out of the information I have for Python for Poser (I'm sure I've a doc about that on this computer somewhere.) I had Fortran (like I said), back in 1975. Since then, I've dinked with Pascal and Basic, and other stuff on that order. (Including attempting to learn some c-sharp not all that long ago while playing with Unity.)
Over the last while, I've kept looking at Python and going, "gee, I wish".
Today I said, "I'm going to go see if this is possible".
Granted, I wasn't a good programmer in any of the languages I've tried. However, I did manage to get simple stuff to run.

It's a very good idea to learn Python first. It's a very peculiar language, in the sense that it uses indentation to identify code block structures - but it doesn't allow TABs to do that, so you need a special editor that can replace TAB characters with spaces. I haven't seen this in any other language, and it also uses semicolons to indicate the start of a code block. This takes some time to get used to.

As opposed to most modern languages, Python doesn't seem to be typed, which in computer science is considered a bad thing. Untyped languages can lead to confusion, and bugs that are difficult to identify. On the other hand, Python has an extremely simplified syntax, up to a minimalistic point, and the compiler is very clever. However, writing classes with an untyped language in this day and age seems awkward to say the least. Classes have very weak encapsulation, where there is no sense of private or protected class members or methods. Or maybe there is, but I am still new to it and haven't learned about it yet. But considering there are no data types, chances are that this is how it is. Nonetheless, I have been able to write regular data structures and OOP just like in other languages. It's odd, but it works.
 

phdubrov

Noteworthy
Contributing Artist
you need a special editor
Not Notepad, yes. But pretty much any editor made with code in mind will do: from Vim to MS Code. (SublimeText, Notepad++ and so on) PyCharm is better :) but too heavy for PoserPython hacking if you don't make something like EZMat.

It's called "XS"
This I have. Love for multi-material editing. Never crashed on me.
 

Ken1171

Esteemed
Contributing Artist
Not Notepad, yes. But pretty much any editor made with code in mind will do: from Vim to MS Code. (SublimeText, Notepad++ and so on)

I use Notepad++ for everything, but it didn't work with Python because if the TAB character. Python gives me a syntax error if indentation is made with TAB. It wants spaces instead.

This I have. Love for multi-material editing. Never crashed on me.

It will have a pretty good chance of crashing if you select a figure and press the "refresh" button. Over here it's almost a guarantee that it will crash Poser. ShaderTree().Refresh() only works per-material, so the command has to be ran over several MAT Zones, which is what I think causes the crashes. It happens with other scripts that try to do this as well. This goes all the way back to PhilC's Poser Tools in Poser 5. If the script calls refresh() repeatedly (required because it only affects a single MAT Zone), then Poser [most likely] crashes.
 

phdubrov

Noteworthy
Contributing Artist
I use Notepad++ for everything, but it didn't work with Python because if the TAB character.
Remembered! Had to change TAB settings for Python long time ago. (Specific tab settings can be made for any language in the settings-preferences-languages.)
 

Ken1171

Esteemed
Contributing Artist
Oh yeah, I have found that now! Thanks for the hint! :D

I have a question regarding importing external classes.

Runtime\Python\poserScripts\Ken1171\Composite Head\Classes <<== My modules are here
Runtime\Python\poserScripts\ScriptsMenu\Ken1171\Composite Head <<== I want to import them from here

This way keeps only classes the user can execute in the ScriptsMenu folder.

I have added the __init__.pyc file to the first path, where my modules are. Then I have tried adding the first folder to sys.path, but I still can't import the modules from my script in the 2nd path. What I am missing?
 

phdubrov

Noteworthy
Contributing Artist
1. .py, not .pyc
2. need the exact code of adding the first folder to sys.path; did you checked that path was added successfully?
 

Ken1171

Esteemed
Contributing Artist
I have experimented with either .py or .pyc, and it seems to work all the same. Of course, it's not necessary for the __init__.py to be compiled, since it's a blank file anyway, but over here Poser Python doesn't seem to care if it's one of the other.

I was adding the module path to sys like this:

sys.path.append(path_to_module_here)

I then check to see if has been added like:

if path_to_module_here in sys.path:
print('yes')
else:
print('no')

...and it was confirming it was added before I tried to import the module. I could do a print(sys,path) to confirm it. Nonetheless, it still raises an exception claiming the imported module doesn't exist.

I was looking for info online, and they say we have add to sys.path the path to the folder BEFORE the one that contains the modules and the __init__.py file, which was bugging me. I have tried either ways and get the same error, claiming the module I try to import doesn't exist.
 

phdubrov

Noteworthy
Contributing Artist
Runtime\Python\PoserScripts\phd\testmodule
__init__.py
actions.py
Code:
def hello():
    print("Hello World!")

Runtime\Python\PoserScripts\ScriptMenu\phd
testimport.py
Code:
#not really needed
import sys
import poser
#not really needed

temppath = poser.AppLocation()
temppath = temppath[:temppath.rfind('\\')]
temppath = temppath + '\\Runtime\\Python\\PoserScripts\\phd'
sys.path.append(temppath)

from testmodule import actions
actions.hello()
It's Win version, Mac workaround should be added. (if sys.platform...)
 

phdubrov

Noteworthy
Contributing Artist
If the script calls refresh() repeatedly (required because it only affects a single MAT Zone), then Poser [most likely] crashes.
A possible workaround to refresh preview for many mat zones at once:
save temp matfile for figure/object and load it. Should work.
 

Ken1171

Esteemed
Contributing Artist
Runtime\Python\PoserScripts\phd\testmodule
It's Win version, Mac workaround should be added. (if sys.platform...)

Thanks! What you have shown here was exactly what I was doing, and didn't work. The only difference was that I was finding the path in relation to where the main script was located at, instead of where Poser is installed at. The end result path ends up the same, but in either cases I get an error message claiming the module I have imported was not defined. I am also having trouble with the reload() command, where I do it like in the examples, and nothing gets reloaded. Error messages still show the old code. For now I am having to restart Poser every time... >__<

A possible workaround to refresh preview for many mat zones at once:
save temp matfile for figure/object and load it. Should work.

One thing I have learned [by accident] was that a single call to Scene().DrawAll() has the same effect as refreshing all the specific MAT zones individual. :)
 

phdubrov

Noteworthy
Contributing Artist
was not defined
not defined or could not be found?

And was it exactly the same? i.e. you had used from a import b, not import a and later a.b() ?
In the second case, you will get name b not defined or a has no property b IIRC.
 
Top