Forum Moderators: Staff
Poser Python Scripting F.A.Q (Last Updated: 2024 Dec 02 3:16 pm)
A simple function to copy matrerial collections between figures and props. if the target (a prop or a figure) has a material defined with a name that also appears in the materials list of the source, that material definition (shader) in the target will be overwritten by the material of the source.
def copyMaterialDefinitions(source, target):
srcmats = source.Materials()
tgtmats = target.Materials()
for srcmat in srcmats:
matnam = srcmat.Name()
srcmat.SaveMaterialSet(matnam)
try:
target.Material(matnam).LoadMaterialSet(matnam)
except:
pass
I tried some of the dialogs class yesterday because I needed some of the functions. I assume the site formatting has ironed some things away here and there:
D_paths = re.findall(r'XDG_DESKTOP_DIR="([^"]*)', data)
FVerbaas posted at 6:07PM Mon, 06 January 2020 - #4375651
I tried some of the dialogs class yesterday because I needed some of the functions. I assume the site formatting has ironed some things away here and there:
- the definition of 'types' in GetFile triggers a complilation error and indentaiton error.
- in 'get_desktop_path', 're' is not defined in
D_paths = re.findall(r'XDG_DESKTOP_DIR="([^"]*)', data)
add
Import re
Locked Out
A dictionary of poser Figures by geometry:
Locked Out
Copy to Clipboard
without wx :
from subprocess import check_callclass clipboard:def copy2clip(self, txt):cmd='echo '+txt.strip()+'|clip'return check_call(cmd, shell=True)
Locked Out
I often use the following little function if I have to script something with Poser meshes. I do that outside of Poser, because I often need a debugger to follow what the script is doing step by step in critical parts.
With Poser-Python:
import numpy as NP
try:
import poser
INSIDEPOSER = True
except ImportError:
# "POSER_FAKE" is a Python lib to allow your editor to know about Poser
# for scripting outsite of Poser (code completition, type checking, highlighting).
# Author: adp001
# Direct download: http://adp.spdns.org/FakePoserLib3.zip
import POSER_FAKE as poser
INSIDEPOSER = False
# Pickle is used to save|load the complete geometry instead of a slow obj loader.
try:
import cPickle as pickle
except ImportError:
import pickle
# Returns python list (assume given poly is tri or quad):
f_forcequad = lambda _poly: list(_poly) if len(_poly) == QUAD else list(_poly) + [_poly[-1]]
VERSION = float(poser.Version()) if poser.Version()[0].isdigit() else 11
NP_PRECISION = NP.float32 if int(VERSION) <= 11 else NP.float
def save_figure(fig, filename):
"""
Saves verts, tverts, polys (4 vertices as float), polysets (4 indices crossreferencing verts),
tpolys (2 vertices as float), tpolysets (2 indices creossreferencing tverts), material names
and a material indexlist for cross-reference.
All collected arrays from current figure are pickled into a file.
:param fig: Poser figure
:param filename: Path and filename
:type fig: poser.FigureType
:type filename: basestring
"""
if INSIDEPOSER:
# Get unimesh of current figure (unmorphed, unposed)
poser_geom = fig.UnimeshInfo()[0]
assert isinstance(poser_geom, poser.GeomType)
geom = MyGeom(
verts=NP.array([[v.X(), v.Y(), v.Z()] for v in poser_geom.Vertices()], NP_PRECISION),
tverts=NP.array([[v.U(), v.V()] for v in poser_geom.TexVertices()], NP_PRECISION),
polys=NP.array([f_forcequad([[v.X(), v.Y(), v.Z()] for v in p.Vertices()])
for p in poser_geom.Polygons()], NP_PRECISION),
polysets=NP.array([f_forcequad(poser_geom.Sets[p.Start():p.Start() + p.NumVertices()])
for p in poser_geom.Polygons()], NP.int32),
tpolys=NP.array([f_forcequad([[v.U(), v.V()]
for v in p.TexVertices()]) for p in poser_geom.TexPolygons()],
NP_PRECISION),
tpolysets=NP.array([f_forcequad(poser_geom.Sets[p.Start():p.Start() + p.NumVertices()])
for p in poser_geom.TexPolygons()], NP.int32),
matindex=NP.array([p.MaterialIndex() for p in poser_geom.Polygons()], NP.int32),
matnames=[m.Name() for m in poser_geom.Materials()]
)
p = poser.TexPolygonType()
with open(filename, "wb") as fh:
pickle.dump(geom, fh, pickle.HIGHEST_PROTOCOL)
return geom
return None
This saves all those collected data in a file (pickled).
To load the data back if you are scripting outside of Poser:
try:
import cPickle as pickle
except ImportError:
import pickle
with open(filename, "rb") as fh:
geom = pickle.load(fh)
(Make sure there is access to the class you saved the file with – maybe it's better to use plain dict in the Poser script part)
Now you can get from the dict what you need and ignore/discard the rest.
Some "constants" I often use:
# Poser <= version 11 seems to work with 32-bit float precision (Numpy standard is 64-bit)
VERSION = float(poser.Version()) if poser.Version()[0].isdigit() else 11
NP_PRECISION = NP.float32 if int(VERSION) <= 11 else NP.float
NP_VERT_ZERO = NP.array((0, 0, 0), NP_PRECISION)
# Simplification to deal with some names used as indices
X, Y, Z = range(3)
A, B, C, D = range(4)
QUAD = 4
TRI = 3
(Because Poser does not know constants, I write them in Uppercase to remember)
The function to save the figure is pretty slow, because a whole lot of function calls to Poser are needed when collecting the indices. Use the following and it is pretty fast:
vsets = poser_geom.Sets()
tsets = poser_geom.TexSets()
geom = MyGeom(
verts=NP.array([[v.X(), v.Y(), v.Z()] for v in poser_geom.Vertices()], NP_PRECISION),
tverts=NP.array([[v.U(), v.V()] for v in poser_geom.TexVertices()], NP_PRECISION),
polys=NP.array([f_forcequad([[v.X(), v.Y(), v.Z()] for v in p.Vertices()])
for p in poser_geom.Polygons()], NP_PRECISION),
polysets=NP.array([f_forcequad(vsets[p.Start():p.Start() + p.NumVertices()])
for p in poser_geom.Polygons()], NP.int32),
tpolys=NP.array([f_forcequad([[v.U(), v.V()]
for v in p.TexVertices()]) for p in poser_geom.TexPolygons()],
NP_PRECISION),
tpolysets=NP.array([f_forcequad(tsets[p.Start():p.Start() + p.NumTexVertices()])
for p in poser_geom.TexPolygons()], NP.int32),
matindex=NP.array([p.MaterialIndex() for p in poser_geom.Polygons()], NP.int32),
matnames=[m.Name() for m in poser_geom.Materials()]
)
I''m no snakehead, and I'm not sure if this is even a good thing to do, but I'm always changing the shadow strength for lights, so I modified someone's script (can't remember whose). This script is useful to me, because, when there are a lot of lights, the displayed log tells me what I've changed already.
# Change Shadow Intensity of Selected Lights #
import poser scene = poser.Scene() actor = scene.CurrentActor()
def doIt(): dialog = None dialog2 = None actor = scene.CurrentActor("GROUND") dialog = poser.DialogSimple.AskActor("Please select a light.") actor = scene.CurrentActor(dialog) if actor.IsLight(): print "n ",actor.Name() dialog2 = poser.DialogSimple.AskFloat("Type a value from 0 to 1.") if dialog2 == None: print "n Please type in a value from 0 to 1." doIt() else: if float(dialog2) < 0: print "n Please type in a value from 0 to 1." doIt() elif float(dialog2) > 1: print "n Please type in a value from 0 to 1." doIt() else: print "n You want ",dialog2," shadow intensity for ",actor.Name() actor.ParameterByCode(poser.kParmCodeDEPTHMAPSTRENGTH).SetValue(float(dialog2)) print "n Update done." scene.SelectActor(scene.Actor("GROUND")) another() else: print "n You didn't select a light." doIt()
def another(): message = "Select another light?" dialog = None dialog = poser.DialogSimple.YesNo(message) if dialog == 1: print "n Yes, another light." doIt() else: print "n No, no more lights." return
doIt()
W11,Intel i9-14900KF @ 3.20GHz, 64.0 GB RAM, 64-bit, GeForce GTX 4070 Ti SUPER, 16GB.
Old lady hobbyist.
All visual art or fiction is "playing with dolls."
Updated version of the above code
# -*- coding: utf-8 -*-
# Change Shadow Intensity of Selected Lights
import poser
import wx
scene = poser.Scene()
title = "Shadow Intensity Editor"
def chooselights( title = "", prompt = "", OptionList = [], parent = None ):
if OptionList == []: return False
dialog = wx.MultiChoiceDialog( parent, prompt, title, OptionList )
if dialog.ShowModal() == wx.ID_OK:
selections = dialog.GetSelections()
strings = [OptionList[x] for x in selections]
if selections == []:
selections = False
return ( selections )
else:
return ( False )
dialog.Destroy()
def gettextentry( title = "", message = "", parent = None ):
TE_dialog = wx.TextEntryDialog( parent, message, title, "", style=wx.OK)
TE_dialog.SetValue("")
return TE_dialog.GetValue() if TE_dialog.ShowModal() == wx.ID_OK else False
def okcancel( title = "", alertmessage = "", okonly = False, parent = None ):
if okonly:
style = ( wx.OK|wx.ICON_INFORMATION|wx.STAY_ON_TOP )
else:
style = ( wx.OK|wx.CANCEL|wx.ICON_INFORMATION|wx.STAY_ON_TOP )
ok_dialog = wx.MessageDialog( parent, alertmessage, title, style )
return True if ok_dialog.ShowModal() == wx.ID_OK else False
lights = []
for light in scene.Lights():
lights.append( light.Name() )
lights = chooselights( title, "Please select which lights to edit.", lights )
if lights:
try:
value = float( gettextentry( title, "Please enter your value ( 0 - 1 )" ) )
except:
value = 0
for light in lights:
scene.Lights()[light].ParameterByCode( poser.kParmCodeDEPTHMAPSTRENGTH ).SetValue( value )
if you wish to edit each light individually, change the script to the following :
lights = []
for light in scene.Lights():
lights.append( light.Name() )
lights = chooselights( title, "Please select which lights to edit.", lights )
if lights:
for light in lights:
try:
value = float( gettextentry( title, "Please enter your value ( 0 - 1 )" ) )
except:
value = scene.Lights()[light].Value()
scene.Lights()[light].ParameterByCode( poser.kParmCodeDEPTHMAPSTRENGTH ).SetValue( value )
Locked Out
A simple lights class
class poserlights:
def processlights( self, code = 0 ):
if not isinstance( code, int):
return
lights = scene.Lights()
if not code > 1:
# LightsOnOff
[light.SetLightOn(code) for light in lights]
elif code == 2:
# toggle lights
[light.SetLightOn(not light.LightOn()) for light in lights]
else:
# Delete Lights
[light.Delete() for light in lights]
scene.DrawAll()
import poser
scene = poser.Scene()
l = poserlights()
# turn lights off
l.processlights(0)
# turn lights on
l.processlights(1)
# toggle lights
l.processlights(2)
# delete lights
l.processlights(3) (any number above 2)
Locked Out
Dealing with figure IK
Locked Out
Use a tuple as a dictionary key
theDict = { (0,1,2,3) : "This is a test" }print(theDict[ tuple(range(0,4))])which gives this outputThis is a testkeys=theDict.keys()test=(0,3)for item in test:for key in keys:if item in key:print(theDict[tuple(key)])which also gives this outputThis is a test
Locked Out
call a function using a string as a variable.
output
You are in the get_all_scene_materials function
You are in the get_item_materials function
Locked Out
create your UI with no stay_on_top style
Locked Out
Locked Out
Locked Out
adp001 posted at 3:55PM Tue, 08 December 2020 - #4406505
Or in short (and without the use of a library):
this is awesome, I always forget about lambda, thanks.
Locked Out
list the contents of a folder in date order - new to old or old to new ( dealers choice )
Locked Out
get Poser's install directory from the windows registry While this is actually mostly redundant
thanks to Poser's AppLocation() it does show how to access the registry to read keys / data.
import winreg as regclass _REGISTRY:def _find_poser_win(self, version):poser = r"SOFTWARE\\Poser Software\\Poser\\Poser %d" % versionwith reg.OpenKey(reg.HKEY_LOCAL_MACHINE, poser) as key:if poser.endswith(str(version)) and key:return(reg.QueryValueEx(key, "InstallDir")[0])# example codeinstalldirs = []for version in (10, 11, 12):print(f"testing Poser {version}")try:installdir = _REGISTRY()._find_poser_win(version)except:installdir = "Not Installed"if not installdir in installdirs:installdirs.append(installdir)print(installdir)
Locked Out
Check if a module exists before trying to import it.
Locked Out
store dictionary names in a list, and retrieve them as a printable string
Locked Out
Find a word / phrase in any file without loading the file into memory;
Locked Out
get machine current ID and BIOS serial number
Locked Out
sort dictionary by value
Locked Out
Locked Out
A shorter and less complicated version:
import os
import re
def get_library_pathes():
version = int(poser.Version().split(".")[0])
fname = os.path.join(os.environ["APPDATA"],
"Poser" if version < 11 else "Poser Pro", str(version),
"LibraryPrefs.xml")
re_libs = re.compile(r"<ContentFolder.*?folder=\"([^\"]+)\"")
with open(fname, "r") as fh:
for line in fh:
res = re.search(re_libs, line)
if res:
yield res.group(1)
if __name__ == "__main__":
for entry in get_library_pathes():
print(entry)
Not so seldom we have situations in which an occurring error is tollerable. Typically we wrap such a situation in a try/except clause.
But this can also be done differently, if we use an appropriate class:
class objectdef __init__selfpass
def __enter__selfreturn self
def __exit__self, , , return True
with ignore_error():
actor = poser.Scene().Actor("not existing actor")
without causing an error.
Note that the entire block after "ignore_error" is ignored in case of an error. Like the part that follows a "try".
A slightly extended version prevents only allowed exceptions:
class ignore_error(object):
def __init__(self, *args):
self.tolerable = args
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
return exc_type in self.tolerable if len(self.tolerable) else True
with ignore_error(NameError, poser.error):
actor = poser.Scene().Actor("not existing actor")
(The construct is called "Context Manager", by the way).
As you can see above, the editor still doesn't work properly. The indentations are completely off when they are displayed. When I bring the text back into the editor, it looks completely right again.
Here again inserted as standard text:
class ignore_error(object):
def __init__(self, *args):
self.tolerable = args
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
return exc_type in self.tolerable if len(self.tolerable) else True
with ignore_error(NameError, poser.error):
actor = poser.Scene().Actor("not existing actor")
adp001 posted at 3:50 PM Tue, 2 November 2021 - #4429791
this line :A shorter and less complicated version:
import os
import re
def get_library_pathes():
version = int(poser.Version().split(".")[0])
fname = os.path.join(os.environ["APPDATA"],
"Poser" if version < 11 else "Poser Pro", str(version),
"LibraryPrefs.xml")
re_libs = re.compile(r"<ContentFolder.*?folder=\"([^\"]+)\"")
with open(fname, "r") as fh:
for line in fh:
res = re.search(re_libs, line)
if res:
yield res.group(1)
if __name__ == "__main__":
for entry in get_library_pathes():
print(entry)
does not appear to working - I have set version to 12 - but it keeps using poser pro as the folder name .
Locked Out
adp001 posted at 2:49 AM Wed, 3 November 2021 - #4429830
looking forward to trying this outAs you can see above, the editor still doesn't work properly. The indentations are completely off when they are displayed. When I bring the text back into the editor, it looks completely right again.
Here again inserted as standard text:class ignore_error(object):
def __init__(self, *args):
self.tolerable = args
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
return exc_type in self.tolerable if len(self.tolerable) else True
with ignore_error(NameError, poser.error):
actor = poser.Scene().Actor("not existing actor")
Locked Out
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.
So I think with the advent of a new dawn for poser, this forum could use a sticky thread where snakeheads can supply snippets of poser python code that others may find useful, or indeed, be able to improve upon. Let me start the ball Rolling - the following is a complete library that I have built / collected over the years ( there are more to follow ) Some of the code was written by others, edited by myself and is now here - for the use of all of you fellow coders should you choose to.
Locked Out