diff --git a/Changes.md b/Changes.md index a95f86714c..c1b56e1fdb 100644 --- a/Changes.md +++ b/Changes.md @@ -11,7 +11,7 @@ Features - Inference : Loads ONNX models and performance inference using an array of input tensors. - ImageToTensor : Converts images to tensors for use with the Inference node. - TensorToImage : Converts tensors back to images following inference. -- VisualiserTool : Added tool to 3D viewer for visualising primitive variables on meshes. +- VisualiserTool : Added tool to 3D viewer for visualising primitive variables on meshes. A list of available variable names for the current selection is available from the `dataName` context menu. Improvements ------------ diff --git a/python/GafferSceneUI/VisualiserToolUI.py b/python/GafferSceneUI/VisualiserToolUI.py index 4546bb000f..072c745517 100644 --- a/python/GafferSceneUI/VisualiserToolUI.py +++ b/python/GafferSceneUI/VisualiserToolUI.py @@ -34,6 +34,11 @@ # ########################################################################## +import functools + +import IECore +import IECoreScene + import Gaffer import GafferUI import GafferSceneUI @@ -58,13 +63,15 @@ "description", """ - Specifies the name of the primitive variable to visualise. The data should - be of type float, V2f or V3f. + Specifies the name of the primitive variable to visualise. Variables of + type int, float, V2f, Color3f or V3f can be visualised. """, "toolbarLayout:section", "Bottom", "toolbarLayout:width", 150, + "plugValueWidget:type", "GafferSceneUI.VisualiserToolUI._DataNameChooser", + ], "opacity" : [ @@ -118,3 +125,83 @@ }, ) + +class _DataNameChooser( GafferUI.PlugValueWidget ) : + + def __init__( self, plug, **kw ) : + + self.__menuButton = GafferUI.MenuButton( + text = plug.getValue(), + menu = GafferUI.Menu( Gaffer.WeakMethod( self.__menuDefinition ) ) + ) + + GafferUI.PlugValueWidget.__init__( self, self.__menuButton, plug, **kw ) + + def __menuDefinition( self ) : + + menuDefinition = IECore.MenuDefinition() + + node = self.getPlug().node() + if not isinstance( node, GafferSceneUI.VisualiserTool ) : + return + if self.getPlug() != node["dataName"] : + return + + scenePlug = node.view()["in"].getInput() + scriptNode = node.view().scriptNode() + with node.view().context() : + selection = GafferSceneUI.ScriptNodeAlgo.getSelectedPaths( scriptNode ) + + primVars = set() + + for path in selection.paths() : + if not scenePlug.exists( path ) : + continue + + primitive = scenePlug.object( path ) + if not isinstance( primitive, IECoreScene.MeshPrimitive ) : + continue + + for v in primitive.keys() : + if primitive[v].interpolation not in [ + IECoreScene.PrimitiveVariable.Interpolation.FaceVarying, + IECoreScene.PrimitiveVariable.Interpolation.Uniform, + IECoreScene.PrimitiveVariable.Interpolation.Vertex, + ] : + continue + + if not isinstance( + primitive[v].data, + ( + IECore.IntVectorData, + IECore.FloatVectorData, + IECore.V2fVectorData, + IECore.Color3fVectorData, + IECore.V3fVectorData, + ) + ) : + continue + + primVars.add( v ) + + if len( primVars ) == 0 : + menuDefinition.append( "/None Available", { "active" : False } ) + + else : + for v in reversed( sorted( primVars ) ) : + menuDefinition.prepend( + "/" + v, + { + "command" : functools.partial( Gaffer.WeakMethod( self.__setDataName ), v ), + "checkBox" : self.getPlug().getValue() == v, + } + ) + + menuDefinition.prepend( "/PrimVarDivider", { "divider" : True, "label" : "Primitive Variables" } ) + + return menuDefinition + + def __setDataName( self, value, *unused ) : + + self.getPlug().setValue( value ) + self.__menuButton.setText( value )