Thu, Oct 3, 12:22 PM CDT

Renderosity Forums / Poser Python Scripting



Welcome to the Poser Python Scripting Forum

Forum Moderators: Staff

Poser Python Scripting F.A.Q (Last Updated: 2024 Sep 18 2:50 am)

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: What path is used for actor.Load/SaveMaterialCollection(FileName) ?


3dcheapskate ( ) posted Tue, 14 June 2022 at 1:19 AM · edited Tue, 24 September 2024 at 3:25 AM

Looking in the Poser 9 PoserPython manual the  scene.Load/SaveLibraryCamera/Face/Figure/Hair/Hand/Light/Pose/Prop(filePath)  methods all require the complete path (absolute or runtime-relative, including filename and extension) as their argument.

But actor.Load/SaveMaterialCollection(FileName) only requires the filename (without any path), and material.Load/SaveMaterialSet(name) only requires the material name (without path, without extension).

So where do those load/save material methods get the path from ?


Background: I'm trying to write a very simple script for Poser 9 to, among other things, load a material collection from a folder on my desktop (no runtime structure, just a few Poser files of various types in a single folder), and/or save a material collection back  to another folder  (again no runtime structure, just a few Poser files of various types in a single folder) on my desktop. Why am I writing a script ? Because Poser 9 needs flash for the library, so the library doesn't work. There's no Poser 10 style workaround, and I'm having problems using the free 3rd party library P3DO. Why am I using Poser 9 ? I want to create the Poser files using the earliest version of Poser I have that supports what I need (e.g. particular nodes) to avoid that "This file is for a later version of Poser..." message when you load it.


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



3dcheapskate ( ) posted Tue, 14 June 2022 at 2:19 AM

While waiting for somebody who knows the answer I found this in a 9 year old script of mine...

import tempfile


# Get the location for writing temporary files
tempPath = tempfile.gettempdir()

...

# Force texture update! [SC]
currentMat = poser.Scene().CurrentMaterial()
poser.Scene().SelectMaterial(mat)
tempMat = os.path.join(tempPath, "temp.mt5");
try:
mat.SaveMaterialSet(tempMat)
mat.LoadMaterialSet(tempMat)
except:
poser.DialogSimple.MessageBox("SC:Mat update fail!")
if not currentMat is None:
poser.Scene().SelectMaterial(currentMat)
...

So maybe the Poser 9 PoserPython manual got it wrong ?

(note to self: Notepad++ EOL conversion to LF; cut-and-paste here - line-spacing screwed; repaste - line spacing okay; delete first paste)



The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



Y-Phil ( ) posted Tue, 14 June 2022 at 2:33 AM · edited Tue, 14 June 2022 at 2:37 AM

In Poser12, something like this works:
scene.LoadLibraryFigure("character:Aeon Soul:SantaMonicaHair:Braid_left.cr2")

VxJMOioXbcOkBMprbJWUdtMvIQ8C2pwU7LM4YtTy.png

I don't have Poser9 anymore, so that I can't test this for you on this version.

𝒫𝒽𝓎𝓁


(っ◔◡◔)っ

👿 Win11 on i9-13900K@5GHz, 64GB, RoG Strix B760F Gamng, Asus Tuf Gaming RTX 4070 OC Edition, 1 TB SSD, 6+4+8TB HD
👿 Mac Mini M2, Sonoma 14.6.1, 16GB, 500GB SSD
👿 Nas 10TB
👿 Poser 13 and soon 14 ❤️


3dcheapskate ( ) posted Tue, 14 June 2022 at 3:25 AM · edited Tue, 14 June 2022 at 3:31 AM

That's the runtime-relative filepath as per the PoserPython manual. It's the LoadMaterialCollection() and LoadMaterialSet() (which don't, according to the manual, include a path) that are puzzling me. But as noted in my previous post it appears that the manual is wrong, or at least slightly misleading.

Given that the Poser file extensions  for materials are mt5 and mc6 I'd guess that the methods for loading/saving materials were added in Poser 5 and 6 - designed, implemented, and documented by somebody different. And of course they're not scene methods.

It appears from my previous post that LoadMaterialSet() does/can in fact take a path as its argument. LoadMaterialCollection() probably does/can too.


jru6DginmkYgyq4FO9LqHhdjRvPxjZqcQK1jTxsq.jpg


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



Y-Phil ( ) posted Tue, 14 June 2022 at 6:31 AM

did you check with the Python Console?
I tend to trust more this

oSBeuFsa1H3iXqet6S54xW99zwXKp8p9Q8sD7vQG.png

𝒫𝒽𝓎𝓁


(っ◔◡◔)っ

👿 Win11 on i9-13900K@5GHz, 64GB, RoG Strix B760F Gamng, Asus Tuf Gaming RTX 4070 OC Edition, 1 TB SSD, 6+4+8TB HD
👿 Mac Mini M2, Sonoma 14.6.1, 16GB, 500GB SSD
👿 Nas 10TB
👿 Poser 13 and soon 14 ❤️


3dcheapskate ( ) posted Tue, 14 June 2022 at 8:28 AM

No, I didn't - I wouldn't know (a) where to find it, and (b) how to use it. The only way I ever run Python is via Poser's main menu > File > Run python script. :oD

P.S. What does the Python Consoile show for LoadMaterialSet() ? I'd wager it's more or less what's in the manual.


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



structure ( ) posted Tue, 14 June 2022 at 9:53 AM
Forum Coordinator

the manual was not written correctly, you need to pass the path, absolute or relative 

Locked Out


Y-Phil ( ) posted Tue, 14 June 2022 at 4:32 PM

3dcheapskate posted at 8:28 AM Tue, 14 June 2022 - #4439957

No, I didn't - I wouldn't know (a) where to find it, and (b) how to use it. The only way I ever run Python is via Poser's main menu > File > Run python script. :oD

P.S. What does the Python Consoile show for LoadMaterialSet() ? I'd wager it's more or less what's in the manual.

I think that the Python Shell command is in the Scripts menu, at least that's where it actually is in P11 & P12.
Both P11 and P2 don't display a lot for this function:

dn2TdkRCIKUvq5TidKgpcxHpVEkcp0Z6zivXi5tA.png

𝒫𝒽𝓎𝓁


(っ◔◡◔)っ

👿 Win11 on i9-13900K@5GHz, 64GB, RoG Strix B760F Gamng, Asus Tuf Gaming RTX 4070 OC Edition, 1 TB SSD, 6+4+8TB HD
👿 Mac Mini M2, Sonoma 14.6.1, 16GB, 500GB SSD
👿 Nas 10TB
👿 Poser 13 and soon 14 ❤️


yarp ( ) posted Wed, 15 June 2022 at 12:01 AM

I experienced that the best way to save a Material Collection with Python (in P10 at least) was from the Material Room.

Didn't work the same when saving from the Pose Room.

Yarp - author of P3DO Organizer for Poser


structure ( ) posted Wed, 15 June 2022 at 12:26 AM · edited Wed, 15 June 2022 at 12:27 AM
Forum Coordinator

here is a small snippet on how to use it. 


        ThisMaterial.SaveMaterialSet(tempmat)
        if os.path.isfile(tempmat+'.mt5'):
            tempmat += '.mt5'
        elif os.path.isfile(tempmat+'.mz5'):
            tempmat += '.mz5'
        else:
            tempmat = None
        if not tempmat is None:
            for Material in TheseMaterials:
                if not Material == ThisMaterial and not Material.Name().lower() == IgnoreMaterial:
                    Material.LoadMaterialSet(tempmat)

Locked Out


3dcheapskate ( ) posted Sun, 19 June 2022 at 9:27 AM · edited Sun, 19 June 2022 at 9:27 AM

yarp posted at 12:01 AM Wed, 15 June 2022 - #4439986

I experienced that the best way to save a Material Collection with Python (in P10 at least) was from the Material Room.

Didn't work the same when saving from the Pose Room.

That's something I hadn't thought about. In Poser 6 the library pane doesn't show the Materials library unless you're in the Material room - I wonder if that's related in any way ?

P.S. regarding the problems I was having with P3DO,  I don't really want to pester you as I've almost got my very simple script finished (P3DO is overkill for the simple thing I'm trying to do !)


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



3dcheapskate ( ) posted Sun, 19 June 2022 at 10:18 AM · edited Sun, 19 June 2022 at 10:20 AM

structure posted at 12:26 AM Wed, 15 June 2022 - #4439987

here is a small snippet on how to use it. 


        ThisMaterial.SaveMaterialSet(tempmat)
        if os.path.isfile(tempmat+'.mt5'):
            tempmat += '.mt5'
        elif os.path.isfile(tempmat+'.mz5'):
            tempmat += '.mz5'
        else:
            tempmat = None
        if not tempmat is None:
            for Material in TheseMaterials:
                if not Material == ThisMaterial and not Material.Name().lower() == IgnoreMaterial:
                    Material.LoadMaterialSet(tempmat)
Thanks, but that kinda sidesteps the actual question ! :o)

"But ... material.Load/SaveMaterialSet(name) only requires the material name (without path, without extension). 
So where do those load/save material methods get the path from ?"

However, since your snippet uses os.path.isfile(path) (that's a Python 2 docs link as I don't have Poser 12) which takes a full path (path, filename, extension) I guess that Python uses some default path - maybe the current working directory, os.getcwd() ?

Anyway - while cobbling together my script I accidentally passed a full path (path, filename, extension) to mat.SaveMaterialSet(whatever) and it wrote the file exactly where I'd said. That makes more sense to me - if I'm loading/saving a file I want to specify the full path.

I also tried saving an MT5 by passsing just the filename. No error thrown (I used try-except), but I can't find the file anywhere ! :oD


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



3dcheapskate ( ) posted Sun, 19 June 2022 at 10:38 AM

Another oddity.

- The PoserPython (Poser 9) save methods for face, light, mat collection, and material appear to automatically add the correct extension if you omit it.

- For camera and figure they don't

- (not sure about prop, hand, hair, and scene yet)


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



3dcheapskate ( ) posted Sun, 19 June 2022 at 10:55 AM · edited Sun, 19 June 2022 at 10:59 AM

Found the missing saved files !

Poser(Python) saved them to C:\Users\Public\Documents\Poser 9 Content*. 
Not the runtime subfolder of that, but directly into that folder. So if you call mat.SaveMaterialSet(filenameonlywithoutpath), as per the manual, it puts the MT5/MZ5 in the same folder as your runtime folder, which is NOT where anybody would want it.


*which is where the default Poser 9 content was installed. And that begs the question, why does my library preferences file say this ?

<?xml version="1.0" encoding="UTF-8"?>
<!-- LibraryPreferences. -->
<!-- Created: Sat Jun 11 23:41:33 2022 -->
<LibraryPreferences curFolder="0"  version="1"  previewNum="100"  limitPreview="0"  doubleClickReplace="0" >
<ContentFolder folder="C:\Program Files (x86)\Smith Micro\Poser 9\Runtime\libraries"  index="0"  searchIndexed="1" />
<ContentFolder folder="C:\Program Files (x86)\Smith Micro\Poser 9\Downloads\Runtime\libraries"  index="1"  searchIndexed="1" />
<CollectionFolder folder="Runtime\libraries\Collections"  index="0" />
</LibraryPreferences>

(I wonder if that explains the problem I was having with P3DO ?)


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



3dcheapskate ( ) posted Sun, 19 June 2022 at 11:19 AM · edited Sun, 19 June 2022 at 11:21 AM

Yet another thing I've noticed.

The extra dialogs you get when you load/save via the library appear as prints to the debug window if you load/save via PoserPython (e.g if you load an MC6 to the wrong figure there's that dialog about not having all the materials, would you like to create the missing ones?)

Except for the "left or right?" one when you load/save an HD2. That throws an error (try-except)

Yarp, I take my hat off to you ! :oD

(Luckily for me I'm not interested in hands)


The 3Dcheapskate* occasionally posts sensible stuff. Usually by accident.
And it usually uses Poser 11, with units set to inches. Except when it's using Poser 6 or PP2014, or when its units are set to PNU.

*also available in ShareCG, DAZ, and HiveWire3D flavours (the DeviantArt and CGBytes flavour have been discontinued).



structure ( ) posted Mon, 20 June 2022 at 9:26 PM · edited Mon, 20 June 2022 at 9:37 PM
Forum Coordinator

if it fails,  try except will fail with no error passed to the user unless the except clause raises an error.

So the file was not created, poser just did not inform you about it. 

for the path - try this:

import os
import poser
filepath = os.path.join("rootfoldername", "Runtime", "Libraries", "materials", "somefoldername", somefilename))
where
rootfoldername could be os.path.dirname(poser.AppLocation()) or (poser.Libraries()[x]) or some other startpoint

you can also create your own dialogs

DialogSimple Methods
This class of methods was introduced in Poser 6.0.0.

AskActor
Explanation Ask the user to select an actor.
Arguments Enter the request message.
Syntax <NoneType> AskActor(<StringType> message)

AskFloat
Explanation Ask the user for a floating-point number.
Arguments Enter the request message.
Syntax <FloatType> AskFloat(<StringType> message)

AskInt
Explanation Ask the user for an integer value.
Arguments Enter the request message.
Syntax <FloatType> AskInt(<StringType> message)

AskMenu
Explanation Ask the user to select an item in a menu.
Arguments Enter the menu title, the request message, and each of the subsequent items in the menu.
Syntax <StringType> AskMenu(<StringType> title, <StringType> message, <StringType> item1, <StringType> item2, ...)

DialogSimple
Explanation Creates an object of the DialogSimple class type – in other words, a simple dialog.
Arguments none
Syntax <NoneType> DialogSimple()

MessageBox
Explanation Show a message box with the message and an OK button.
Arguments Enter the message.
Syntax <NoneType> MessageBox(<StringType> message)

PickImage
Explanation Bring up the Texture Manager and let the user pick an image for this input.
Arguments Specify the input to which the new image node will be attached.
Syntax <NoneType> PickImage(<ShaderNodeInputType> inputInput)

YesNo
Explanation Show a dialog with the message and a Yes and a No button.
The function returns 1 if the user clicks Yes, and 0 if the user clicks No.
Arguments Enter the message.
Syntax <IntType> YesNo(<StringType> message)

Locked Out


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.