Dynamic sets creation

71 views
Skip to first unread message

Paolo DE LUCIA

unread,
Sep 12, 2024, 11:16:18 AMSep 12
to gaffer-dev
Hello gafferers,
I'm wondering if it's possible to generate several sets dynamically from a unique "set" node, and vary their path filter accordingly. I can create the sets (separated with spaces), but can't find a way to link them to a different geo assignment.

More precisely, I'm trying to feed the "set" node with a json file with key="set name" and value="object list"... without success.
I'd like to avoid the manual creation of sets, and although it's fairly easy to create a button that will generate the values in a spreadsheet, I'm curious to see if it's possible through direct links.

Besides, I wouldn't be against a little example on you expect the "set contect variable" to work.
Thanks for your time.

eric...@gmail.com

unread,
Sep 12, 2024, 5:27:19 PMSep 12
to gaffer-dev
You're on the right track with the `Set Context Variable`. It's meant to do pretty much exactly what you want to do. When the `Set` node is evaluated, it will loop through all the set names you have in the `Name` plug, separated by spaces. For each one, it sets the value of the context variable named by `setVariable` to the set being computed. Then the path filter is computed with that context variable included. So you could plug a spreadsheet into the path filter, put your set names as the row values and the scene paths you want to be included in that set as the `paths` value.

Here's a quick demo of that. Note the value of the spreadsheet's `selector` matches the name in the `Set` node's `setVariable` plug.

```
import Gaffer
import GafferScene
import IECore
import imath

Gaffer.Metadata.registerValue( parent, "serialiser:milestoneVersion", 1, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:majorVersion", 4, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:minorVersion", 11, persistent=False )
Gaffer.Metadata.registerValue( parent, "serialiser:patchVersion", 0, persistent=False )

__children = {}

__children["SceneReader"] = GafferScene.SceneReader( "SceneReader" )
parent.addChild( __children["SceneReader"] )
__children["SceneReader"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Set"] = GafferScene.Set( "Set" )
parent.addChild( __children["Set"] )
__children["Set"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["PathFilter"] = GafferScene.PathFilter( "PathFilter" )
parent.addChild( __children["PathFilter"] )
__children["PathFilter"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["Spreadsheet"] = Gaffer.Spreadsheet( "Spreadsheet" )
parent.addChild( __children["Spreadsheet"] )
__children["Spreadsheet"]["rows"].addColumn( Gaffer.StringVectorDataPlug( "paths", defaultValue = IECore.StringVectorData( [  ] ), ) )
__children["Spreadsheet"]["rows"].addRows( 4 )
__children["Spreadsheet"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) )
__children["SceneReader"]["fileName"].setValue( '${GAFFER_ROOT}/resources/gafferBot/caches/gafferBot.scc' )
__children["SceneReader"]["__uiPosition"].setValue( imath.V2f( -9.25, 7.0999999 ) )
__children["Set"]["in"].setInput( __children["SceneReader"]["out"] )
__children["Set"]["filter"].setInput( __children["PathFilter"]["out"] )
__children["Set"]["name"].setValue( 'head body legs arms' )
__children["Set"]["setVariable"].setValue( 'setName' )
__children["Set"]["__uiPosition"].setValue( imath.V2f( -9.25, -7.76406336 ) )
__children["PathFilter"]["paths"].setInput( __children["Spreadsheet"]["out"]["paths"] )
__children["PathFilter"]["__uiPosition"].setValue( imath.V2f( 10.5499973, -2.5999999 ) )
__children["Spreadsheet"]["selector"].setValue( '${setName}' )
__children["Spreadsheet"]["rows"][1]["name"].setValue( 'head' )
__children["Spreadsheet"]["rows"][1]["cells"]["paths"]["value"].setValue( IECore.StringVectorData( [ '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso016_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_headShaftPin001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/L_ear001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_mouthGrill001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_head001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/R_ear001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_headShaft001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_mouthLiner001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_headShaftSpacer001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_head002_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_browNose001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_headShaftBase001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_headCap001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_mouthTubeBacking001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/C_head_CPT/C_mouthTube001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/L_eye_GRP/L_eye_CPT/L_eyeBacking001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/L_eye_GRP/L_eye_CPT/L_eyeBulb001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/L_eye_GRP/L_eye_CPT/L_eyeLens001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/R_eye_GRP/R_eye_CPT/R_eyeBulb001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/R_eye_GRP/R_eye_CPT/R_eyeBacking001_REN', '/GAFFERBOT/C_torso_GRP/C_head_GRP/R_eye_GRP/R_eye_CPT/R_eyeLens001_REN' ] ) )
__children["Spreadsheet"]["rows"][2]["name"].setValue( 'body' )
__children["Spreadsheet"]["rows"][2]["cells"]["paths"]["value"].setValue( IECore.StringVectorData( [ '/GAFFERBOT/C_torso_GRP/C_key_GRP/C_key_CPT/C_key001_REN', '/GAFFERBOT/C_torso_GRP/C_key_GRP/C_key_CPT/C_key002_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso011_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso008_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso015_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso004_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso007_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso002_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso009_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso006_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso005_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso013_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso012_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso014_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso016_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso003_REN', '/GAFFERBOT/C_torso_GRP/C_torso_CPT/C_torso010_REN' ] ) )
__children["Spreadsheet"]["rows"][3]["name"].setValue( 'legs' )
__children["Spreadsheet"]["rows"][3]["cells"]["paths"]["value"].setValue( IECore.StringVectorData( [ '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_foot_GRP/R_foot_CPT/R_foot002_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_foot_GRP/R_foot_CPT/R_foot001_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_foot_GRP/R_foot_CPT/R_foot003_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_legLower_CPT/R_legLower001_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_legLower_CPT/R_legLower005_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_legLower_CPT/R_legLower002_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_legLower_CPT/R_legLower003_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legLower_GRP/R_legLower_CPT/R_legLower004_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legUpper_CPT/R_legUpper004_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legUpper_CPT/R_legUpper003_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legUpper_CPT/R_legUpper002_REN', '/GAFFERBOT/C_torso_GRP/R_legUpper_GRP/R_legUpper_CPT/R_legUpper001_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legUpper_CPT/L_legUpper001_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legUpper_CPT/L_legUpper002_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legUpper_CPT/L_legUpper004_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legUpper_CPT/L_legUpper003_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_legLower_CPT/L_legLower001_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_legLower_CPT/L_legLower002_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_legLower_CPT/L_legLower003_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_legLower_CPT/L_legLower005_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_legLower_CPT/L_legLower004_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_foot_GRP/L_foot_CPT/L_foot002_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_foot_GRP/L_foot_CPT/L_foot003_REN', '/GAFFERBOT/C_torso_GRP/L_legUpper_GRP/L_legLower_GRP/L_foot_GRP/L_foot_CPT/L_foot001_REN' ] ) )
__children["Spreadsheet"]["rows"][4]["name"].setValue( 'arms' )
__children["Spreadsheet"]["rows"][4]["cells"]["paths"]["value"].setValue( IECore.StringVectorData( [ '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_clawTop_GRP/R_clawTop_CPT/R_clawTop001_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_armLower_CPT/R_armLower007_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_armLower_CPT/R_armLower001_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_armLower_CPT/R_armLower002_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_armLower_CPT/R_armLower005_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_armLower_CPT/R_armLower004_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_armLower_CPT/R_armLower006_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_armLower_CPT/R_armLower003_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armLower_GRP/R_clawBottom_GRP/R_clawBottom_CPT/R_clawBottom001_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armUpper_CPT/R_armUpper004_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armUpper_CPT/R_armUpper001_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armUpper_CPT/R_armUpper005_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armUpper_CPT/R_armUpper003_REN', '/GAFFERBOT/C_torso_GRP/R_armUpper_GRP/R_armUpper_CPT/R_armUpper002_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_armLower_CPT/L_armLower001_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_armLower_CPT/L_armLower005_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_armLower_CPT/L_armLower004_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_armLower_CPT/L_armLower006_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_armLower_CPT/L_armLower003_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_armLower_CPT/L_armLower007_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_armLower_CPT/L_armLower002_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_clawTop_GRP/L_clawTop_CPT/L_clawTop001_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armLower_GRP/L_clawBottom_GRP/L_clawBottom_CPT/L_clawBottom001_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armUpper_CPT/L_armUpper003_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armUpper_CPT/L_armUpper001_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armUpper_CPT/L_armUpper005_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armUpper_CPT/L_armUpper004_REN', '/GAFFERBOT/C_torso_GRP/L_armUpper_GRP/L_armUpper_CPT/L_armUpper002_REN' ] ) )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'ui:scene:acceptsSetName:promotable', False )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'ui:scene:acceptsSetNames:promotable', False )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'ui:scene:acceptsSetExpression:promotable', False )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'renameable:promotable', False )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'deletable:promotable', False )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'description', "The list of paths to the locations to be matched by the filter.\nA path is formed by a sequence of names separated by `/`, and\nspecifies the hierarchical position of a location within the scene.\nPaths may use Gaffer's standard wildcard characters to match\nmultiple locations.\n\nThe `*` wildcard matches any sequence of characters within\nan individual name, but never matches across names separated\nby a `/`.\n\n - `/robot/*Arm` matches `/robot/leftArm`, `/robot/rightArm` and\n   `/robot/Arm`. But does not match `/robot/limbs/leftArm` or\n   `/robot/arm`.\n\nThe `...` wildcard matches any sequence of names, and can be\nused to match locations no matter where they are parented in\nthe hierarchy.\n\n - `/.../house` matches `/house`, `/street/house` and `/city/street/house`." )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'nodule:type', '' )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'ui:scene:acceptsPaths', True )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'vectorDataPlugValueWidget:dragPointer', 'objects' )
Gaffer.Metadata.registerValue( __children["Spreadsheet"]["rows"][0]["cells"]["paths"]["value"], 'plugValueWidget:type', 'GafferSceneUI.PathFilterUI._PathsPlugValueWidget' )
__children["Spreadsheet"]["__uiPosition"].setValue( imath.V2f( 0.0499806739, -2.59913397 ) )


del __children
```

John Haddon

unread,
Sep 13, 2024, 3:38:05 AMSep 13
to gaffe...@googlegroups.com
There's one small but worthwhile improvement that can be made to Eric's example. You can plug the `enabledRowNames` output of the spreadsheet into the `name` plug of the Set node, so that adding a row to the Spreadsheet automatically adds a set to the Set node. I've attached an updated network.

To use JSON rather than a Spreadsheet, you could use a Python expresssion to drive `PathFilter.paths`, using `context.get( "setName", "" )` in the expression to find out what set is being generated and load the appropriate data.

Cheers...
John


--
You received this message because you are subscribed to the Google Groups "gaffer-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gaffer-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gaffer-dev/742f00ce-63c0-4f15-9db6-64cd6db805ffn%40googlegroups.com.
setSpreadsheet.gfr

Paolo DE LUCIA

unread,
Sep 13, 2024, 11:23:11 AMSep 13
to gaffer-dev

Just awesome...
Indeed, using the expression in the path filter to query the set being processed works like a charm. I've also made a box that generates the spreadsheet according to the Json, so I just need to choose now between the "live" link and the "button" version.

Can't thank you enough for the answer and the example, although I still have a small question :
In my button script, I want to clean the existing rows before recreating them. I can't find a way to query the rows in a good format that would allow me to delete them.
I've built a string that matches the format "Gaffer.Spreadsheet.RowPlug( "row1", )", but a string is definitely not a gaffer object...

ERROR   [Button Error] Boost.Python.ArgumentError: Python argument types in
    RowsPlug.removeRow(RowsPlug, str)
did not match C++ signature:
    removeRow(Gaffer::Spreadsheet::RowsPlug {lvalue}, Gaffer::Spreadsheet::RowPlug {lvalue})

All the examples I found use the name at the row creation
row = node["rows"].addRow()

Thanks in advance !

John Haddon

unread,
Sep 13, 2024, 11:45:07 AMSep 13
to gaffe...@googlegroups.com
On Fri, Sep 13, 2024 at 4:23 PM Paolo DE LUCIA <pao...@gmail.com> wrote:
In my button script, I want to clean the existing rows before recreating them. I can't find a way to query the rows in a good format that would allow me to delete them.
I've built a string that matches the format "Gaffer.Spreadsheet.RowPlug( "row1", )", but a string is definitely not a gaffer object...

Here's one way :

```

for row in root['Spreadsheet']["rows"].children()[1:] :

root['Spreadsheet']["rows"].removeRow( row )

```


Note that you can't delete the first row, because that provides the defaults for the outputs when no other rows match (and also is where we have the column definitions).

Cheers...

John


Paolo DE LUCIA

unread,
Sep 13, 2024, 11:48:16 AMSep 13
to gaffer-dev
Marvelous.
I was using .items(), without success.
It's a closed subject for me, hoping others will find useful information there.
thanks again.
Reply all
Reply to author
Forward
0 new messages