Mat Preset to Change ONLY Colors on a Blender Node?



  • @karina Now that @Snarlygribbly has made the source for EZSkin (and others) public domain you can get a lot of examples of Wx and Other stuff especially to do with the mat room.



  • @karina oh, some other material related things I've recently had to deal with in my own scripts:

    Some actors have no materials, so you can't safely iterate over actor.Materials() without try:except: or a pre-test. This is just bad API programming IMVHO. Materials() should return an empty list if there are no materials, not None!

    For completeness' sake, you need to iterate through the layers within each material, as they have a separate ShaderTree with it's own UpdatePreview() method.

    On occasion, you also strike materials which present with no ShaderTree, so I use:

    for actor in scene.Actors():
        if actor.ItsFigure() is None:
            if actor.Materials(): # Some actors like "UNIVERSE" return None, so we can't just iterate
                for mat in actor.Materials():
                    for layer in mat.Layers():
                        try:
                            tree = layer.ShaderTree() # Some materials raise poser.error on this call
                            if not tree:
                                continue
                        except: # Ignoring implicit poser.error from ShaderTree() call
                            continue
                        # Parse tree
    else: # Now parse figures' materials
        for figure in scene.Figures():
            try: # An alternative way to protect from a None on calling Materials()
                for mat in figure.Materials():
                    for layer in mat.Layers():
                        try:
                            tree = layer.ShaderTree() # Some materials raise poser.error on this call
                            if not tree:
                                continue
                        except: # Ignoring implicit poser.error from ShaderTree() call
                            continue
                        # Parse tree
            except:
                pass # Ignore inability to iterate over potential None returned by Materials() call
    

    These are not prescriptive examples, just ways I've come up with to quash unexpected script errors. I also note that my sample loop may not deal appropriately with props on figures that have their own materials. I've frequently noted to myself that it's terribly wasteful to iterate over all of the actors in a figure, since the materials they return are just the ones you get from the figure directly, except when an actor or prop has customMaterials.



  • @amethystpendant said in Mat Preset to Change ONLY Colors on a Blender Node?:

    @karina Now that @Snarlygribbly has made the source for EZSkin (and others) public domain you can get a lot of examples of Wx and Other stuff especially to do with the mat room.

    Oh did he? I didn't know, so thank you for the heads-up!

    @anomalaus said in Mat Preset to Change ONLY Colors on a Blender Node?:

    @karina oh, some other material related things I've recently had to deal with in my own scripts:

    Some actors have no materials, so you can't safely iterate over actor.Materials() without try:except: or a pre-test. This is just bad API programming IMVHO. Materials() should return an empty list if there are no materials, not None!

    For completeness' sake, you need to iterate through the layers within each material, as they have a separate ShaderTree with it's own UpdatePreview() method.

    On occasion, you also strike materials which present with no ShaderTree, so I use:
    (see post above)
    These are not prescriptive examples, just ways I've come up with to quash unexpected script errors. I also note that my sample loop may not deal appropriately with props on figures that have their own materials. I've frequently noted to myself that it's terribly wasteful to iterate over all of the actors in a figure, since the materials they return are just the ones you get from the figure directly, except when an actor or prop has customMaterials.

    Thank you for looking further into the code!

    To my defense let me say that it's still much experimenting - wrote my last line of Py code over a year ago :/
    You're right, omitting error management is bad style, but if I add it in the development phase I wouldn't get immediate error messages in the "print" window. And I get a lot of error messages, believe me :)

    Thank you for the heads-up about the problem with missing mat zones and other caveats in the "iterate" routine, and especially for your example.
    I'll have a look at it this weekend and rewrite my own code accordingly. Unfortunately I'm too busy today...

    Thank you for your help!

    Karina



  • To give at least a little back, here is something I figured out

    Because I wanted to add the ability to change the current actor in my script I thought I could use the eventCallback()
    for Poser.
    During my searches I stumbled upon this thread and post:

    @fbs7 said in Metaballs script:

    Hmm.. check this:

    def eventCallback(scene, code):
    	if code <> 16:
    		print 'Code = ',code
    
    ...
    scene.SetEventCallback(eventCallback)
    

    It will display a continuous series of code = 16, even when nothing's happening. No idea yet what is that 16. Whenever you change frames manually, it sends a code = 17

    So I tinkered with it but got the same result, a continous kEventCode_ "16" running ad nauseum until I killed it with
    "scene.ClearEventCallback()"

    Here's what I tried to make it work:

    """
    # Notes on the EventCallBack():
    #	 - Poser returns kEventCode "16" all the time, endlessly, unless an event happens.
    #	 - IF an event happens (like selecting another actor), 
    #	   Poser still returns "16", >>>but this time ADDS the kEventCode of the actual event<<<:
    #	   SO an event like poser.kEventCodeACTORSELECTIONCHANGED (which is 8) 
    #	   will return: 16 + 8
    # 
    # Since kEventCode "16" is undocumented, I think it stands for "idle" and is only constantly
    # sent due to a glitch in the code 
    # (because, it doesn't make sense to waste processing power for a non-event)
    """
    
    def eventCallbackFunc(thisScene, thisEventType):
    	if thisEventType <> 16: # filter out the constant "16" events
    		if thisEventType == 16 + poser.kEventCodeACTORSELECTIONCHANGED: # add 16 to the kEventCode
    			print "A new actor was selected. Code: ", thisEventType # print only for testing
    	
    scene.SetEventCallback(eventCallbackFunc)
    

    Maybe it's useful.
    K



  • @karina Announcing that Poser has nothing important to do makes sense. I use this often to delay my own functions to make sure Userinput has priority.



  • @anomalaus It's Python. You can create your very own special iterator's.

    Returning None if an actor has no materials is correct. An empty list means something different (again: it's Python 😉).



  • @karina Have a look into Posers Python folder with demo scripts. There is a script called "eventCallback.py".
    Here is the better way to handle events:

    def EventCB(iScene, iEventType):
    	string = ''
    	if( (iEventType & poser.kEventCodeKEYSCHANGED) != 0):
    		string = string + 'KeysChanged, '
    	if( (iEventType & poser.kEventCodePARMCHANGED) != 0):
    		string = string + 'ParmChanged, '
    	if( (iEventType & poser.kEventCodeACTORDELETED) != 0):
    		string = string + 'ActorDeleted, '
    	if( (iEventType & poser.kEventCodeACTORSELECTIONCHANGED) != 0):
    		string = string + 'ActorSelectionChanged, '
    	if( (iEventType & poser.kEventCodePARMDELETED) != 0):
    		string = string + 'ParmDeleted, '
    	if( (iEventType & poser.kEventCodeACTORADDED) != 0):
    		string = string + 'ActorAdded, '
    	if( (iEventType & poser.kEventCodePARMADDED) != 0):
    		string = string + 'ParmAdded, '
    	if( (iEventType & poser.kEventCodeITEMRENAMED) != 0):
    		string = string + 'ItemRenamed, '	
    	if( (iEventType & poser.kEventCodeANIMSETSCHANGED) != 0):
    		string = string + 'AnimSetsChanged, '
    	if( (iEventType & poser.kEventCodeSETUPMODE) != 0):
    		string = string + 'SetupMode, '
    ...
    

    Reason is that iEventType may contain more then one event, e.g.:

    iEventType = kEventCodeACTORSELECTIONCHANGED | kEventCodeACTORADDED
    


  • @karina is it not Poser's own equivalent of ProcessSomeEvents(). I.e. a way of sharing processing time with subprocesses. Since Poser deprecates (if not prevents) Python scripts being multi-threaded in any real sense.



  • @adp I understand that, but I don't agree with the distinction. Python is subordinate to Poser, in this case, so Poser's Python API should reflect the requirements of Poser, not Python's style guide.

    Anyway, it's not worth arguing over :-). I just felt that to make an unnecessary exception for a single actor in the scene, "UNIVERSE" which never has, and can never have any materials, is an unfortunate trap for simple iterations over all actors, forcing special handling, rather than "empty list, so nothing to do here". When someone digitizes Guido's brain, then we'll all be more enlightened over the whys and wherefores of Python. (Not that I imagine Poser will ever support Python 3+)


  • Poser Ambassadors

    Most of what Poser Python does is cpu bound, so having a threading module would more often than not just slow it down.



  • @anomalaus You don't need and exeption.

    The "pythonic way" is:

    for mat in Materials() or []:
        print mat
    


  • @adp kewl! New toy to play with ;-) Haven't seen that one before. I've been gradually trawling through my scripts and replacing abort flags and code blocks with asserts, where appropriate.

    Python's funny in the way a piece of code can run happily for ages, until you run into that one condition with an unhandled exception and BOOM! everything falls over. ;-)



  • @shvrdavid that's fair. I just picked that observation in relation to processes, not because I have any issue with it. Multi-threaded bending is certainly a worthy case of something entirely within Poser's control, whereas Python scripts can never be.

    Speaking of processes and Python, it would truly be wonderful if there were a way to record the details of a PythonCallback valueOperation (which may not have been installed within the purview of a currently executing script, so that it could be temporarily removed and then restored along with all of the other valueOperations affecting a parameter. I've run into this case a few times when trying to implement procedures which need to extract parameter dial values at a range of frames, without valueOperation influence. Even if the callback is only monitoring a parameter, and not modifying it's value, there's no way to restore it if you didn't apply it in the first place. I'm still waiting for an UnaffectedValueFrame() method to avoid having to iterate through actual animation frames and use UnaffectedValue() at each step.



  • Oups, looks like I've opened a can of worms here, at least for me :D

    Meaning, I don't even guess what you people are discussing here in the last few threads.
    To me this is all like Ron Moore (STTNG witer) lately admitted:

    At his recent keynote speech at the New York Television Festival, former Star Trek writer and creator of the re-imagined Battlestar Galactica Ron Moore revealed the secret formula to writing for Trek.
    He described how the writers would just insert "tech" into the scripts whenever they needed to resolve a story or plot line, then they'd have consultants fill in the appropriate words (aka technobabble) later.
    "It became the solution to so many plot lines and so many stories," Moore said. "It was so mechanical that we had science consultants who would just come up with the words for us and we'd just write 'tech' in the script. You know, Picard would say 'Commander La Forge, tech the tech to the warp drive.' I'm serious. If you look at those scripts, you'll see that."
    Moore then went on to describe how a typical script might read before the science consultants did their thing:
    La Forge: "Captain, the tech is overteching."
    Picard: "Well, route the auxiliary tech to the tech, Mr. La Forge."
    La Forge: "No, Captain. Captain, I've tried to tech the tech, and it won't work."
    Picard: "Well, then we're doomed."
    "And then Data pops up and says, 'Captain, there is a theory that if you tech the other tech ... '" Moore said. "It's a rhythm and it's a structure, and the words are meaningless. It's not about anything except just sort of going through this dance of how they tech their way out of it."

    Full blog entry here: http://www.antipope.org/charlie/blog-static/2009/10/why_i_hate_star_trek.html
    and I DISAGREE with "Charlie" (Charles Stross) rant as far as Star Trek is concerned (discussing this would lead us to OT, so I'lll skip)

    What I want to say is:

    Most of your replies are far, far beyond my own knowledge of Python.
    I hope it makes sense to me some time later.
    --> Is there a way to save this whole thread to my local disk for future reference?

    Besides that, I want to thank you all VERY MUCH for all the input you made.
    And though I didn't understand many of it, I still learned some things - and that's what this is about.
    I'll keep watching this thread.

    Karina



  • @karina "Semper Tech" ;-)

    Having worked with colleagues who could not ever admit that they didn't know or understand something, until caught out blatantly BS'ing, I am a great fan of admitting that one doesn't know everything and is always happy to learn, even that one has mis-spoken through ignorance. That way, people are happier to share both their mistakes and successes. Enlightenment (and Potassium Nitrate!) can be found in the darkest dung-piles ;-)


  • Poser Ambassadors

    @anomalaus

    Extracting scene info from Poser can be a challenge. (Yes, I have brought that up more times than I can count...)

    There are more than a few things that are basically impossible to extract directly with Python.

    Many things that you might not first think of can be accessed if you save the scene to a temp file, then parse out the info you are after.
    I have seen more than a few scripts that do just that to get at things that are not directly poll-able with Python.



  • @shvrdavid well now, that is actually useful and encouraging :-). I have a reasonably full-featured parser, though it's problems are as much about a lack of API methods to create the things it has parsed (deformer falloff curves, for a start, though I have successfully applied them via loaded poses, but only if the scene contains a figure - and lo, and behold, even a dummy figure like the cross-talk eliminator will do, to allow adjustment of scene prop deformers). Saving an entire scene and then parsing it had not occurred to me (or was subconsciously eliminated as unwieldy, inelegant and slow). I've always wanted to be able to determine how Poser categorises cameras as user created. If the API won't tell me, a saved scene file certainly will. Hmmm...

    Well, well, well (three holes in the ground!). If that isn't just the second most useful thing that auto-saved scene files can do!

    [Hops merrily down the road to the tune of "A parsing we will go..." ;^) ]


  • Poser Ambassadors

    Yes there are things that the API wont let you create.
    Think outside the box thou.

    After you parse out and do whatever you want with the info, you can write a scene file and load it as well.



  • Just wanted to post a quick update to let anyone looking for a similar solution know that Karina's Batch Color Gadget works very well for the purpose I described above!

    You just have to set up your materials so that the main color is driven by a Simple_Color node that's plugged into a black/0 Ambient channel. The Simple_Color node should also be plugged into whatever part of your shader tree makes the most sense. If I was still using the Blender method I started with, I would've plugged into the Blender inputs. But now I have it plugged into the inputs on a Clouds node that mixes two shades of the color. If I want to change the color on multiple props, I just invoke Karina's gadget, select a new color, and voila, everything has the new color! Very nifty. THANK YOU Karina!!

    You can find the Batch Color Gadget on Karina's Sasha-16 forums in this post.

    Here's a screenshot of one of my simpler materials to illustrate. (You'll note that I changed the name of the Simple_Color node, but the script still works!)

    0_1536275044367_ColorGadgetInfo-PaintStrip.png



  • Just in case anyone reading this thread is curious about the "Messy Painter" prop set I was working on, it's now available for download on ShareCG.

    Many thanks in particular to Karina and IronSoul for their help with scripts that made it easier for me to set up 14 paint colors for each prop!