Creating dependencies between settings on the Surfaces tab and Parameters tab

3dcheapskate3dcheapskate Posts: 2,070

(This thread is a continuation of the "follow-on stuff" that was going on in the DS: Creating a slider on the Parameters tab that can ONLY have integer values (+follow-on stuff...) thread over on the Technical Help forum)

I've now created very simple test script to apply bidirectional linking of parameters on the Surfaces tab to parmeters on the Parameters tab.

The script was cobbled together from bits of the post_load_material_proxy_create.dsa and post_load_material_proxy_link_properties.dsa sample scripts and the DzSettings documentation, replacing the ephemeral 'DataItem' with good old hard-coded stuff.

I left the script using the bidirectional DzNumericProperty::linkTo() to set up the links because I couldn't work out how to create a unidirectional DzERCLink (the DzERCLink constructors creating 'controllers' is one level of Object Obfuscation beyond me at present!)

 

The main problem I'd come up against over on the other thread was that applying a material preset sometimes (i.e. under certain criteria) breaks these links.
What I'm trying to do is find a way to maintain (or reinstate) these links when (after) a material preset has been applied.
Use of the DzCallBack was proposed as a solution, but I really can't get my head around that stuff.

So that's the introduction to what this thread is about.

 

Here's the script in-line (edit: replacing tabs with '   ', using the 'insert code snippet' icon next to image on the forum post editor, and using 'javascript'option , as suggested by Syrus_Dante) if you don't want to download it but could do with a laugh!

    // This is just a simple test script to apply BIdirectional linking of parameters

    // HOW TO USE:
    // - Open DS4.8+,
    // - Create a primitive sphere
    // - apply a texture to the Diffuse Color (one that make changes to tiling offsets obvious)
    // - create two new float parameters on the parameters tab (in a new group/path called 'TEST',or anything you want) - names are "Vertical Offset" and "Horizontal Offset"
    // - run this script
    // The tiling offsets on the Surfaces tab are now BIdirectionally linked to the twonewsliders on the parameters tab
    
    MessageBox.information("STARTED...","INFO","OK");
    var sSettings = [
        '<Settings>',
        ' <Setting Type="Float" Key="Horizontal Offset">0</Setting>',
        ' <Setting Type="Float" Key="Vertical Offset">0</Setting>',
        '</Settings>'
    ].join( "\n" );

    var aNodes = Scene.getSelectedNodeList();
    if ( aNodes.length == 1 ){
        var oNode = aNodes[0];
        var sName = "Default"   // The material we're going to work with
        if( oNode ){
            var oObject = oNode.getObject();
            if( oObject ){
                var oShape = oObject.getCurrentShape();
                if( oShape ){
                    var oMaterial = oShape.findMaterial( sName );
                    if( oMaterial ){
                        MessageBox.information("...FOUND MATERIAL","INFO","OK");
                        // var oPropertySettings = oSettings.getSettingsValue( "properties" );
                        
                        var oPropertySettings = new DzSettings();
                        if( oPropertySettings.fromString( sSettings ) ){
                            
                            MessageBox.information("Read of XML encoded data was successful.","INFO","OK");
                            print ("oPropertySettings = "+oPropertySettings);

                            if( oPropertySettings ){
                                MessageBox.information("...FOUND PROPERTY SETTINGS","INFO","OK");
                                var oMaterialProperty, oProxyProperty;
                                var sPropertyName, sProxyName;
                                
                                // Iterate over the properties
                                for( var i = 0, nProps = oPropertySettings.getNumValues(); i < nProps; i += 1 ){
                                    sPropertyName = oPropertySettings.getKey( i );
                                    MessageBox.information("Searching for "+sPropertyName,"INFO","OK");
                                    oMaterialProperty = oMaterial.findProperty( sPropertyName );
                                    if( oMaterialProperty ){
                                        MessageBox.information("...FOUND MATERIAL PROPERTY","INFO","OK");
                                        sProxyName = String("%1 %2 Proxy").arg( oMaterial.name ).arg( sPropertyName );
                                        sProxyName = oMaterial.name
                                        print ("sProxyName = "+sProxyName);
                                        //oProxyProperty = oNode.findProperty( sProxyName );
                                        oProxyProperty = oNode.findProperty( sPropertyName );
                                        if( oProxyProperty ){
                                            MessageBox.information("...FOUND PROXY PROPERTY","INFO","OK");
                                            if( oMaterialProperty.inherits( "DzNumericProperty" ) ){
                                                oMaterialProperty.linkTo(oProxyProperty);
                                                MessageBox.information("...SUCCESS!...","INFO","OK");
                                            }
                                        }
                                    }
                                }
                            }
                        } else {
                            MessageBox.information("Could not read XML encoded data.","INFO","OK");
                        }
                    }
                }
            }
        }
    }
    MessageBox.information("...FINISHED","INFO","OK");

 

 

 

Edit: Note that if the "Vertical/Horizontal Offset"values on the Parameters tab and/or the Surfaces tab are given non-zero values before running the script, then the "Vertical/Horizontal Offset" values on the Surfaces tab will be set to match those on the Parameters tab after running the script. So those on the Parameters tab are the 'masters'. which makes sense from the DzNumericProperty::linkTo() documentation - you call the method on the slave property, and pass the master property,i.e. 'oMaterialProperty.linkTo(oProxyProperty);'

dsa
dsa
JustPlaying.dsa
3K
Post edited by 3dcheapskate on

Comments

  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 29

    Hmm... interesting.

    Simply adding that script as a post-load item via main menu >Edit > Object > Element Data, and then saving a material preset* seems to work.

    I can create an !Iray Uber Base materials preset that calls this script to reestablish the links.

    And this Iray materials preset works(and correctly reestablishes the links), even when applied to a prop which has DS Default materials (as long as it has the "Vertical/Horizontal Offset"values on the Parameters tab).

    Which was my biggest problem.

    Here's a snippet from the end of the materials preset showing the post-load script (edit: using 'insert code snippet' with style = 'javascript'):

        ...
        "scene" : {
            "materials" : [
                {
                    "url" : "#Default",
                    "groups" : [ "Default" ],
                    "extra" : [
                        {
                            "type" : "studio/material/uber_iray"
                        },
                        {
                            "type" : "item_post_load_file",
                            "name" : "Just Playing",
                            "file" : "/Scripts/JustPlaying.dsa"
                        }
                    ]
                }
            ],
            ...

     

    I'll have to do a bit more testing, once I've had my morning coffee, to be sure that I haven't overlooked something.

    But this does seem to work. And it seems much, much easier (i.e. my type of solution) than using callbacks.

     

    *Edit: However, saving as a Figure/Prop Asset has a problem - see next post

    Post edited by 3dcheapskate on
  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 29

    As mentioned in the edit to the post above, simply adding that script as a post-load item via main menu >Edit > Object > Element Data, and then saving as a Figure/Prop Asset runs into a problem.

    When the new prop is loaded and the post-load script is run, the node for the prop is not selected, so the script fails to reestablish the links.

    I guess that's why the post_load_material_proxy_create.dsa and post_load_material_proxy_link_properties.dsa sample scripts use that DataItem (the 'settings' bit in the blue code snippet in this post on the earlier thread.

    But I'm fairly certain that I got around this problem (i.e. the node that's just been loaded isn't selected) in a different way before. Either forcing it to be automatically selected when it loads, or by picking up the most recently loaded node I think ?

    But how ?

     

    Edit: Found one answer which doesn't really help - search all nodes for a name match. The script actually loaded a Poser prop PP2 with 'App.getImportMgr().readFile()', and I knew that this prop would be the only one with a specific name in the scene,so I did this:

            allNodes =  Scene.getNodeList();
            for( n = 0; n < allNodes.length; n++ ) {
                nodelabel = allNodes[n].getLabel();
                if (nodelabel.left(10) == "UniqueName"){
                ...
                }

    But for this new case I expect to have several props with the same name in the scene, so this wouldn't work.

    Edit2: Ah! Found this old mid-2014 thread - DAZ Script (DS4) - Identifying the node that's just been loaded, which refers back to the Can I automatically run a DSA script when I load a prop from a DUF/DSF file? thread. I managed to get what I wasdoing back then to work using that advice.

    The Prop DUF had this bit to call the post-load script:

        ...
        "scene" : {
            "nodes" : [
                {
                    "id" : "Dha",
                    "url" : "/data/3DCheapskate/SmartPlus/Dha/Dha.dsf#Dha",
                    "name" : "Dha",
                    "label" : "Dha",
                    "geometries" : [
                        ...
                    ],
                    "preview" : {
                        ...
                    },
                    "rotation" : [
                        ...
                    ],
                    "extra" : [
                        {
                            "type" : "item_post_load_file",
                            "name" : "The Smart+ Part",
                            "file" : "/Scripts/3DCheapskate/SmartPlus/Smart+Rod.dsa"
                        }
                    ]
                }
            ],
            ...
        }
        ...

     

    and the script started with this:

        // Get the node that caused this script call, i.e. the prop that's just been loaded ( http://www.daz3d.com/forums/viewthread/41175/ and http://www.daz3d.com/forums/viewthread/41334/ )
        if( typeof( DataItem ) != "undefined" ){
            var oOwner = DataItem.getOwner();
            if (oOwner){
                        
                // Select the prop we've just loaded
                oOwner.select();
                ...

     

    So I've sort of come full circle. Adding the 'DataItem' bit above to the start of my script should get it to work when it's run as a post-load from the prop DUF.

    But if I then run same script as a post-load from a material preset DUF... ? I'll have to go and play as I can't work out whether that should or shouldn't work.

     

    Edit: oOwner=DataItem.getOwner(); returns a scene node DzNode (oOwner.name=sphere) when called from the prop DUF, but a material DzMaterial (oOwner.name=Default) when called from the materialpreset DUF, which makes perfect sense. So the modified script works fine when calledfrom the Prop DUF, but crashes when called from a material preset DUF (oNode.getObject()doesn't work as oNode is a DzMaterial.

    So next idea is to test the result of oOwner=DataItem.getOwner(). If it's a DzNode then select that node, if it's a DzMaterial then pick the currently selected node (as per the script in the OP), and if it's 'undefined' (i.e.the script's been run manually) then also pick the currently selected node.

    Might work...laugh

    Post edited by 3dcheapskate on
  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 29

    It does work ! It's extremely ropey, held-together-with-chewing-gum code at present*, but it does work:

    - It works (and sets up the bidirectional links) when run as a post-load file from a prop with Ds Default material, and from a prop with Iray UberBase** material.

    - It works (and reestablishes the bidirectional links) when run as a post-load file from a DS Default or Iray UberBase material preset, regardless of whether the prop originally/previously had a DSDefault or Iray Uner Base material.

    - If a DS Default or Iray UberBase material preset WITHOUT a post-load file is applied thebidirectional links are lost. But simply running thescript manually reestablishes them

    DSA attached basically so that I don't lose it !

     

    *I do plan to tidy it up - probably replace the chewing gum with neatly cut pieces of sticky tape...

    *One point - when run as a post-load from aprop with Iray Uber Base material the script is called twice, once with the DataItem 'owner' a DzNode, then again with the DataItem 'owner' a DzUberIraymaterial. Edit2: That would be because I called it twice ! Just deleted the spurious second call from the "materials" section of the PropDUF and that's resolved

     

    Edit: One neatly cut piece of sticky tape - of course it's more logical to check for oNode.inherits("DzMaterial")rather than oNode.className()=="DzDefaultMaterial" or oNode.className()=="DzUberIrayMaterial"

     

     

    dsa
    dsa
    JustPlaying 03 (as posted).dsa
    4K
    Post edited by 3dcheapskate on
  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 29

    Right, I'm doing some tidying up.

    If the script is called as a post-load from a materials preset DUF then var oElement = DataItem.getOwner() will return something that inherits from DzMaterial.
    I assume that from this I should be able to find the node for the prop to which that material is applied, yes ?

    The tree for going the other way, i.e. from a prop to its material(s) is this (distilled from the Material Properties sample script):

        ...
        if( oNode ){
            var oObject = oNode.getObject();
            if( oObject ){
                var oShape = oObject.getCurrentShape();
                if( oShape ){
                    var aMaterials = oShape.getAllSelectedMaterials();
                    ...
                    }
                }
            }
        }
        ...

     

    But I'm having trouble finding out how to go the other way, i.e. oMaterial > oShape > oObject > oNode

    Can anybody assist ?

     

    DzElement has getElementParent(), but that returns 'null' from my DzMaterials (i.e. oMaterial.getElementParent() ). I don't see anything else there that might help.
    The two classes from which DzElement inherits (QObject,DzBase) don't seem to have anything to help me

    Edit: Looking through the online Object Index:
    - I can get from DzMaterial to DzShape using DzMaterial::getShapeList() - since it returns an array I'll have to check whether it's a single shape.
    - DzShape isn't in the online documentation, so I'm stuck on getting from DzShape to a DzObject.
    - I can't see any DzObject methods to get to the DzNode

    Post edited by 3dcheapskate on
  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 29

    Nobody ?

    No matter.

    I've more or less finished tidying up the script, and I've modified it for my specific requirement.

     

    // 'ConnectOrReconnectExistingTilingOffsetProxies.dsa'
    // Initial pre-release 0.01
        
    // Define an anonymous function for the main code to limit the scope of variables - as per the current sample scripts
    // http://docs.daz3d.com/doku.php/public/software/dazstudio/4/referenceguide/scripting/api_reference/samples/start
    //(function(){
    
        MessageBox.information( "Running script 'ConnectOrReconnectExistingTilingOffsetProxies.dsa'", "DEBUG", "OK" );
    
        // Flags and function for showing debug information as pop-up message boxes and/or prints to the log file
        var SHOWDEBUG = true;
        var POPUPDEBUG = false;
        var PRINTDEBUG = true;
        function showDebug( sMsg ){
            if (POPUPDEBUG) MessageBox.information( sMsg, "DEBUG", "OK" );
            if (PRINTDEBUG) print( sMsg );
        }
        
        //
        function showError( sMsg ){
            MessageBox.information( sMsg, "Script Error", "OK" );
            print( "***ERROR***"+sMsg );
        }
        
        if (SHOWDEBUG) showDebug("STARTED 'Connect_Reconnect_Tiling_Offset_Proxies.dsa' script");
        
        // Define the list of parameter names on the surfaces tab that we want to link to proxies on the Parameters tab.
        // Note: The proxy parameters must have exactly the same names as those on the Surface tab, but can have a different path. And they must already exist on the node - this script does not create them.
        
        var aPropertyNames = [ "Horizontal Offset", "Vertical Offset"];
        
        // Specify the list of material names on the node which we're going to be looking for these parameters
        var aMaterialNames = [ "Covers-64BookMapping", "Pages-64BookMapping" ]   // The material we're going to work with
    
        // Declare the node variable.
        // This will identify the main node of the prop on which we need to set up the Surface tab to Parameters tab bidirectional link(s)
        // - If the script is run manually then there is no DataItem and we use the currently selected node, provide that a SINGLE node is selected. If 0 or 2+ nodes are selected then we simply inform the user and abort.
        // - If the script is called as a post-load file from a prop DUF then the required node is the 'owner' of the 'DataItem' that's passed to the script.
        // - If the script is called as a post-load file from a materials preset DUF then the 'owner' of the 'DataItem' is a DzMaterial.We do thesame asif it was run manually    
        var oNode;
        
        // Get the 'owner' of the'DataItem' (if any) that's been passed to this script to determine whether we already know the node we want to work with (i.e. the script was called from a prop DUF)
        if( typeof( DataItem ) != "undefined" ){
            var oElement = DataItem.getOwner();
            if (SHOWDEBUG) showDebug("oElement.className()="+oElement.className());
            if (oElement.className()=="DzNode"){
                oNode = oElement;
                if (SHOWDEBUG) showDebug("Owner is a DzNode, so script was called from a Prop DUF.");
            }else if (oElement.inherits("DzMaterial")){
                if (SHOWDEBUG) showDebug("Owner is a DzMaterial, so script was called from a Materials Preset DUF");        
                // If it's amaterial I should be able to get the node by climbing the oMaterial > oShape > oObject > oNode tree, but  I'm stuck on this at present
                //var aShapes = oElement.getShapeList()
                //if (aShapes.length = 1){
                //    oShape = aShapes[0];
                //  // do something to get the DzObject from the DzShape
                //    // do something to get the DzNode from the DzObject
                //}
            }else
                if (SHOWDEBUG) showDebug("Owner is an unexpected class ("+oElement.className()+") so the script will probably crash!");
        }
        
        // If 'oNode' is still not set (i.e. if script wasn't called frop a Prop DUF), but there's a single node selected,then use that
        if (!oNode){
            if (SHOWDEBUG) showDebug("oNode was NOT setfrom DataItem, so try to identify it from the list of selected nodes in the scene");
            var aNodes = Scene.getSelectedNodeList();
            if ( aNodes.length == 1 ){
                oNode = aNodes[0];
            }else{
                MessageBox.information("You must have exactly one scene node selected when you apply the material preset that post-loads this script (or to run this script manually)","Too Many/Few Nodes Selected","OK");
            }
        }
        
        if (oNode){
            if (SHOWDEBUG) showDebug("We've identified the following to be the node we're working with - oNode.name="+oNode.name);
            var oObject = oNode.getObject();
            if( oObject ){
                var oShape = oObject.getCurrentShape();
                if( oShape ){
                    
                    // For each of the material names in our predefined list...
                    for( var i = 0, nMats = aMaterialNames.length; i < nMats; i += 1 ){
                        if (SHOWDEBUG) showDebug("...found shape, now looking for the "+aMaterialNames.length+" materials")
                        var oMaterial = oShape.findMaterial( aMaterialNames[i] );
                        if( oMaterial ){
                            if (SHOWDEBUG) showDebug("...FOUND MATERIAL. Now look for the "+aPropertyNames.length+" properties");
                            
                            
                            // For each of the material parameters for which we wish to establish/restablish a link to a similarly named parameter on the node...
                            for( var j = 0, nProps = aPropertyNames.length; j < nProps; j += 1 ){
                                var oMaterialProperty, oProxyProperty;
                                var sPropertyName, sProxyName;
                                    
                                // ...first find the parameter on the material...
                                sPropertyName = aPropertyNames[j];
                                if (SHOWDEBUG) showDebug("Searching for "+sPropertyName);
                                oMaterialProperty = oMaterial.findProperty( sPropertyName );
                                if( oMaterialProperty ){
                                    if (SHOWDEBUG) showDebug("...FOUND MATERIAL PROPERTY");
                                
                                    // ...and then find the corresponding parameter on the node...
                                    oProxyProperty = oNode.findProperty( sPropertyName );
                                    if( oProxyProperty ){
                                        if (SHOWDEBUG) showDebug("...FOUND PROXY PROPERTY");
                                        if( oMaterialProperty.inherits( "DzNumericProperty" ) ){
                                            oMaterialProperty.linkTo(oProxyProperty);
                                            if (SHOWDEBUG) showDebug("...MATERIAL AND PROXY PROPERTIES LINKED ");
                                        }
                                    }
                                }
                                    
                            }
                        } else showError("Could not find material '"+aMaterialNames[i]+"' in '"+oNode.name+"'(node) > '"+oObject.name+"'(object) > '"+oShape.name+"'(shape)");
                    }
                } else showError("Could not identify the current DzShape from '"+oNode.name+"'(node) > '"+oObject.name+"'(object)");
            } else showError("Could not identify the DzObject from node '"+oNode.name+"'");
        } else showError("Could not identify the node to work with.");
        
        MessageBox.information( "Done without crashing !", "DEBUG", "OK" );
    
    // Finalize the function and invoke
    //})();

    Slightly less ropey than the earlier version.

    The script is added to the prop as a post-load item (main menu > Edit > Object > Element Data) before saving as a Figure/Prop Asset DUF.

    The script is manually added as a post-load item to the Material Preset DUFs (both 3Delight DS Default based, and Iray Uber Base based) in a text editor, as noted in the second post on this thread.

    The prop loads fine with the proxies connected. If I apply a material preset (3Delight/Iray),the proxies are correctly reconnected.

    So everything works beautifully.

    One minor problem. If I save a prop after I've applied a material preset, the new prop has two identical post-load items - one is the prop post-load, and the other is the material post-load.

    Post edited by 3dcheapskate on
  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 29
    ...

    One minor problem. If I save a prop after I've applied a material preset, the new prop has two identical post-load items - one is the prop post-load, and the other is the material post-load.

    Well, that actually turns out to be the solution* !

    With my script as it stands, the second time it is called from the Prop DUF (from the scene > materials bit of the file) it simply alerts the user that there is no selected node.

    The answer appears to be to make the first post-load call from the Prop DUF (from the scene > nodes bit) to a different script which simply selects the node that's just been loaded, i.e.

     

        // Get the node that caused this script call, i.e. the prop that's just been loaded ( http://www.daz3d.com/forums/viewthread/41175/ and http://www.daz3d.com/forums/viewthread/41334/ )
        if( typeof( DataItem ) != "undefined" ){
            var oOwner = DataItem.getOwner();
            if (oOwner){                    
                // Select the prop we've just loaded
                oOwner.select();
                if (SHOWDEBUG) showDebug( "The node we've just loaded ("+oOwner.name+") is now selected");
            } else showError("oOwner not valid");
        } else showError("Undefined DataItem");


    Then when the original script is called from the scene > materials bit of the file, the correct node is already selected, and it reconnects theproxies. (The bit of script above should probably be modified to make sure that only the node we've just loaded is selected.)

    And now, if I save a materials preset, the post-load from the scene > materials bit is automatically saved, so the proxies will be reconnected after applying a material preset.

     

    *Not thoroughly tested yet,but it's looking promising...

     

    P.S. I tried to use the 'Computer Code' style from the 'Styles' dropdownof this forum's post editor, but it does this:

    &nbsp;&nbsp;&nbsp; // Get the node that caused this script call, i.e. the prop that&#39;s just been loaded ( http://www.daz3d.com/forums/viewthread/41175/ and http://www.daz3d.com/forums/viewthread/41334/ )<br />&nbsp;&nbsp; &nbsp;if( typeof( DataItem ) != &quot;undefined&quot; ){<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;var oOwner = DataItem.getOwner();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (oOwner){&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// Select the prop we&#39;ve just loaded<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;oOwner.select();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (SHOWDEBUG) showDebug( &quot;The node we&#39;ve just loaded (&quot;+oOwner.name+&quot;) is now selected&quot;);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;} else showError(&quot;oOwner not valid&quot;);<br />&nbsp;&nbsp; &nbsp;} else showError(&quot;Undefined DataItem&quot;);

    Odd (and just in case other people don't see what I see, I've added a screenshot of what I see after I posted that). So I started using both 'Typewriter' and 'Special Container'. And then Syrus_Dante reminded me of the 'insert code snippet'.

    kjhkh.jpg
    788 x 365 - 77K
    Post edited by 3dcheapskate on
  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 29

    But regardless of that, it would be nice to know what I need here, as mentioned earlier:

                ...
                // If oElement is a material I should be able to get the node by climbing the oMaterial > oShape > oObject > oNode tree, but  I'm stuck on this at present
                var aShapes = oElement.getShapeList()
                if (aShapes.length = 1){
                    oShape = aShapes[0];
                    // do something to get the DzObject from the DzShape, and the DzNode fromthe DzObject
                    oObject = oShape.??? // ...since DzShape isn't documented I have to guess - oShape.getObject() perhaps ?
                    oNode = oObject.??? // ...DzObject (and the classes it inherits from) don't seem to have anything to get the node
                }
                ...

     

    Edit: Just found the bit in the Select by Tag sample summary that says "... an example demonstrating how to select materials that have a particular tag ... and how to use element parent information to get the node(s) that a material or shape is associated with."- so that should do the trick.
    Here are the 3 functions that are required -
    getNodesFromMaterial(), getNodeFromElement(), and inheritsType():

       /*********************************************************************/
       // Boolean : A function for testing whether or not a QObject instance
       // inherits one of a list of types
       function inheritsType( oObject, aTypeNames )
       {
          // If the object does not define the 'inherits' function
          if( !oObject || typeof( oObject.inherits ) != "function" ){
             // We are done... it is not a QObject
             return false;
          }
     
          // Iterate over the list of type names
          for( var i = 0, nTypes = aTypeNames.length; i < nTypes; i += 1 ){
             // If the object does not inherit the 'current' type
             if( !oObject.inherits( aTypeNames[i] ) ){
                // Next!!
                continue;
             }
     
             // Return the result
             return true;
          }
     
          // Return the result
          return false;
       };
     
       /*********************************************************************/
       // DzNode : A function for getting a node from an element child
       function getNodeFromElement( oElement )
       {
          // Get the element parent of the element
          var oParent = oElement.getElementParent();
          // While there are more element parents
          while( oParent ){
             // If the parent is a node
             if( inheritsType( oParent, ["DzNode"] ) ){
                // We are done...
                return oParent;
             }
     
             // Get the element parent of the parent
             oParent = oParent.getElementParent();
          }
     
          return undefined;
       };
     
       /*********************************************************************/
       // Array<DzNode> : A function for getting nodes from a material
       function getNodesFromMaterial( oMaterial )
       {
          // Initialize the result
          var aNodes = [];
     
          // Get the shapes this material is on
          var aShapes = oMaterial.getShapeList();
          // Iterate over the shapes
          for( var i = 0; i < aShapes.length; i += 1 ){
             // Get the 'current' shape
             oShape = aShapes[ i ];
             // Get the node from the shape
             oNode = getNodeFromElement( oShape );
             // If we do not have a node
             if( !oNode ){
                // Next!!
                continue;
             }
     
             // Append the node
             aNodes.push( oNode );
          }
     
          // Return the result
          return aNodes;
       };

     

    Post edited by 3dcheapskate on
  • Syrus_DanteSyrus_Dante Posts: 983
    edited July 29

    Hi 3dcheapskate,

    all in all a very interesting project using the example script and rewrite it to make use of those proxy-load features regarding animation controls for material and shader properties.

    I hope you get the things figured out I will have a closer look at your script if I find the time.

    As discussed here: Animation for surface tab timeline not working I was thinking of trying that too one day but currently I am working on another script: PowerPose Templates generator script

    By quickly looking at the posted scripts, thus far I can only tell you that it would propably better readable if you use the "Insert Code Snippet" script container in the edit comment bar right next to "Image".

    You copy-paste the code in there and choose a code highlighting style, I would pick Java or JavaScript, this would make the script much better readable directly on the page.

    The Code Snippet container box has the disadvantage that if your code includes tabs for indents those get unbelievable 8 spaces pushig everything too far to the right. As a workaround you could convert tabs to spaces in the DS Script IDE pane right-click menu.

    A hint to the forum page admins: by default tabs are 3 or 4 spaces long no one ever wants to use 8 spaces for a tab and please add a button to collapse those Code Snippet container boxes.

    Regarding guessing and undocumented methods, as I discovered it is hard enougth to understand the documented scripting stuff and not even that is guaranteed to work. If you start guessing there must be other methods you should somehow be able to print out all methods and properties of a given object. I can vaguely remember Richard was posting something about that, but I can't remeber if it was about getting undocumented methods and/or properties of Dz type objects printed out.

    I'm pretty shure I have bookmarked that thread with the forum but then if you have over 1000 bookmarks and I lost the overview, only getting notifications if someone posted in those threads again.

    @Richard if you read this please could you give us a hint again how to get undocumented methods and/or properties of Dz type objects printed out. I know it is not good practice to use undocumented stuff because this may be a subject to change and may work or not work like intended now or in future updates. But if you get something to work with the undocumented things, that where not possible before or will not be possible like this in later versions you can always check for the DS version first.

    Post edited by Syrus_Dante on
  • 3dcheapskate3dcheapskate Posts: 2,070
    edited July 31

    Thanks - I think I'm almost there now.

    I do remember that "Insert Code Snippet"... obvious when it's pointed out. blush (Edit: Ha! Forum WYSIWYG Issues from 2016 - not my title, I'd have used 'Probems' wink)
    And now that you've mentioned it, I also remember somebody (Richard? Rob?) posting a simple way to get an object to tell you all its methods/properties. I vaguely recall asking the question before too, so I'll go and see if I can find it. (Edit2: Jag11 posted a way to do it here, way back in 2015)

    From that Animation for surface tab timeline not working link, I see that MCasual has a script covering the basics of what I want to do (MatAnim for DS 1, 2, 3, 4)* - as is often the case !
    Thinks: I really do have to put mCasual's DAZ Scripts alongside  DAZ Script Object Index in my bookmarks !

    Edit3: I now need to add these identical sliders and dependencies to several props.Doing it manually is tedious and error-prone.So I've decided to write a short script to do it for me. The process of writing a script is also tedious and error-prone for me, but once it works well enough to run for one prop it's good enough for me. I'm nearly there - I just need to work out how to do the last bit, Creating a simple DzERCLink between two new parameters

    Edit4: All problems now appear to be resolved, so I just need to convert my 14 Poser props to DS-native props that use all the stuff from this thread. These are just more notes to myself:
    - Rename each PP2 (DS uses the PP2 filename as the node name - it took me a while to remember that!) E.g. 'Row08(2Mat).pp2' becomes 'Books (Row Of 8) Map64.pp2'
    - In the PP2s change both internal/external name of the prop to be the same as the filename
    - In the PP2s change all the 'ROW08-SPINE-WIDTHS' type morph names to something less computer-code-y and without the prop-specific prefix, e.g. 'Adjust Spine Widths' (regular expression ROW..- works nicely)
    - In the PP2s change 'groupNode Morph' to 'groupNode Book Adjustments''
    - Import the PP2 into DS4.8 and select it
    - Run 'AddParameters.dsa' to create the 4 new parametersand the 2 ERC links between them. Check the ERC is working, but be sure to set values back to 0 afterwards !
    - Apply the 3Delight Pulp1 material preset (which already has the post-load 'ConnectOrReconnectExistingTilingOffsetProxies.dsa'
    - Check that the 2 main controls change the texture offsets correctly. Be sure to set values back to 0 afterwards !
    - Hide the two intermediate/proxy values
    - Edit > Object > Element Data and add the 'SelectThisNode.dsa' post-load
    - Save as a Prop/Figure Asset
    - Close and restart DS4.8,load the new prop, and test it. Apply 3Delight presets and Iray presets to check that everything works.

     

    *Actually I'm not sure... I've had a look and can't make head or tail of it. Too many functions for my poor brain to handle. Give me monolithic code any day - start at the top, carry on till you reach the bottom !

    Post edited by 3dcheapskate on
Sign In or Register to comment.