Learning to script DAZ Studio...

CypherFOXCypherFOX Posts: 3,401

Greetings,
I'm trying to learn to script DAZ Studio, and there seemed to be no function references for various objects. Maybe I missed them, but I really did try to find them in the documentation section. So I decided to try and find what functions I could, and reverse engineer them as much as possible. Historically I've found that functions are usually very descriptive, even without docs, and with a little guesswork and trial and error, you can make sense of how to use them.

So I'm creating this thread to track my explorations, not terribly dissimilar to a art forum render thread. Hopefully I will update it as I go with interesting stuff I learn/find.

And thus I present my first useful piece of code in DAZ Script. (It's actually pretty generic JavaScript, but it's a start. Also I'm over semi-colon-ing, but that seems to be the style.)

Dump all methods and members of an object; especially useful on the Scene object.

function dumpBehavior(obj) {
  var properties = new RegExp("([a-zA-Z0-9]+(\\(.*?\\))?),", "g");
  print(Object.getOwnPropertyNames(obj).sort().toString().replace(properties, "$1\n"));
}

dumpBehavior(Scene);

This gave me:

DefaultMethod
DzIncludeAllFlag
DzIncludeCamerasFlag
DzIncludeLightsFlag
DzIncludeNonShadowersFlag
DzIncludeNonVisibleFlag
DzObjectsOnly
MergeFile
OpenNew
aboutToRemoveNode(DzNode*)
aboutToRender(DzRenderer*)
addDataItem(DzSceneData*)
addNode(DzNode*)
addWSModifier(DzWSModifier*)
addWSModifier(DzWSModifier*,int)
animRangeChanged(DzTimeRange)
assetModified()
assetWasSaved()
beginTimeEdit()
cameraAdded(DzCamera*)
cameraListChanged()
cameraRemoved(DzCamera*)
cameraSelectionListChanged()
className()
clear()
clearDebugPoints()
currentTimeChanged(DzTime,DzTime)
deleteLater()
destroyed()
destroyed(QObject*)
drawnDataChanged()
findCamera(QString)
findCameraByLabel(QString)
findDataItem(QString)
findLight(QString)
findLightByLabel(QString)
findNode(QString)
findNodeByLabel(QString)
findNodeIndex(const DzNode*)
findSkeleton(QString)
findSkeletonByLabel(QString)
findSkeletonIndex(const DzSkeleton*)
finishTimeEdit()
getAnimRange()
getAssetLoadPath()
getAssetLoadPath(bool*)
getAudio()
getAudioStartFrame()
getBackdrop()
getBoundingBox()
getBoundingBox(int)
getCamera(int)
getCameraList()
getDataItem(int)
getFilename()
getFilename(bool*)
getFrame()
getHighlightNode()
getLight(int)
getLightList()
getName()
getNode(int)
getNodeList()
getNumCameras()
getNumDataItems()
getNumLights()
getNumNodes()
getNumSelectedCameras()
getNumSelectedLights()
getNumSelectedNodes()
getNumSelectedSkeletons()
getNumSelectedTimeRanges()
getNumSkeletons()
getNumStorablesInScene()
getNumWSModifiers()
getPlayRange()
getPreviewLights()
getPrimarySelection()
getSelectedCamera(int)
getSelectedCameraList()
getSelectedLight(int)
getSelectedLightList()
getSelectedNode(int)
getSelectedNodeList()
getSelectedSkeleton(int)
getSelectedSkeletonList()
getSkeleton(int)
getSkeletonList()
getSortedLightList()
getTime()
getTimeStep()
getUniqueTopLevelLabel(QString)
getUniqueTopLevelLabel(QString,DzNode*)
getWSModifier(int)
getWSModifierList()
highlightNodeChanged(DzNode*)
inherits(QString)
invalidate()
invalidateLightSorting()
isClearing()
isDAZLoading()
isLoading()
isLoopingEnabled()
isPlaying()
iskindof(QString)
lightAdded(DzLight*)
lightListChanged()
lightRemoved(DzLight*)
lightSelectionListChanged()
loadScene(QString,DzOpenMethod)
loopPlayback(bool)
loopPlaybackChanged(bool)
makePersistent()
markChanged()
materialListChanged()
materialSelectionChanged()
name
nameChanged(QString)
needsSave()
nodeAdded(DzNode*)
nodeListChanged()
nodeRemoved(DzNode*)
nodeSelectionListChanged()
objectName
pause()
play()
play(bool)
playRangeChanged(DzTimeRange)
playbackFinished()
playbackStarted()
primarySelectionChanged(DzNode*)
removeAllCameras()
removeAllLights()
removeDataItem(DzSceneData*)
removeNode(DzNode*)
removeSelected()
removeWSModifier(DzWSModifier*)
renderFinished(DzRenderer*)
saveScene()
saveScene(QString)
saveThumbnail(QString)
sceneClearStarting()
sceneCleared()
sceneFilenameChanged(QString)
sceneLoadStarting()
sceneLoaded()
sceneSaveStarting(QString)
sceneSaved(QString)
sceneTopologyChanged()
selectAllNodes(bool)
selectAllSkeletons(bool)
selectAllTime(bool)
setAnimRange(DzTimeRange)
setAssetLoadPath(QString)
setAudio(DzAudioClip*)
setAudio(DzAudioClip*,int)
setBackdrop(DzBackdrop*)
setDebugPoints(int,QColor,const DzPnt3*,int)
setDebugPoints(int,QColor,const DzPnt3*,int,DzMatrix3)
setFrame(int)
setHighlightNode(DzNode*)
setPlayRange(DzTimeRange)
setPreviewLights(bool)
setPrimarySelection(DzNode*)
setTime(DzTime)
setTimeStep(DzTime)
skeletonAdded(DzSkeleton*)
skeletonListChanged()
skeletonRemoved(DzSkeleton*)
skeletonSelectionListChanged()
stepTime()
stepTime(int)
stepTime(int,bool)
stripLabelNumber(QString)
timeChanged(DzTime)
timeChanging(DzTime)
timeSelectionChanged()
timeStepChanged(DzTime)
update()
wsModifierAdded(DzWSModifier*)
wsModifierRemoved(DzWSModifier*)
wsModifierStackChanged()
...which gives me a good starting point to investigate.

Is there a top-level object 'above' scene, like something which owns the currently selected camera, etc...?

-- Morgan

Comments

  • CypherFOXCypherFOX Posts: 3,401
    edited November 2015

    Greetings,

    Cypherfox said:

    Is there a top-level object 'above' scene, like something which owns the currently selected camera, etc...?

     

    Yes.

    You can get to it via:

    var active = App.getInterface().getViewportMgr().getActiveViewport();var viewport = active.get3DViewport();

     

    Some example code, to cycle through available user cameras:

    var active = App.getInterface().getViewportMgr().getActiveViewport();var viewport = active.get3DViewport();var list = Scene.getCameraList();if(list.length != 0) {  var nameList = [];  for(i=0; i = list[ i ].getName();  }  var current = viewport.getCamera();  var idx = nameList.indexOf(current.getName());  //  Presumes names are unique.  var switchTo = Scene.getCamera((idx+1) % list.length);  viewport.setCamera(switchTo);}

     

    That's all for tonight, I think. Although I did discover how to 'hear' when a camera change is made, so let's list that here also:

    var active = App.getInterface().getViewportMgr().getActiveViewport();var viewport = active.get3DViewport();connect(viewport, 'activeCameraChanged(DzCamera*)',  function(cam) {   print("Foo...");  });

     

    Now that's really all.

    -- Morgan

    Post edited by Richard Haseltine on
  • Richard HaseltineRichard Haseltine Posts: 100,939
    edited December 1969

    The DS3 docs are still available from the script reference section in the Documentation centre, since the DS3 docs aren't. They cover a lot, though there have been significant changes to accommodate TriAx figures - I would strongly urge using object.inherits( classname ) rather than object.className() == string to avoid many issues.

  • CypherFOXCypherFOX Posts: 3,401
    edited December 1969

    Greetings,

    The DS3 docs are still available from the script reference section in the Documentation centre, since the DS3 docs aren't.
    Thanks! That was helpful... I now know how to set the aspect ratio programmatically. Can you tell me how to get a script in the Script IDE to remain...running?

    Specifically, I have this code:

    var active = App.getInterface().getViewportMgr().getActiveViewport();
    var viewport = active.get3DViewport();
    
    connect(viewport, 'activeCameraChanged(DzCamera*)',
      function(cam) {
        print("Swapping to " + cam.getName() + "...");
        var renderMgr = App.getRenderMgr();
        var opts = renderMgr.getRenderOptions();
        if(cam.getName() == 'Camera 3') {
          opts.setAspectRatio(16, 9);
        } else if(cam.getName() == 'Camera 4') {
          opts.setAspectRatio(4, 3);
        }
      }
    );
    
    var myCam = Scene.getCamera(2);
    viewport.setCamera(myCam);
    print("Done.");
    with the eventual intent of extracting the aspect ratio from the camera name, or some other camera property. However, I can't get it to remain running. Is there a trick to getting a signal/slot installed and retained from the Script IDE, or is it something where I just have to put it in a startup script or something and restart every time I change it?

    That script works, but only during the time it's running, as soon as the Script IDE stops running it, it doesn't trap the camera change anymore.

    What am I missing?

    -- Morgan

  • Richard HaseltineRichard Haseltine Posts: 100,939
    edited December 1969

    It should be possible to have a script triggered by an event, but I know it was problematic at one point (there's probably a thread on it in the old forum's Developer Discussion). It's not something I've ever tried, so I can't offer any advice.

  • CypherFOXCypherFOX Posts: 3,401
    edited November 2013

    Greetings,
    Thanks for the approximate pointer! I found this article by rbtwhiz by using the keywords you mentioned and judicious googling... The entire script now looks like this:

    var active = App.getInterface().getViewportMgr().getActiveViewport();
    var viewport = active.get3DViewport();
    
    var ratioCamScript = 'function gcd(x, y) {while (y != 0) {var z = x % y;x = y;y = z;}return x;}\n' +
        'var cam = CallBack.getArg(0);\n' +
        'var renderMgr = App.getRenderMgr();\n' +
        'var opts = renderMgr.getRenderOptions();\n' +
        'var common = gcd(opts.imageSize.height, opts.imageSize.width);\n' +
        'var r = new RegExp("\\\\((\\\\d+)[,x]\\\\s*(\\\\d+)\\\\)");\n' +
        'var matches = cam.getLabel().match(r)\n' +
        'if(matches != null) {\n' +
        '  var w = parseInt(matches[1]); var h = parseInt(matches[2]);\n' +
        '  opts.setAspectRatio(w, h);\n' +
        '  opts.imageSize = new Size(w * common, h * common);\n' +
        '}\n';
    var cbm = App.getCallBackMgr();
    cbm.deleteCallBack('com.3dwishlist.Set Aspect');
    var cb = cbm.createCallBack("com.3dwishlist.Set Aspect", ratioCamScript, true);
    cb.setConnection(viewport, 'activeCameraChanged(DzCamera*)');

    If you include '(16x9)', '(16,9)', '(4x3)', '(8x11)', etc., in the name of your camera, it will set the aspect ratio to that when you switch to that camera. (So, for example, I have 'Whole Scene (16x9)' as a camera and 'Closeup (3x4)' as another...) It supports both (##x##) and (##,##) formats.

    Thanks very much for the help!

    -- Morgan

    Post edited by CypherFOX on
  • Richard HaseltineRichard Haseltine Posts: 100,939
    edited December 1969

    Now I need to bookmark this thread so I can find it when I want that info :)

  • CypherFOXCypherFOX Posts: 3,401
    edited December 1969

    Greetings,
    I made a small tweak, it wasn't properly propagating the aspect ratio to the pixels themselves, so I fixed that. It operates on the theory that the GCD between the pixel sizes is the old multiplier times the ratios, so it preserves that multiplier to whatever aspect ratio you set. This avoids unchecked resolution inflation as you change cameras.

    So if you've started with 4x3 and 1024x68, you have a 256 multiplier. This means that if you switch to 16x9 it will go to 4096x2304, but if you switch back to 4x3 it'll be 1024x768 again. I couldn't think of a better algorithm to preserve your expected size, offhand. I could, I suppose, preserve the larger dimension, but then it's possible to change from 4x3 to 3x4 over and over and get resolution inflation each cycle. :)

    The best answer would be to preserve the resolution somehow associated with the previous camera... No idea how to do that yet. :)

    -- Morgan

  • rbtwhizrbtwhiz Posts: 2,250
    edited December 1969

    You can create numeric properties on the camera... Then use the value changed signal from the properties to trigger a callback that sets the other properties and triggers updates to render settings.

    -Rob

  • julian_2378311julian_2378311 Posts: 2
    edited December 1969

    thank you morgan, richard & rob for all this information.

    regarding using the DS3 documentation, is this the correct link?

    http://docs.daz3d.com/lib/exe/fetch.php/public/software/dazstudio/3/ds3_daz_script_development_kit_3.0.1.144_docs.zip

    if so, then i am on the right track, but it would help me if someone could tell whether a couple of things are possible or impossible:

    1) i am trying to automate certain actions and need to find the function references in particular for 'Restore Figure Shape' - is this function exposed in the script API? in the list that i get from running morgan's object function list code (for which many thanks), i don't see anything connected with 'Restore'. i would be very grateful to know what the function name is. if it is not available, is that avenue closed?

    2) i would like to be able to assign keyboard shortcuts to items not listed in Window > Workspace > Customize - again, 'Restore Figure Shape' would be one of them - sometimes i just need to do the action a couple of times, and don't necessarily want to run a full script to automate the task.

    3) ultimately i am trying to automate the process of stepping forward a keyframe, applying Restore Figure Shape, and repeating this till the end of the clip.

    thanks,
    julian
    ps. i am (re-)learning javascript at the same time as learning Daz Script, so more detailed explanation is highly appreciated.

  • julian_2378311julian_2378311 Posts: 2
    edited December 1969

    update: it looks like my link was correct (to the sdk.zip), and using what i found here and that document i have created two working scripts that seem to do the job. thus, if anyone faces the following problem, my solution may be helpful:

    i bought the Daz Millennium Cat (DMC), then the Cat Animation Pack (CAP) from Renderosity. the animation pack is quite good, but it is built for Poser, and you just keep MC the same shape, then CAP will work perfectly without any adjustment. if however, you want to change the shape of the cat, as we did (and make the cat very fat), then when you apply CAP to your differently shaped cat, it will revert to the original shape of MC, which is not what i wanted.

    in order to get CAP to work with a morphed DMC, i found that the following worked:

    create the following scripts

    'memorizeFigure.dsa' script: [you can name this what you like]
    var oMgr = MainWindow.getActionMgr();
    var memorizeFigureAction = oMgr.findAction("DzMemorizeFigureAction");

    if( memorizeFigureAction ){ memorizeFigureAction.trigger(); }

    'applyMorph.dsa' script: [you can also name this what you like]
    var oMgr = MainWindow.getActionMgr();
    var nextKeyAction = oMgr.findAction("DzSkipToNextKeyAction");
    var restoreAction = oMgr.findAction("DzRestoreSelectedItemsAction");

    /* set the i limit to be larger than your keyframes - i really ought to get the number of keyframes and use that as a limit, but haven't done this yet */
    for ( var i=0; i < 200; i++ ) {
    restoreAction.trigger();
    nextKeyAction.trigger();
    }

    instructions:
    1) open Daz IDE
    2) i suggest docking the IDE in the left-hand pane where you can always see it and it will appear as a sensible size
    3) load the two scripts, memorizeFigure.dsa & applyMorph.dsa into the IDE
    4) load a DMC with any body changes you like
    5) run memorizeFigure.dsa script - this memorizes your different cat shape
    6) double-click poser animation morph to apply selected morph to 'different' cat show - the cat now reverts to the original DMC shape
    7) check keyframes don't have a huge gap of 25 frames - sometimes they do, sometimes they don’t - no idea why at present
    8) run applyMorph.dsa script
    9) press play to run 'different-shaped' cat animation

    i hope this helps someone - if you have a lot of these 'morph-animations' to do it could save you many tedious hours. i hope so, because as a newbie it took me some long toil to put it together, simple though it is!

Sign In or Register to comment.